diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..b7eee574a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,160 @@ +name: 'Build' + +on: + push: + branches: + - dev + - "release*" + tags: + - '*' + pull_request: + +env: + TARGETS: f7 f18 + DEFAULT_TARGET: f7 + FBT_TOOLCHAIN_PATH: /home/runner/work + +jobs: + main: + runs-on: ubuntu-latest + steps: + - name: 'Decontaminate previous build leftovers' + run: | + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + fi + + - name: 'Checkout code' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: 'Get commit details' + id: names + run: | + if [[ ${{ github.event_name }} == 'pull_request' ]]; then + TYPE="pull" + elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then + TYPE="tag" + else + TYPE="other" + fi + python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" + echo random_hash=$(openssl rand -base64 40 | shasum -a 256 | awk '{print $1}') >> $GITHUB_OUTPUT + echo "event_type=$TYPE" >> $GITHUB_OUTPUT + + - name: 'Make artifacts directory' + run: | + rm -rf artifacts + mkdir artifacts + + - name: 'Bundle scripts' + run: | + tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts debug + + - name: 'Build the firmware' + run: | + set -e + for TARGET in ${TARGETS}; do + TARGET="$(echo "${TARGET}" | sed 's/f//')"; \ + ./fbt TARGET_HW=$TARGET copro_dist updater_package \ + ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} + done + + - name: 'Move upload files' + run: | + set -e + for TARGET in ${TARGETS}; do + mv dist/${TARGET}-*/* artifacts/ + done + + - name: "Check for uncommitted changes" + run: | + git diff --exit-code + + - name: 'Bundle resources' + run: | + tar czpf "artifacts/flipper-z-any-resources-${SUFFIX}.tgz" -C assets resources + + - name: 'Bundle core2 firmware' + run: | + cp build/core2_firmware.tgz "artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz" + + - name: 'Updater artifact' + uses: actions/upload-artifact@v3 + with: + name: updater + path: | + artifacts/f7-* + + - name: 'Firmware artifact' + uses: actions/upload-artifact@v3 + with: + name: firmware + path: | + artifacts + + # - name: 'Find Previous Comment' + # if: ${{ github.event.pull_request }} + # uses: peter-evans/find-comment@v1 + # id: fc + # with: + # issue-number: ${{ github.event.pull_request.number }} + # comment-author: 'github-actions[bot]' + # body-includes: 'Compiled firmware for commit' + + # - name: Artifact info + # id: artifact-info + # uses: dawidd6/action-download-artifact@v2 + # with: + # dry_run: true + + # - name: 'Create or update comment' + # if: ${{ github.event.pull_request}} + # uses: peter-evans/create-or-update-comment@v1 + # with: + # comment-id: ${{ steps.fc.outputs.comment-id }} + # issue-number: ${{ github.event.pull_request.number }} + # body: | + # **Compiled firmware for commit `${{steps.names.outputs.commit_sha}}`:** + # - [📦 Update package](${{steps.artifact-info.outputs.artifacts[0].archive_download_url}}) + # edit-mode: replace + + compact: + if: ${{ !startsWith(github.ref, 'refs/tags') }} + runs-on: ubuntu-latest + steps: + - name: 'Decontaminate previous build leftovers' + run: | + if [ -d .git ] + then + git submodule status \ + || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + fi + + - name: 'Checkout code' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + submodules: true + ref: ${{ github.event.pull_request.head.sha }} + + - name: 'Get commit details' + run: | + if [[ ${{ github.event_name }} == 'pull_request' ]]; then + TYPE="pull" + elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then + TYPE="tag" + else + TYPE="other" + fi + python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" + + - name: 'Build the firmware' + run: | + set -e + for TARGET in ${TARGETS}; do + TARGET="$(echo "${TARGET}" | sed 's/f//')"; \ + ./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 updater_package + done diff --git a/.github/workflows/check_submodules.yml b/.github/workflows/check_submodules.yml new file mode 100644 index 000000000..d1a1a64c3 --- /dev/null +++ b/.github/workflows/check_submodules.yml @@ -0,0 +1,47 @@ +name: 'Check submodules branch' + +on: + push: + branches: + - dev + - "release*" + tags: + - '*' + pull_request: + +jobs: + check_protobuf: + runs-on: ubuntu-latest + steps: + - name: 'Decontaminate previous build leftovers' + run: | + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + fi + + - name: 'Checkout code' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: 'Check protobuf branch' + run: | + git submodule update --init + SUB_PATH="assets/protobuf"; + SUB_BRANCH="dev"; + SUB_COMMITS_MIN=40; + cd "$SUB_PATH"; + SUBMODULE_HASH="$(git rev-parse HEAD)"; + BRANCHES=$(git branch -r --contains "$SUBMODULE_HASH"); + COMMITS_IN_BRANCH="$(git rev-list --count dev)"; + if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then + echo "name=fails::error" >> $GITHUB_OUTPUT + echo "::error::Error: Too low commits in $SUB_BRANCH of submodule $SUB_PATH: $COMMITS_IN_BRANCH(expected $SUB_COMMITS_MIN+)"; + exit 1; + fi + if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then + echo "name=fails::error" >> $GITHUB_OUTPUT + echo "::error::Error: Submodule $SUB_PATH is not on branch $SUB_BRANCH"; + exit 1; + fi diff --git a/.github/workflows/lint_c.yml b/.github/workflows/lint_c.yml new file mode 100644 index 000000000..232e3c689 --- /dev/null +++ b/.github/workflows/lint_c.yml @@ -0,0 +1,46 @@ +name: 'Lint C/C++ with clang-format' + +on: + push: + branches: + - dev + - "release*" + tags: + - '*' + pull_request: + +env: + TARGETS: f7 + SET_GH_OUTPUT: 1 + +jobs: + lint_c_cpp: + runs-on: ubuntu-latest + steps: + - name: 'Decontaminate previous build leftovers' + run: | + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + fi + + - name: 'Checkout code' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: 'Check code formatting' + id: syntax_check + run: ./fbt lint + + - name: Report code formatting errors + if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request + uses: peter-evans/create-or-update-comment@v1 + with: + issue-number: ${{ github.event.pull_request.number }} + body: | + Please fix following code formatting errors: + ``` + ${{ steps.syntax_check.outputs.errors }} + ``` + You might want to run `./fbt format` for an auto-fix. diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml new file mode 100644 index 000000000..65a8b6150 --- /dev/null +++ b/.github/workflows/pvs_studio.yml @@ -0,0 +1,93 @@ +name: 'Static C/C++ analysis with PVS-Studio' + +on: + push: + branches: + - dev + - "release*" + tags: + - '*' + pull_request: + +env: + TARGETS: f7 + DEFAULT_TARGET: f7 + FBT_TOOLCHAIN_PATH: /runner/_work + +jobs: + analyse_c_cpp: + if: ${{ !github.event.pull_request.head.repo.fork }} + runs-on: [self-hosted, FlipperZeroShell] + steps: + - name: 'Decontaminate previous build leftovers' + run: | + if [ -d .git ]; then + git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)" + fi + + - name: 'Checkout code' + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: 'Get commit details' + id: names + run: | + if [[ ${{ github.event_name }} == 'pull_request' ]]; then + TYPE="pull" + elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then + TYPE="tag" + else + TYPE="other" + fi + python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" + + - name: 'Supply PVS credentials' + run: | + pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }} + + - name: 'Convert PVS-Studio output to html and detect warnings' + id: pvs-warn + run: | + WARNINGS=0 + ./fbt COMPACT=1 PVSNOBROWSER=1 firmware_pvs || WARNINGS=1 + echo "warnings=${WARNINGS}" >> $GITHUB_OUTPUT + + - name: 'Upload report' + if: ${{ !github.event.pull_request.head.repo.fork && (steps.pvs-warn.outputs.warnings != 0) }} + uses: prewk/s3-cp-action@v2 + with: + aws_s3_endpoint: "${{ secrets.PVS_AWS_ENDPOINT }}" + aws_access_key_id: "${{ secrets.PVS_AWS_ACCESS_KEY }}" + aws_secret_access_key: "${{ secrets.PVS_AWS_SECRET_KEY }}" + source: "./build/f7-firmware-DC/pvsreport" + dest: "s3://${{ secrets.PVS_AWS_BUCKET }}/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/" + flags: "--recursive --acl public-read" + + - name: 'Find Previous Comment' + if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request && (steps.pvs-warn.outputs.warnings != 0) }} + uses: peter-evans/find-comment@v2 + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: 'PVS-Studio report for commit' + + - name: 'Create or update comment' + if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request && (steps.pvs-warn.outputs.warnings != 0) }} + uses: peter-evans/create-or-update-comment@v1 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: | + **PVS-Studio report for commit `${{steps.names.outputs.commit_sha}}`:** + - [Report](https://pvs.flipp.dev/${{steps.names.outputs.branch_name}}/${{steps.names.outputs.default_target}}-${{steps.names.outputs.suffix}}/index.html) + edit-mode: replace + + - name: 'Raise exception' + if: ${{ steps.pvs-warn.outputs.warnings != 0 }} + run: | + echo "Please fix all PVS warnings before merge" + exit 1 + diff --git a/.gitignore b/.gitignore index 6a3b80c65..025246faa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.swp +*.swo *.gdb_history @@ -67,8 +68,15 @@ PVS-Studio.log # Automate files, etc automate.py deployments/ -assets/dolphin/custom/ -assets/resources/dolphin_custom/ fbt_options.py commitnotes.md lib/STM32CubeWB + +# Asset packs +assets/dolphin/custom/* +!assets/dolphin/custom/NSFW/ +!assets/dolphin/custom/WatchDogs/ +!assets/dolphin/custom/ReadMe.md +assets/resources/dolphin_custom/* +!assets/resources/dolphin_custom/NSFW/ +!assets/resources/dolphin_custom/WatchDogs/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b53ffc24c..b5791a91e 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -11,5 +11,8 @@ "augustocdias.tasks-shell-input" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. - "unwantedRecommendations": [] -} \ No newline at end of file + "unwantedRecommendations": [ + "twxs.cmake", + "ms-vscode.cmake-tools" + ] +} diff --git a/CODING_STYLE.md b/CODING_STYLE.md index 6c7d6d792..c62009eff 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -52,7 +52,7 @@ Almost everything in flipper firmware is built around this concept. ## Naming -### Type names are CamelCase +### Type names are PascalCase Examples: diff --git a/ReadMe.md b/ReadMe.md index 58123126d..027fb2fce 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -4,7 +4,7 @@

-[Intro](https://github.com/ClaraCrazy/Flipper-Xtreme#What-makes-it-special) | [Animations](https://github.com/ClaraCrazy/Flipper-Xtreme#Animations--Asset-Packs) | [Docs](https://github.com/ClaraCrazy/Flipper-Xtreme/wiki) | [Changelog](https://github.com/ClaraCrazy/Flipper-Xtreme#list-of-changes) | [Known bugs](https://github.com/ClaraCrazy/Flipper-Xtreme#Known-bugs) | [Install](https://github.com/ClaraCrazy/Flipper-Xtreme#Install) | [Build](https://github.com/ClaraCrazy/Flipper-Xtreme#build-it-yourself) | [Discord](https://discord.gg/flipper-xtreme) +[Intro](https://github.com/ClaraCrazy/Flipper-Xtreme#What-makes-it-special) | [Animations](https://github.com/ClaraCrazy/Flipper-Xtreme#Animations--Asset-Packs) | [Docs](https://github.com/ClaraCrazy/Flipper-Xtreme/wiki) | [Changelog](https://github.com/ClaraCrazy/Flipper-Xtreme#list-of-changes) | [Known bugs](https://github.com/ClaraCrazy/Flipper-Xtreme/issues?q=is%3Aissue+is%3Aopen+label%3Arelease-pending) | [Install](https://github.com/ClaraCrazy/Flipper-Xtreme#Install) | [Build](https://github.com/ClaraCrazy/Flipper-Xtreme#build-it-yourself) | [Discord](https://discord.gg/flipper-xtreme) ----- This firmware is a complete overhaul of the [Official Firmware](https://github.com/flipperdevices/flipperzero-firmware), it also features lots of awesome code-bits from [Unleashed](https://github.com/DarkFlippers/unleashed-firmware). @@ -42,7 +42,7 @@ We wrote a powerful yet easy-to-use application specifically for our Firmware, t
Anim Speed: Speed in which the animations play
Cycle Anims: Duration of how long animations are played before switching to next
Unlock Anims: Custom setting just for NSFW fallback animations. Figure it out ;) -
Battery style: Classic Firmware battery style toggle, just at a more convenient place +
Battery Icon: Classic Firmware battery style toggle, just at a more convenient place
XP Level: Changes your Flippers level
SubGhz Extend: Allows you to extend the subghz range beyond what FZ devs planned
SubGhz Bypass: Allows you to bypass the subghz region locks of the Flipper @@ -113,9 +113,9 @@ Note: This repo is always updated with OFW & Unleashed. No need to mention all t - NSFW Animations tied to the level system. Read more above - Folder handling for empty ones (Now indicate they are empty) -- Jamming Files - Custom subghz presets - Multiple NFC protocols +- Multiple Sub-Ghz protocols | Merged from Unleashed, thanks @xMasterX - Subghz and IR signal replication via gpio | Credits to @ankris812 - Honda Keys (CVE-2022-27254) & Ford blockers @@ -127,6 +127,7 @@ Note: This repo is always updated with OFW & Unleashed. No need to mention all t - All Assets - Tons of apps +- File browser - Massive compiler re-do - About 1k files to speed things up a lot - Applications to now use the new Locale setting @@ -147,14 +148,6 @@ Note: This repo is always updated with OFW & Unleashed. No need to mention all t - Tons of unused code from FAPs and system calls ``` ----- -
-

Known Bugs:

- -```txt -- Nothing rn. Hopefully that wont change -``` - ----

Install:

diff --git a/applications/ReadMe.md b/applications/ReadMe.md index 3bd2aeb06..efc9afd86 100644 --- a/applications/ReadMe.md +++ b/applications/ReadMe.md @@ -25,7 +25,7 @@ Applications for factory testing the Flipper. Applications for main Flipper menu. - `archive` - Archive and file manager -- `bad_usb` - Bad USB application +- `bad_kb` - Bad KB application - `fap_loader` - External applications loader - `gpio` - GPIO application: includes USART bridge and GPIO control - `ibutton` - iButton application, onewire keys and more diff --git a/applications/debug/accessor/application.fam b/applications/debug/accessor/application.fam index 93fc9bc3f..6b8472711 100644 --- a/applications/debug/accessor/application.fam +++ b/applications/debug/accessor/application.fam @@ -2,6 +2,7 @@ App( appid="accessor", name="Accessor", apptype=FlipperAppType.DEBUG, + targets=["f7"], entry_point="accessor_app", cdefines=["APP_ACCESSOR"], requires=["gui"], diff --git a/applications/debug/battery_test_app/application.fam b/applications/debug/battery_test_app/application.fam index b388445cc..f97d10279 100644 --- a/applications/debug/battery_test_app/application.fam +++ b/applications/debug/battery_test_app/application.fam @@ -11,4 +11,5 @@ App( stack_size=1 * 1024, order=130, fap_category="Debug", + fap_libs=["assets"], ) diff --git a/applications/debug/battery_test_app/views/battery_info.c b/applications/debug/battery_test_app/views/battery_info.c new file mode 100644 index 000000000..5353a2e2a --- /dev/null +++ b/applications/debug/battery_test_app/views/battery_info.c @@ -0,0 +1,148 @@ +#include "battery_info.h" +#include +#include +#include + +#define LOW_CHARGE_THRESHOLD 10 +#define HIGH_DRAIN_CURRENT_THRESHOLD 100 + +struct BatteryInfo { + View* view; +}; + +static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) { + canvas_draw_frame(canvas, x - 7, y + 7, 30, 13); + canvas_draw_icon(canvas, x, y, icon); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, x - 4, y + 16, 24, 6); + canvas_set_color(canvas, ColorBlack); + canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val); +}; + +static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { + char emote[20] = {}; + char header[20] = {}; + char value[20] = {}; + + int32_t drain_current = data->gauge_current * (-1000); + uint32_t charge_current = data->gauge_current * 1000; + + // Draw battery + canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28); + if(charge_current > 0) { + canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14); + } else if(drain_current > HIGH_DRAIN_CURRENT_THRESHOLD) { + canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14); + } else if(data->charge < LOW_CHARGE_THRESHOLD) { + canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14); + } else { + canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNormal_29x14); + } + + // Draw bubble + elements_bubble(canvas, 53, 0, 71, 39); + + // Set text + if(charge_current > 0) { + snprintf(emote, sizeof(emote), "%s", "Yummy!"); + snprintf(header, sizeof(header), "%s", "Charging at"); + snprintf( + value, + sizeof(value), + "%lu.%luV %lumA", + (uint32_t)(data->vbus_voltage), + (uint32_t)(data->vbus_voltage * 10) % 10, + charge_current); + } else if(drain_current > 0) { + snprintf( + emote, + sizeof(emote), + "%s", + drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!"); + snprintf(header, sizeof(header), "%s", "Consumption is"); + snprintf( + value, + sizeof(value), + "%ld %s", + drain_current, + drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); + } else if(drain_current != 0) { + snprintf(header, 20, "..."); + } else if(data->charging_voltage < 4.2) { + // Non-default battery charging limit, mention it + snprintf(emote, sizeof(emote), "Charged!"); + snprintf(header, sizeof(header), "Limited to"); + snprintf( + value, + sizeof(value), + "%lu.%luV", + (uint32_t)(data->charging_voltage), + (uint32_t)(data->charging_voltage * 10) % 10); + } else { + snprintf(header, sizeof(header), "Charged!"); + } + + canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote); + canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header); + canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value); +}; + +static void battery_info_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + BatteryInfoModel* model = context; + + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + draw_battery(canvas, model, 0, 5); + + char batt_level[10]; + char temperature[10]; + char voltage[10]; + char health[10]; + + snprintf(batt_level, sizeof(batt_level), "%lu%%", (uint32_t)model->charge); + snprintf(temperature, sizeof(temperature), "%lu C", (uint32_t)model->gauge_temperature); + snprintf( + voltage, + sizeof(voltage), + "%lu.%01lu V", + (uint32_t)model->gauge_voltage, + (uint32_t)(model->gauge_voltage * 10) % 10UL); + snprintf(health, sizeof(health), "%d%%", model->health); + + draw_stat(canvas, 8, 42, &I_Battery_16x16, batt_level); + draw_stat(canvas, 40, 42, &I_Temperature_16x16, temperature); + draw_stat(canvas, 72, 42, &I_Voltage_16x16, voltage); + draw_stat(canvas, 104, 42, &I_Health_16x16, health); +} + +BatteryInfo* battery_info_alloc() { + BatteryInfo* battery_info = malloc(sizeof(BatteryInfo)); + battery_info->view = view_alloc(); + view_set_context(battery_info->view, battery_info); + view_allocate_model(battery_info->view, ViewModelTypeLocking, sizeof(BatteryInfoModel)); + view_set_draw_callback(battery_info->view, battery_info_draw_callback); + + return battery_info; +} + +void battery_info_free(BatteryInfo* battery_info) { + furi_assert(battery_info); + view_free(battery_info->view); + free(battery_info); +} + +View* battery_info_get_view(BatteryInfo* battery_info) { + furi_assert(battery_info); + return battery_info->view; +} + +void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data) { + furi_assert(battery_info); + furi_assert(data); + with_view_model( + battery_info->view, + BatteryInfoModel * model, + { memcpy(model, data, sizeof(BatteryInfoModel)); }, + true); +} diff --git a/applications/debug/battery_test_app/views/battery_info.h b/applications/debug/battery_test_app/views/battery_info.h new file mode 100644 index 000000000..7bfacf69e --- /dev/null +++ b/applications/debug/battery_test_app/views/battery_info.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +typedef struct BatteryInfo BatteryInfo; + +typedef struct { + float vbus_voltage; + float gauge_voltage; + float gauge_current; + float gauge_temperature; + float charging_voltage; + uint8_t charge; + uint8_t health; +} BatteryInfoModel; + +BatteryInfo* battery_info_alloc(); + +void battery_info_free(BatteryInfo* battery_info); + +View* battery_info_get_view(BatteryInfo* battery_info); + +void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data); diff --git a/applications/debug/bt_debug_app/bt_debug_app.c b/applications/debug/bt_debug_app/bt_debug_app.c index 405051a4a..bf13f6570 100644 --- a/applications/debug/bt_debug_app/bt_debug_app.c +++ b/applications/debug/bt_debug_app/bt_debug_app.c @@ -31,9 +31,6 @@ uint32_t bt_debug_start_view(void* context) { BtDebugApp* bt_debug_app_alloc() { BtDebugApp* app = malloc(sizeof(BtDebugApp)); - // Load settings - bt_settings_load(&app->settings); - // Gui app->gui = furi_record_open(RECORD_GUI); @@ -105,13 +102,15 @@ int32_t bt_debug_app(void* p) { } BtDebugApp* app = bt_debug_app_alloc(); + // Was bt active? + const bool was_active = furi_hal_bt_is_active(); // Stop advertising furi_hal_bt_stop_advertising(); view_dispatcher_run(app->view_dispatcher); // Restart advertising - if(app->settings.enabled) { + if(was_active) { furi_hal_bt_start_advertising(); } bt_debug_app_free(app); diff --git a/applications/debug/bt_debug_app/bt_debug_app.h b/applications/debug/bt_debug_app/bt_debug_app.h index cd59e4d00..0ad94d7dd 100644 --- a/applications/debug/bt_debug_app/bt_debug_app.h +++ b/applications/debug/bt_debug_app/bt_debug_app.h @@ -4,15 +4,14 @@ #include #include #include +#include + #include -#include #include "views/bt_carrier_test.h" #include "views/bt_packet_test.h" -#include typedef struct { - BtSettings settings; Gui* gui; ViewDispatcher* view_dispatcher; Submenu* submenu; diff --git a/applications/debug/bt_debug_app/views/bt_carrier_test.c b/applications/debug/bt_debug_app/views/bt_carrier_test.c index c09aa3fdf..8e2240495 100644 --- a/applications/debug/bt_debug_app/views/bt_carrier_test.c +++ b/applications/debug/bt_debug_app/views/bt_carrier_test.c @@ -1,7 +1,7 @@ #include "bt_carrier_test.h" #include "bt_test.h" #include "bt_test_types.h" -#include "furi_hal_bt.h" +#include struct BtCarrierTest { BtTest* bt_test; diff --git a/applications/debug/bt_debug_app/views/bt_packet_test.c b/applications/debug/bt_debug_app/views/bt_packet_test.c index 7cbc3c5c5..8a56a3003 100644 --- a/applications/debug/bt_debug_app/views/bt_packet_test.c +++ b/applications/debug/bt_debug_app/views/bt_packet_test.c @@ -1,7 +1,7 @@ #include "bt_packet_test.h" #include "bt_test.h" #include "bt_test_types.h" -#include "furi_hal_bt.h" +#include struct BtPacketTest { BtTest* bt_test; diff --git a/applications/debug/display_test/application.fam b/applications/debug/display_test/application.fam index 4b40322fb..e8a00d2ae 100644 --- a/applications/debug/display_test/application.fam +++ b/applications/debug/display_test/application.fam @@ -5,6 +5,7 @@ App( entry_point="display_test_app", cdefines=["APP_DISPLAY_TEST"], requires=["gui"], + fap_libs=["misc"], stack_size=1 * 1024, order=120, fap_category="Debug", diff --git a/applications/debug/display_test/display_test.c b/applications/debug/display_test/display_test.c index 5b46d2b41..8065a23a1 100644 --- a/applications/debug/display_test/display_test.c +++ b/applications/debug/display_test/display_test.c @@ -91,7 +91,6 @@ static void display_test_reload_config(DisplayTest* instance) { instance->config_contrast, instance->config_regulation_ratio, instance->config_bias); - gui_update(instance->gui); } static void display_config_set_bias(VariableItem* item) { diff --git a/applications/debug/example_custom_font/application.fam b/applications/debug/example_custom_font/application.fam new file mode 100644 index 000000000..06c0a7f61 --- /dev/null +++ b/applications/debug/example_custom_font/application.fam @@ -0,0 +1,9 @@ +App( + appid="example_custom_font", + name="Example: custom font", + apptype=FlipperAppType.DEBUG, + entry_point="example_custom_font_main", + requires=["gui"], + stack_size=1 * 1024, + fap_category="Debug", +) diff --git a/applications/debug/example_custom_font/example_custom_font.c b/applications/debug/example_custom_font/example_custom_font.c new file mode 100644 index 000000000..15eeb5f02 --- /dev/null +++ b/applications/debug/example_custom_font/example_custom_font.c @@ -0,0 +1,98 @@ +#include +#include + +#include +#include + +//This arrays contains the font itself. You can use any u8g2 font you want + +/* +Fontname: -Raccoon-Fixed4x6-Medium-R-Normal--6-60-75-75-P-40-ISO10646-1 +Copyright: +Glyphs: 95/203 +BBX Build Mode: 0 +*/ +const uint8_t u8g2_font_tom_thumb_4x6_tr[725] = + "_\0\2\2\2\3\3\4\4\3\6\0\377\5\377\5\0\0\352\1\330\2\270 \5\340\315\0!\6\265\310" + "\254\0\42\6\213\313$\25#\10\227\310\244\241\206\12$\10\227\310\215\70b\2%\10\227\310d\324F\1" + "&\10\227\310(\65R\22'\5\251\313\10(\6\266\310\251\62)\10\226\310\304\224\24\0*\6\217\312\244" + "\16+\7\217\311\245\225\0,\6\212\310)\0-\5\207\312\14.\5\245\310\4/\7\227\310Ve\4\60" + "\7\227\310-k\1\61\6\226\310\255\6\62\10\227\310h\220\312\1\63\11\227\310h\220\62X\0\64\10\227" + "\310$\65b\1\65\10\227\310\214\250\301\2\66\10\227\310\315\221F\0\67\10\227\310\314TF\0\70\10\227" + "\310\214\64\324\10\71\10\227\310\214\64\342\2:\6\255\311\244\0;\7\222\310e\240\0<\10\227\310\246\32" + "d\20=\6\217\311l\60>\11\227\310d\220A*\1\77\10\227\310\314\224a\2@\10\227\310UC\3" + "\1A\10\227\310UC\251\0B\10\227\310\250\264\322\2C\7\227\310\315\32\10D\10\227\310\250d-\0" + "E\10\227\310\214\70\342\0F\10\227\310\214\70b\4G\10\227\310\315\221\222\0H\10\227\310$\65\224\12" + "I\7\227\310\254X\15J\7\227\310\226\252\2K\10\227\310$\265\222\12L\7\227\310\304\346\0M\10\227" + "\310\244\61\224\12N\10\227\310\244q\250\0O\7\227\310UV\5P\10\227\310\250\264b\4Q\10\227\310" + "Uj$\1R\10\227\310\250\64V\1S\10\227\310m\220\301\2T\7\227\310\254\330\2U\7\227\310$" + "W\22V\10\227\310$\253L\0W\10\227\310$\65\206\12X\10\227\310$\325R\1Y\10\227\310$U" + "V\0Z\7\227\310\314T\16[\7\227\310\214X\16\134\10\217\311d\220A\0]\7\227\310\314r\4^" + "\5\213\313\65_\5\207\310\14`\6\212\313\304\0a\7\223\310\310\65\2b\10\227\310D\225\324\2c\7" + "\223\310\315\14\4d\10\227\310\246\245\222\0e\6\223\310\235\2f\10\227\310\246\264b\2g\10\227\307\35" + "\61%\0h\10\227\310D\225\254\0i\6\265\310\244\1j\10\233\307f\30U\5k\10\227\310\304\264T" + "\1l\7\227\310\310\326\0m\7\223\310 #include "file_browser_app_i.h" -#include "gui/modules/file_browser.h" -#include -#include +#include + +#include #include #include +#include +#include static bool file_browser_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -48,7 +49,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) { app->file_path = furi_string_alloc(); app->file_browser = file_browser_alloc(app->file_path); - file_browser_configure(app->file_browser, "*", NULL, true, false, &I_badusb_10px, true); + file_browser_configure(app->file_browser, "*", NULL, true, false, &I_badkb_10px, true); view_dispatcher_add_view( app->view_dispatcher, FileBrowserAppViewStart, widget_get_view(app->widget)); diff --git a/applications/debug/file_browser_test/icons/badusb_10px.png b/applications/debug/file_browser_test/icons/badkb_10px.png similarity index 100% rename from applications/debug/file_browser_test/icons/badusb_10px.png rename to applications/debug/file_browser_test/icons/badkb_10px.png diff --git a/applications/debug/file_browser_test/scenes/file_browser_scene_start.c b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c index 9eb26944f..9211ff3bb 100644 --- a/applications/debug/file_browser_test/scenes/file_browser_scene_start.c +++ b/applications/debug/file_browser_test/scenes/file_browser_scene_start.c @@ -19,7 +19,7 @@ bool file_browser_scene_start_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - furi_string_set(app->file_path, ANY_PATH("badusb/demo_windows.txt")); + furi_string_set(app->file_path, ANY_PATH("badkb/demo_windows.txt")); scene_manager_next_scene(app->scene_manager, FileBrowserSceneBrowser); consumed = true; } else if(event.type == SceneManagerEventTypeTick) { diff --git a/applications/debug/lfrfid_debug/application.fam b/applications/debug/lfrfid_debug/application.fam index 6844f9291..323f77818 100644 --- a/applications/debug/lfrfid_debug/application.fam +++ b/applications/debug/lfrfid_debug/application.fam @@ -2,6 +2,7 @@ App( appid="lfrfid_debug", name="LF-RFID Debug", apptype=FlipperAppType.DEBUG, + targets=["f7"], entry_point="lfrfid_debug_app", requires=[ "gui", diff --git a/applications/debug/locale_test/application.fam b/applications/debug/locale_test/application.fam index 32d065299..e46eeff51 100644 --- a/applications/debug/locale_test/application.fam +++ b/applications/debug/locale_test/application.fam @@ -8,4 +8,4 @@ App( stack_size=2 * 1024, order=70, fap_category="Debug", -) \ No newline at end of file +) diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c index eae12e6ee..367ca7a4f 100644 --- a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c @@ -44,7 +44,11 @@ bool rpc_debug_app_scene_input_error_code_on_event(void* context, SceneManagerEv if(event.type == SceneManagerEventTypeCustom) { if(event.event == RpcDebugAppCustomEventInputErrorCode) { - rpc_system_app_set_error_code(app->rpc, (uint32_t)atol(app->text_store)); + char* end; + int error_code = strtol(app->text_store, &end, 10); + if(!*end) { + rpc_system_app_set_error_code(app->rpc, error_code); + } scene_manager_previous_scene(app->scene_manager); consumed = true; } diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index e9e7b35f6..54bdd5909 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -348,13 +348,37 @@ static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) { memcpy(atqa, nfc_dev->dev_data.nfc_data.atqa, 2); MfClassicData* mf_data = &nfc_dev->dev_data.mf_classic_data; - // Check the manufacturer block (should be uid[uid_len] + 0xFF[rest]) + // Check the manufacturer block (should be uid[uid_len] + BCC (for 4byte only) + SAK + ATQA0 + ATQA1 + 0xFF[rest]) uint8_t manufacturer_block[16] = {0}; memcpy(manufacturer_block, nfc_dev->dev_data.mf_classic_data.block[0].value, 16); mu_assert( memcmp(manufacturer_block, uid, uid_len) == 0, "manufacturer_block uid doesn't match the file\r\n"); - for(uint8_t i = uid_len; i < 16; i++) { + + uint8_t position = 0; + if(uid_len == 4) { + position = uid_len; + + uint8_t bcc = 0; + + for(int i = 0; i < uid_len; i++) { + bcc ^= uid[i]; + } + + mu_assert(manufacturer_block[position] == bcc, "manufacturer_block bcc assert failed\r\n"); + } else { + position = uid_len - 1; + } + + mu_assert(manufacturer_block[position + 1] == sak, "manufacturer_block sak assert failed\r\n"); + + mu_assert( + manufacturer_block[position + 2] == atqa[0], "manufacturer_block atqa0 assert failed\r\n"); + + mu_assert( + manufacturer_block[position + 3] == atqa[1], "manufacturer_block atqa1 assert failed\r\n"); + + for(uint8_t i = position + 4; i < 16; i++) { mu_assert( manufacturer_block[i] == 0xFF, "manufacturer_block[i] == 0xFF assert failed\r\n"); } @@ -466,6 +490,10 @@ static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) { nfc_device_free(nfc_keys); } +MU_TEST(mf_mini_file_test) { + mf_classic_generator_test(4, MfClassicTypeMini); +} + MU_TEST(mf_classic_1k_4b_file_test) { mf_classic_generator_test(4, MfClassicType1k); } @@ -486,6 +514,7 @@ MU_TEST_SUITE(nfc) { nfc_test_alloc(); MU_RUN_TEST(nfca_file_test); + MU_RUN_TEST(mf_mini_file_test); MU_RUN_TEST(mf_classic_1k_4b_file_test); MU_RUN_TEST(mf_classic_4k_4b_file_test); MU_RUN_TEST(mf_classic_1k_7b_file_test); diff --git a/applications/examples/example_thermo/README.md b/applications/examples/example_thermo/README.md new file mode 100644 index 000000000..fa00264dc --- /dev/null +++ b/applications/examples/example_thermo/README.md @@ -0,0 +1,44 @@ +# 1-Wire Thermometer +This example application demonstrates the use of the 1-Wire library with a DS18B20 thermometer. +It also covers basic GUI, input handling, threads and localisation. + +## Electrical connections +Before launching the application, connect the sensor to Flipper's external GPIO according to the table below: +| DS18B20 | Flipper | +| :-----: | :-----: | +| VDD | 9 | +| GND | 18 | +| DQ | 17 | + +*NOTE 1*: GND is also available on pins 8 and 11. + +*NOTE 2*: For any other pin than 17, connect an external 4.7k pull-up resistor to pin 9. + +## Launching the application +In order to launch this demo, follow the steps below: +1. Make sure your Flipper has an SD card installed. +2. Connect your Flipper to the computer via a USB cable. +3. Run `./fbt launch_app APPSRC=example_thermo` in your terminal emulator of choice. + +## Changing the data pin +It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it, set the `THERMO_GPIO_PIN` macro to any of the options listed below: + +```c +/* Possible GPIO pin choices: + - gpio_ext_pc0 + - gpio_ext_pc1 + - gpio_ext_pc3 + - gpio_ext_pb2 + - gpio_ext_pb3 + - gpio_ext_pa4 + - gpio_ext_pa6 + - gpio_ext_pa7 + - ibutton_gpio +*/ + +#define THERMO_GPIO_PIN (ibutton_gpio) +``` +Do not forget about the external pull-up resistor as these pins do not have one built-in. + +With the changes been made, recompile and launch the application again. +The on-screen text should reflect it by asking to connect the thermometer to another pin. diff --git a/applications/examples/example_thermo/application.fam b/applications/examples/example_thermo/application.fam new file mode 100644 index 000000000..b4a05c7f9 --- /dev/null +++ b/applications/examples/example_thermo/application.fam @@ -0,0 +1,10 @@ +App( + appid="example_thermo", + name="Example: Thermometer", + apptype=FlipperAppType.EXTERNAL, + entry_point="example_thermo_main", + requires=["gui"], + stack_size=1 * 1024, + fap_icon="example_thermo_10px.png", + fap_category="Examples", +) diff --git a/applications/examples/example_thermo/example_thermo.c b/applications/examples/example_thermo/example_thermo.c new file mode 100644 index 000000000..b3bc7cd99 --- /dev/null +++ b/applications/examples/example_thermo/example_thermo.c @@ -0,0 +1,356 @@ +/* + * This file contains an example application that reads and displays + * the temperature from a DS18B20 1-wire thermometer. + * + * It also covers basic GUI, input handling, threads and localisation. + * + * References: + * [1] DS18B20 Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS18B20.pdf + */ + +#include +#include + +#include +#include + +#include + +#include +#include + +#define UPDATE_PERIOD_MS 1000UL +#define TEXT_STORE_SIZE 64U + +#define DS18B20_CMD_CONVERT 0x44U +#define DS18B20_CMD_READ_SCRATCHPAD 0xbeU + +#define DS18B20_CFG_RESOLUTION_POS 5U +#define DS18B20_CFG_RESOLUTION_MASK 0x03U +#define DS18B20_DECIMAL_PART_MASK 0x0fU + +#define DS18B20_SIGN_MASK 0xf0U + +/* Possible GPIO pin choices: + - gpio_ext_pc0 + - gpio_ext_pc1 + - gpio_ext_pc3 + - gpio_ext_pb2 + - gpio_ext_pb3 + - gpio_ext_pa4 + - gpio_ext_pa6 + - gpio_ext_pa7 + - ibutton_gpio +*/ + +#define THERMO_GPIO_PIN (ibutton_gpio) + +/* Flags which the reader thread responds to */ +typedef enum { + ReaderThreadFlagExit = 1, +} ReaderThreadFlag; + +typedef union { + struct { + uint8_t temp_lsb; /* Least significant byte of the temperature */ + uint8_t temp_msb; /* Most significant byte of the temperature */ + uint8_t user_alarm_high; /* User register 1 (Temp high alarm) */ + uint8_t user_alarm_low; /* User register 2 (Temp low alarm) */ + uint8_t config; /* Configuration register */ + uint8_t reserved[3]; /* Not used */ + uint8_t crc; /* CRC checksum for error detection */ + } fields; + uint8_t bytes[9]; +} DS18B20Scratchpad; + +/* Application context structure */ +typedef struct { + Gui* gui; + ViewPort* view_port; + FuriThread* reader_thread; + FuriMessageQueue* event_queue; + OneWireHost* onewire; + float temp_celsius; + bool has_device; +} ExampleThermoContext; + +/*************** 1-Wire Communication and Processing *****************/ + +/* Commands the thermometer to begin measuring the temperature. */ +static void example_thermo_request_temperature(ExampleThermoContext* context) { + OneWireHost* onewire = context->onewire; + + /* All 1-wire transactions must happen in a critical section, i.e + not interrupted by other threads. */ + FURI_CRITICAL_ENTER(); + + bool success = false; + do { + /* Each communication with a 1-wire device starts by a reset. + The functon will return true if a device responded with a presence pulse. */ + if(!onewire_host_reset(onewire)) break; + /* After the reset, a ROM operation must follow. + If there is only one device connected, the "Skip ROM" command is most appropriate + (it can also be used to address all of the connected devices in some cases).*/ + onewire_host_skip(onewire); + /* After the ROM operation, a device-specific command is issued. + In this case, it's a request to start measuring the temperature. */ + onewire_host_write(onewire, DS18B20_CMD_CONVERT); + + success = true; + } while(false); + + context->has_device = success; + + FURI_CRITICAL_EXIT(); +} + +/* Reads the measured temperature from the thermometer. */ +static void example_thermo_read_temperature(ExampleThermoContext* context) { + /* If there was no device detected, don't try to read the temperature */ + if(!context->has_device) { + return; + } + + OneWireHost* onewire = context->onewire; + + /* All 1-wire transactions must happen in a critical section, i.e + not interrupted by other threads. */ + FURI_CRITICAL_ENTER(); + + bool success = false; + + do { + DS18B20Scratchpad buf; + + /* Attempt reading the temperature 10 times before giving up */ + size_t attempts_left = 10; + do { + /* Each communication with a 1-wire device starts by a reset. + The functon will return true if a device responded with a presence pulse. */ + if(!onewire_host_reset(onewire)) continue; + + /* After the reset, a ROM operation must follow. + If there is only one device connected, the "Skip ROM" command is most appropriate + (it can also be used to address all of the connected devices in some cases).*/ + onewire_host_skip(onewire); + + /* After the ROM operation, a device-specific command is issued. + This time, it will be the "Read Scratchpad" command which will + prepare the device's internal buffer memory for reading. */ + onewire_host_write(onewire, DS18B20_CMD_READ_SCRATCHPAD); + + /* The actual reading happens here. A total of 9 bytes is read. */ + onewire_host_read_bytes(onewire, buf.bytes, sizeof(buf.bytes)); + + /* Calculate the checksum and compare it with one provided by the device. */ + const uint8_t crc = maxim_crc8(buf.bytes, sizeof(buf.bytes) - 1, MAXIM_CRC8_INIT); + + /* Checksums match, exit the loop */ + if(crc == buf.fields.crc) break; + + } while(--attempts_left); + + if(attempts_left == 0) break; + + /* Get the measurement resolution from the configuration register. (See [1] page 9) */ + const uint8_t resolution_mode = (buf.fields.config >> DS18B20_CFG_RESOLUTION_POS) & + DS18B20_CFG_RESOLUTION_MASK; + + /* Generate a mask for undefined bits in the decimal part. (See [1] page 6) */ + const uint8_t decimal_mask = + (DS18B20_DECIMAL_PART_MASK << (DS18B20_CFG_RESOLUTION_MASK - resolution_mode)) & + DS18B20_DECIMAL_PART_MASK; + + /* Get the integer and decimal part of the temperature (See [1] page 6) */ + const uint8_t integer_part = (buf.fields.temp_msb << 4U) | (buf.fields.temp_lsb >> 4U); + const uint8_t decimal_part = buf.fields.temp_lsb & decimal_mask; + + /* Calculate the sign of the temperature (See [1] page 6) */ + const bool is_negative = (buf.fields.temp_msb & DS18B20_SIGN_MASK) != 0; + + /* Combine the integer and decimal part together */ + const float temp_celsius_abs = integer_part + decimal_part / 16.f; + + /* Set the appropriate sign */ + context->temp_celsius = is_negative ? -temp_celsius_abs : temp_celsius_abs; + + success = true; + } while(false); + + context->has_device = success; + + FURI_CRITICAL_EXIT(); +} + +/* Periodically requests measurements and reads temperature. This function runs in a separare thread. */ +static int32_t example_thermo_reader_thread_callback(void* ctx) { + ExampleThermoContext* context = ctx; + + for(;;) { + /* Tell the termometer to start measuring the temperature. The process may take up to 750ms. */ + example_thermo_request_temperature(context); + + /* Wait for the measurement to finish. At the same time wait for an exit signal. */ + const uint32_t flags = + furi_thread_flags_wait(ReaderThreadFlagExit, FuriFlagWaitAny, UPDATE_PERIOD_MS); + + /* If an exit signal was received, return from this thread. */ + if(flags != (unsigned)FuriFlagErrorTimeout) break; + + /* The measurement is now ready, read it from the termometer. */ + example_thermo_read_temperature(context); + } + + return 0; +} + +/*************** GUI, Input and Main Loop *****************/ + +/* Draw the GUI of the application. The screen is completely redrawn during each call. */ +static void example_thermo_draw_callback(Canvas* canvas, void* ctx) { + ExampleThermoContext* context = ctx; + char text_store[TEXT_STORE_SIZE]; + const size_t middle_x = canvas_width(canvas) / 2U; + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, middle_x, 12, AlignCenter, AlignBottom, "Thermometer Demo"); + canvas_draw_line(canvas, 0, 16, 128, 16); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, middle_x, 30, AlignCenter, AlignBottom, "Connnect thermometer"); + + snprintf( + text_store, + TEXT_STORE_SIZE, + "to GPIO pin %ld", + furi_hal_resources_get_ext_pin_number(&THERMO_GPIO_PIN)); + canvas_draw_str_aligned(canvas, middle_x, 42, AlignCenter, AlignBottom, text_store); + + canvas_set_font(canvas, FontKeyboard); + + if(context->has_device) { + float temp; + char temp_units; + + /* The applicaton is locale-aware. + Change Settings->System->Units to check it out. */ + switch(locale_get_measurement_unit()) { + case LocaleMeasurementUnitsMetric: + temp = context->temp_celsius; + temp_units = 'C'; + break; + case LocaleMeasurementUnitsImperial: + temp = locale_celsius_to_fahrenheit(context->temp_celsius); + temp_units = 'F'; + break; + default: + furi_crash("Illegal measurement units"); + } + /* If a reading is available, display it */ + snprintf(text_store, TEXT_STORE_SIZE, "Temperature: %+.1f%c", (double)temp, temp_units); + } else { + /* Or show a message that no data is available */ + strncpy(text_store, "-- No data --", TEXT_STORE_SIZE); + } + + canvas_draw_str_aligned(canvas, middle_x, 58, AlignCenter, AlignBottom, text_store); +} + +/* This function is called from the GUI thread. All it does is put the event + into the application's queue so it can be processed later. */ +static void example_thermo_input_callback(InputEvent* event, void* ctx) { + ExampleThermoContext* context = ctx; + furi_message_queue_put(context->event_queue, event, FuriWaitForever); +} + +/* Starts the reader thread and handles the input */ +static void example_thermo_run(ExampleThermoContext* context) { + /* Configure the hardware in host mode */ + onewire_host_start(context->onewire); + + /* Start the reader thread. It will talk to the thermometer in the background. */ + furi_thread_start(context->reader_thread); + + /* An endless loop which handles the input*/ + for(bool is_running = true; is_running;) { + InputEvent event; + /* Wait for an input event. Input events come from the GUI thread via a callback. */ + const FuriStatus status = + furi_message_queue_get(context->event_queue, &event, FuriWaitForever); + + /* This application is only interested in short button presses. */ + if((status != FuriStatusOk) || (event.type != InputTypeShort)) { + continue; + } + + /* When the user presses the "Back" button, break the loop and exit the application. */ + if(event.key == InputKeyBack) { + is_running = false; + } + } + + /* Signal the reader thread to cease operation and exit */ + furi_thread_flags_set(furi_thread_get_id(context->reader_thread), ReaderThreadFlagExit); + + /* Wait for the reader thread to finish */ + furi_thread_join(context->reader_thread); + + /* Reset the hardware */ + onewire_host_stop(context->onewire); +} + +/******************** Initialisation & startup *****************************/ + +/* Allocate the memory and initialise the variables */ +static ExampleThermoContext* example_thermo_context_alloc() { + ExampleThermoContext* context = malloc(sizeof(ExampleThermoContext)); + + context->view_port = view_port_alloc(); + view_port_draw_callback_set(context->view_port, example_thermo_draw_callback, context); + view_port_input_callback_set(context->view_port, example_thermo_input_callback, context); + + context->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); + + context->reader_thread = furi_thread_alloc(); + furi_thread_set_stack_size(context->reader_thread, 1024U); + furi_thread_set_context(context->reader_thread, context); + furi_thread_set_callback(context->reader_thread, example_thermo_reader_thread_callback); + + context->gui = furi_record_open(RECORD_GUI); + gui_add_view_port(context->gui, context->view_port, GuiLayerFullscreen); + + context->onewire = onewire_host_alloc(&THERMO_GPIO_PIN); + + return context; +} + +/* Release the unused resources and deallocate memory */ +static void example_thermo_context_free(ExampleThermoContext* context) { + view_port_enabled_set(context->view_port, false); + gui_remove_view_port(context->gui, context->view_port); + + onewire_host_free(context->onewire); + furi_thread_free(context->reader_thread); + furi_message_queue_free(context->event_queue); + view_port_free(context->view_port); + + furi_record_close(RECORD_GUI); +} + +/* The application's entry point. Execution starts from here. */ +int32_t example_thermo_main(void* p) { + UNUSED(p); + + /* Allocate all of the necessary structures */ + ExampleThermoContext* context = example_thermo_context_alloc(); + + /* Start the applicaton's main loop. It won't return until the application was requested to exit. */ + example_thermo_run(context); + + /* Release all unneeded resources */ + example_thermo_context_free(context); + + return 0; +} diff --git a/applications/examples/example_thermo/example_thermo_10px.png b/applications/examples/example_thermo/example_thermo_10px.png new file mode 100644 index 000000000..3d527f306 Binary files /dev/null and b/applications/examples/example_thermo/example_thermo_10px.png differ diff --git a/applications/main/application.fam b/applications/main/application.fam index 376af8c42..eefb801b3 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -9,7 +9,7 @@ App( "lfrfid", "nfc", "subghz", - "bad_usb", + "bad_kb", "u2f", "fap_loader", "sub_playlist", @@ -25,13 +25,13 @@ App( apptype=FlipperAppType.METAPACKAGE, provides=[ "gpio", - #"ibutton", + # "ibutton", "infrared", "lfrfid", "nfc", "subghz", - #"bad_usb", - #"u2f", + # "bad_kb", + # "u2f", "fap_loader", "archive", ], diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index f579a2beb..78b010a78 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -1,10 +1,11 @@ -#include #include "archive_files.h" #include "archive_apps.h" #include "archive_browser.h" +#include "../views/archive_browser_view.h" + #include #include -#include "gui/modules/file_browser_worker.h" +#include #include #include @@ -55,9 +56,14 @@ static void archive_list_load_cb(void* context, uint32_t list_load_offset) { false); } -static void - archive_list_item_cb(void* context, FuriString* item_path, bool is_folder, bool is_last) { +static void archive_list_item_cb( + void* context, + FuriString* item_path, + uint32_t idx, + bool is_folder, + bool is_last) { furi_assert(context); + UNUSED(idx); ArchiveBrowserView* browser = (ArchiveBrowserView*)context; if(!is_last) { @@ -67,7 +73,9 @@ static void browser->view, ArchiveBrowserViewModel * model, { - files_array_sort(model->files); + if(model->item_cnt <= BROWSER_SORT_THRESHOLD) { + files_array_sort(model->files); + } model->list_loading = false; }, true); @@ -456,10 +464,14 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { browser->last_tab_switch_dir = key; - if(key == InputKeyLeft) { - tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal; - } else { - tab = (tab + 1) % ArchiveTabTotal; + for(int i = 0; i < 2; i++) { + if(key == InputKeyLeft) { + tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal; + } else { + tab = (tab + 1) % ArchiveTabTotal; + } + if(tab == ArchiveTabInternal && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) continue; + break; } browser->is_root = true; diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 5b13e98da..36da022da 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -14,9 +14,10 @@ static const char* tab_default_paths[] = { [ArchiveTabSubGhz] = ANY_PATH("subghz"), [ArchiveTabLFRFID] = ANY_PATH("lfrfid"), [ArchiveTabInfrared] = ANY_PATH("infrared"), - [ArchiveTabBadUsb] = ANY_PATH("badusb"), + [ArchiveTabBadKb] = ANY_PATH("badkb"), [ArchiveTabU2f] = "/app:u2f", [ArchiveTabApplications] = ANY_PATH("apps"), + [ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX, [ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX, }; @@ -26,7 +27,7 @@ static const char* known_ext[] = { [ArchiveFileTypeSubGhz] = ".sub", [ArchiveFileTypeLFRFID] = ".rfid", [ArchiveFileTypeInfrared] = ".ir", - [ArchiveFileTypeBadUsb] = ".txt", + [ArchiveFileTypeBadKb] = ".txt", [ArchiveFileTypeU2f] = "?", [ArchiveFileTypeApplication] = ".fap", [ArchiveFileTypeUpdateManifest] = ".fuf", @@ -41,9 +42,10 @@ static const ArchiveFileTypeEnum known_type[] = { [ArchiveTabSubGhz] = ArchiveFileTypeSubGhz, [ArchiveTabLFRFID] = ArchiveFileTypeLFRFID, [ArchiveTabInfrared] = ArchiveFileTypeInfrared, - [ArchiveTabBadUsb] = ArchiveFileTypeBadUsb, + [ArchiveTabBadKb] = ArchiveFileTypeBadKb, [ArchiveTabU2f] = ArchiveFileTypeU2f, [ArchiveTabApplications] = ArchiveFileTypeApplication, + [ArchiveTabInternal] = ArchiveFileTypeUnknown, [ArchiveTabBrowser] = ArchiveFileTypeUnknown, }; diff --git a/applications/main/archive/helpers/archive_files.c b/applications/main/archive/helpers/archive_files.c index 5c06c1bda..83eb2a845 100644 --- a/applications/main/archive/helpers/archive_files.c +++ b/applications/main/archive/helpers/archive_files.c @@ -16,11 +16,11 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder for(size_t i = 0; i < COUNT_OF(known_ext); i++) { if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue; if(furi_string_search(file->path, known_ext[i], 0) != FURI_STRING_FAILURE) { - if(i == ArchiveFileTypeBadUsb) { - if(furi_string_search( - file->path, archive_get_default_path(ArchiveTabBadUsb)) == 0) { + if(i == ArchiveFileTypeBadKb) { + if(furi_string_search(file->path, archive_get_default_path(ArchiveTabBadKb)) == + 0) { file->type = i; - return; // *.txt file is a BadUSB script only if it is in BadUSB folder + return; // *.txt file is a BadKB script only if it is in BadKB folder } } else { file->type = i; diff --git a/applications/main/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h index db624f5b5..863a8e7da 100644 --- a/applications/main/archive/helpers/archive_files.h +++ b/applications/main/archive/helpers/archive_files.h @@ -3,9 +3,9 @@ #include #include #include -#include #include #include "toolbox/path.h" +#include "xtreme/settings.h" #define FAP_MANIFEST_MAX_ICON_SIZE 32 @@ -15,7 +15,7 @@ typedef enum { ArchiveFileTypeSubGhz, ArchiveFileTypeLFRFID, ArchiveFileTypeInfrared, - ArchiveFileTypeBadUsb, + ArchiveFileTypeBadKb, ArchiveFileTypeU2f, ArchiveFileTypeApplication, ArchiveFileTypeUpdateManifest, @@ -84,11 +84,16 @@ static void ArchiveFile_t_clear(ArchiveFile_t* obj) { } static int ArchiveFile_t_cmp(const ArchiveFile_t* a, const ArchiveFile_t* b) { - if(a->type == ArchiveFileTypeFolder && b->type != ArchiveFileTypeFolder) { - return -1; + if(!XTREME_SETTINGS()->sort_ignore_dirs) { + if(a->type == ArchiveFileTypeFolder && b->type != ArchiveFileTypeFolder) { + return -1; + } + if(a->type != ArchiveFileTypeFolder && b->type == ArchiveFileTypeFolder) { + return 1; + } } - return furi_string_cmp(a->path, b->path); + return furi_string_cmpi(a->path, b->path); } #define M_OPL_ArchiveFile_t() \ diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index f88efb0c4..0696647ea 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -17,7 +17,7 @@ static const char* flipper_app_name[] = { [ArchiveFileTypeSubGhz] = "Sub-GHz", [ArchiveFileTypeLFRFID] = "125 kHz RFID", [ArchiveFileTypeInfrared] = "Infrared", - [ArchiveFileTypeBadUsb] = "Bad USB", + [ArchiveFileTypeBadKb] = "Bad KB", [ArchiveFileTypeU2f] = "U2F", [ArchiveFileTypeApplication] = "Applications", [ArchiveFileTypeUpdateManifest] = "UpdaterApp", diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index dce753fde..59c20ce6b 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -16,9 +16,10 @@ static const char* ArchiveTabNames[] = { [ArchiveTabSubGhz] = "Sub-GHz", [ArchiveTabLFRFID] = "RFID LF", [ArchiveTabInfrared] = "Infrared", - [ArchiveTabBadUsb] = "Bad USB", + [ArchiveTabBadKb] = "Bad KB", [ArchiveTabU2f] = "U2F", [ArchiveTabApplications] = "Apps", + [ArchiveTabInternal] = "Internal", [ArchiveTabBrowser] = "Browser", }; @@ -28,7 +29,7 @@ static const Icon* ArchiveItemIcons[] = { [ArchiveFileTypeSubGhz] = &I_sub1_10px, [ArchiveFileTypeLFRFID] = &I_125_10px, [ArchiveFileTypeInfrared] = &I_ir_10px, - [ArchiveFileTypeBadUsb] = &I_badusb_10px, + [ArchiveFileTypeBadKb] = &I_badkb_10px, [ArchiveFileTypeU2f] = &I_u2f_10px, [ArchiveFileTypeApplication] = &I_Apps_10px, [ArchiveFileTypeUpdateManifest] = &I_update_10px, @@ -109,7 +110,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { menu_array_push_raw(model->context_menu), item_pin, ArchiveBrowserEventFileMenuPin); - if(selected->type <= ArchiveFileTypeBadUsb) { + if(selected->type <= ArchiveFileTypeBadKb) { archive_menu_add_item( menu_array_push_raw(model->context_menu), item_show, @@ -129,7 +130,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { menu_array_push_raw(model->context_menu), item_info, ArchiveBrowserEventFileMenuInfo); - if(selected->type <= ArchiveFileTypeBadUsb) { + if(selected->type <= ArchiveFileTypeBadKb) { archive_menu_add_item( menu_array_push_raw(model->context_menu), item_show, @@ -157,7 +158,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { menu_array_push_raw(model->context_menu), item_info, ArchiveBrowserEventFileMenuInfo); - if(selected->type <= ArchiveFileTypeBadUsb) { + if(selected->type <= ArchiveFileTypeBadKb) { archive_menu_add_item( menu_array_push_raw(model->context_menu), item_show, @@ -397,15 +398,20 @@ static bool archive_view_input(InputEvent* event, void* context) { bool in_menu; bool move_fav_mode; + bool is_loading; with_view_model( browser->view, ArchiveBrowserViewModel * model, { in_menu = model->menu; move_fav_mode = model->move_fav; + is_loading = model->folder_loading || model->list_loading; }, false); + if(is_loading) { + return false; + } if(in_menu) { if(event->type != InputTypeShort) { return true; // RETURN @@ -481,7 +487,7 @@ static bool archive_view_input(InputEvent* event, void* context) { model->scroll_counter = 0; } }, - true); + false); archive_update_offset(browser); } @@ -588,4 +594,4 @@ void browser_free(ArchiveBrowserView* browser) { view_free(browser->view); free(browser); -} \ No newline at end of file +} diff --git a/applications/main/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h index dfe18d13b..1ce35cb53 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -1,10 +1,13 @@ #pragma once +#include "../helpers/archive_files.h" +#include "../helpers/archive_favorites.h" + #include #include #include #include -#include +#include #include #include "../helpers/archive_files.h" #include "../helpers/archive_menu.h" @@ -25,9 +28,10 @@ typedef enum { ArchiveTabNFC, ArchiveTabInfrared, ArchiveTabIButton, - ArchiveTabBadUsb, + ArchiveTabBadKb, ArchiveTabU2f, ArchiveTabApplications, + ArchiveTabInternal, ArchiveTabBrowser, ArchiveTabTotal, } ArchiveTabEnum; diff --git a/applications/main/bad_usb/application.fam b/applications/main/bad_kb/application.fam similarity index 55% rename from applications/main/bad_usb/application.fam rename to applications/main/bad_kb/application.fam index 2442dd3aa..09531da81 100644 --- a/applications/main/bad_usb/application.fam +++ b/applications/main/bad_kb/application.fam @@ -1,15 +1,15 @@ App( - appid="bad_usb", - name="Bad USB", + appid="bad_kb", + name="Bad KB", apptype=FlipperAppType.APP, - entry_point="bad_usb_app", - cdefines=["APP_BAD_USB"], + entry_point="bad_kb_app", + cdefines=["APP_BAD_KB"], requires=[ "gui", "dialogs", ], stack_size=2 * 1024, - icon="A_BadUsb_14", + icon="A_BadKb_14", order=70, fap_libs=["assets"], ) diff --git a/applications/main/bad_kb/bad_kb_app.c b/applications/main/bad_kb/bad_kb_app.c new file mode 100644 index 000000000..dfce5acbf --- /dev/null +++ b/applications/main/bad_kb/bad_kb_app.c @@ -0,0 +1,223 @@ +#include "bad_kb_app_i.h" +#include "bad_kb_settings_filename.h" +#include +#include +#include +#include +#include + +#include +#include + +#define BAD_KB_SETTINGS_PATH BAD_KB_APP_BASE_FOLDER "/" BAD_KB_SETTINGS_FILE_NAME + +static bool bad_kb_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + BadKbApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool bad_kb_app_back_event_callback(void* context) { + furi_assert(context); + BadKbApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void bad_kb_app_tick_event_callback(void* context) { + furi_assert(context); + BadKbApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +static void bad_kb_load_settings(BadKbApp* app) { + File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(storage_file_open(settings_file, BAD_KB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + char chr; + while((storage_file_read(settings_file, &chr, 1) == 1) && + !storage_file_eof(settings_file) && !isspace(chr)) { + furi_string_push_back(app->keyboard_layout, chr); + } + } + storage_file_close(settings_file); + storage_file_free(settings_file); +} + +static void bad_kb_save_settings(BadKbApp* app) { + File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(storage_file_open(settings_file, BAD_KB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { + storage_file_write( + settings_file, + furi_string_get_cstr(app->keyboard_layout), + furi_string_size(app->keyboard_layout)); + storage_file_write(settings_file, "\n", 1); + } + storage_file_close(settings_file); + storage_file_free(settings_file); +} + +void bad_kb_set_name(BadKbApp* app, const char* fmt, ...) { + furi_assert(app); + + va_list args; + va_start(args, fmt); + + vsnprintf(app->name, BAD_KB_ADV_NAME_MAX_LEN, fmt, args); + + va_end(args); +} + +BadKbApp* bad_kb_app_alloc(char* arg) { + BadKbApp* app = malloc(sizeof(BadKbApp)); + + app->bad_kb_script = NULL; + + app->file_path = furi_string_alloc(); + app->keyboard_layout = furi_string_alloc(); + if(arg && strlen(arg)) { + furi_string_set(app->file_path, arg); + } + + bad_kb_load_settings(app); + + app->gui = furi_record_open(RECORD_GUI); + app->notifications = furi_record_open(RECORD_NOTIFICATION); + app->dialogs = furi_record_open(RECORD_DIALOGS); + + app->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(app->view_dispatcher); + + app->scene_manager = scene_manager_alloc(&bad_kb_scene_handlers, app); + + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, bad_kb_app_tick_event_callback, 500); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, bad_kb_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, bad_kb_app_back_event_callback); + + Bt* bt = furi_record_open(RECORD_BT); + app->bt = bt; + app->is_bt = XTREME_SETTINGS()->bad_bt; + const char* adv_name = bt_get_profile_adv_name(bt); + memcpy(app->name, adv_name, BAD_KB_ADV_NAME_MAX_LEN); + memcpy(app->bt_old_config.name, adv_name, BAD_KB_ADV_NAME_MAX_LEN); + + const uint8_t* mac_addr = bt_get_profile_mac_address(bt); + memcpy(app->mac, mac_addr, BAD_KB_MAC_ADDRESS_LEN); + memcpy(app->bt_old_config.mac, mac_addr, BAD_KB_MAC_ADDRESS_LEN); + + // Custom Widget + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadKbAppViewError, widget_get_view(app->widget)); + + app->var_item_list_bt = variable_item_list_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + BadKbAppViewConfigBt, + variable_item_list_get_view(app->var_item_list_bt)); + app->var_item_list_usb = variable_item_list_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + BadKbAppViewConfigUsb, + variable_item_list_get_view(app->var_item_list_usb)); + + app->bad_kb_view = bad_kb_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadKbAppViewWork, bad_kb_get_view(app->bad_kb_view)); + + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadKbAppViewConfigName, text_input_get_view(app->text_input)); + + app->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, BadKbAppViewConfigMac, byte_input_get_view(app->byte_input)); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + if(furi_hal_usb_is_locked()) { + app->error = BadKbAppErrorCloseRpc; + scene_manager_next_scene(app->scene_manager, BadKbSceneError); + } else { + if(!furi_string_empty(app->file_path)) { + app->bad_kb_script = bad_kb_script_open(app->file_path, app->is_bt ? app->bt : NULL); + bad_kb_script_set_keyboard_layout(app->bad_kb_script, app->keyboard_layout); + scene_manager_next_scene(app->scene_manager, BadKbSceneWork); + } else { + furi_string_set(app->file_path, BAD_KB_APP_BASE_FOLDER); + scene_manager_next_scene(app->scene_manager, BadKbSceneFileSelect); + } + } + + return app; +} + +void bad_kb_app_free(BadKbApp* app) { + furi_assert(app); + + if(app->bad_kb_script) { + bad_kb_script_close(app->bad_kb_script); + app->bad_kb_script = NULL; + } + + // Views + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewWork); + bad_kb_free(app->bad_kb_view); + + // Custom Widget + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewError); + widget_free(app->widget); + + // Variable item list + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfigBt); + variable_item_list_free(app->var_item_list_bt); + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfigUsb); + variable_item_list_free(app->var_item_list_usb); + + // Text Input + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfigName); + text_input_free(app->text_input); + + // Byte Input + view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfigMac); + byte_input_free(app->byte_input); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + // restores bt config + // BtProfile have already been switched to the previous one + // so we directly modify the right profile + bad_kb_connection_deinit(app->bt); + if(strcmp(app->bt_old_config.name, app->name) != 0) { + furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, app->bt_old_config.name); + } + if(memcmp(app->bt_old_config.mac, app->mac, BAD_KB_MAC_ADDRESS_LEN) != 0) { + furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, app->bt_old_config.mac); + } + + // Close records + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_BT); + + bad_kb_save_settings(app); + + furi_string_free(app->file_path); + furi_string_free(app->keyboard_layout); + + free(app); +} + +int32_t bad_kb_app(void* p) { + BadKbApp* bad_kb_app = bad_kb_app_alloc((char*)p); + + view_dispatcher_run(bad_kb_app->view_dispatcher); + + bad_kb_app_free(bad_kb_app); + return 0; +} diff --git a/applications/main/bad_kb/bad_kb_app.h b/applications/main/bad_kb/bad_kb_app.h new file mode 100644 index 000000000..e75a94651 --- /dev/null +++ b/applications/main/bad_kb/bad_kb_app.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BadKbApp BadKbApp; + +void bad_kb_set_name(BadKbApp* app, const char* fmt, ...); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/bad_kb/bad_kb_app_i.h b/applications/main/bad_kb/bad_kb_app_i.h new file mode 100644 index 000000000..913830e72 --- /dev/null +++ b/applications/main/bad_kb/bad_kb_app_i.h @@ -0,0 +1,80 @@ +#pragma once + +#include "bad_kb_app.h" +#include "scenes/bad_kb_scene.h" +#include "bad_kb_script.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "views/bad_kb_view.h" + +#define BAD_KB_APP_BASE_FOLDER ANY_PATH("badkb") +#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/layouts" +#define BAD_KB_APP_SCRIPT_EXTENSION ".txt" +#define BAD_KB_APP_LAYOUT_EXTENSION ".kl" + +#define BAD_KB_MAC_ADDRESS_LEN 6 // need replace with MAC size maccro +#define BAD_KB_ADV_NAME_MAX_LEN 18 + +typedef enum { + BadKbAppErrorNoFiles, + BadKbAppErrorCloseRpc, +} BadKbAppError; + +typedef enum BadKbCustomEvent { + BadKbAppCustomEventTextEditResult, + BadKbAppCustomEventByteInputDone, + BadKbCustomEventErrorBack +} BadKbCustomEvent; + +typedef struct { + uint8_t mac[BAD_KB_MAC_ADDRESS_LEN]; + char name[BAD_KB_ADV_NAME_MAX_LEN + 1]; + + // number of bt keys before starting the app (all keys added in + // the bt keys file then will be removed) + uint16_t n_keys; +} BadKbBtConfig; + +struct BadKbApp { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + NotificationApp* notifications; + DialogsApp* dialogs; + Widget* widget; + VariableItemList* var_item_list_bt; + VariableItemList* var_item_list_usb; + + Bt* bt; + TextInput* text_input; + ByteInput* byte_input; + uint8_t mac[BAD_KB_MAC_ADDRESS_LEN]; + char name[BAD_KB_ADV_NAME_MAX_LEN + 1]; + BadKbBtConfig bt_old_config; + + BadKbAppError error; + FuriString* file_path; + FuriString* keyboard_layout; + BadKb* bad_kb_view; + BadKbScript* bad_kb_script; + + bool is_bt; +}; + +typedef enum { + BadKbAppViewError, + BadKbAppViewWork, + BadKbAppViewConfigBt, + BadKbAppViewConfigUsb, + BadKbAppViewConfigMac, + BadKbAppViewConfigName +} BadKbAppView; diff --git a/applications/main/bad_kb/bad_kb_script.c b/applications/main/bad_kb/bad_kb_script.c new file mode 100644 index 000000000..e2fd464ff --- /dev/null +++ b/applications/main/bad_kb/bad_kb_script.c @@ -0,0 +1,976 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "bad_kb_script.h" +#include + +#include + +#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("apps/Tools/.bt_hid.keys") + +#define TAG "BadKB" +#define WORKER_TAG TAG "Worker" +#define FILE_BUFFER_LEN 16 + +#define SCRIPT_STATE_ERROR (-1) +#define SCRIPT_STATE_END (-2) +#define SCRIPT_STATE_NEXT_LINE (-3) + +#define BADKB_ASCII_TO_KEY(script, x) \ + (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) + +typedef enum { + WorkerEvtToggle = (1 << 0), + WorkerEvtEnd = (1 << 1), + WorkerEvtConnect = (1 << 2), + WorkerEvtDisconnect = (1 << 3), +} WorkerEvtFlags; + +typedef enum { + LevelRssi122_100, + LevelRssi99_80, + LevelRssi79_60, + LevelRssi59_40, + LevelRssi39_0, + LevelRssiNum, + LevelRssiError = 0xFF, +} LevelRssiRange; + +typedef enum { + BadKbConnectionModeNone, + BadKbConnectionModeUsb, + BadKbConnectionModeBt, +} BadKbConnectionMode; + +/** + * Delays for waiting between HID key press and key release +*/ +const uint8_t bt_hid_delays[LevelRssiNum] = { + 30, // LevelRssi122_100 + 25, // LevelRssi99_80 + 20, // LevelRssi79_60 + 17, // LevelRssi59_40 + 14, // LevelRssi39_0 +}; + +struct BadKbScript { + FuriHalUsbHidConfig hid_cfg; + BadKbState st; + FuriString* file_path; + FuriString* keyboard_layout; + uint32_t defdelay; + uint16_t layout[128]; + FuriThread* thread; + uint8_t file_buf[FILE_BUFFER_LEN + 1]; + uint8_t buf_start; + uint8_t buf_len; + bool file_end; + FuriString* line; + + FuriString* line_prev; + uint32_t repeat_cnt; + + Bt* bt; +}; + +typedef struct { + char* name; + uint16_t keycode; +} DuckyKey; + +static const DuckyKey ducky_keys[] = { + {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, + {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, + {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, + {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, + {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, + {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, + + {"CTRL", KEY_MOD_LEFT_CTRL}, + {"CONTROL", KEY_MOD_LEFT_CTRL}, + {"SHIFT", KEY_MOD_LEFT_SHIFT}, + {"ALT", KEY_MOD_LEFT_ALT}, + {"GUI", KEY_MOD_LEFT_GUI}, + {"WINDOWS", KEY_MOD_LEFT_GUI}, + + {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, + {"DOWN", HID_KEYBOARD_DOWN_ARROW}, + {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, + {"LEFT", HID_KEYBOARD_LEFT_ARROW}, + {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, + {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, + {"UPARROW", HID_KEYBOARD_UP_ARROW}, + {"UP", HID_KEYBOARD_UP_ARROW}, + + {"ENTER", HID_KEYBOARD_RETURN}, + {"BREAK", HID_KEYBOARD_PAUSE}, + {"PAUSE", HID_KEYBOARD_PAUSE}, + {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, + {"DELETE", HID_KEYBOARD_DELETE}, + {"BACKSPACE", HID_KEYPAD_BACKSPACE}, + {"END", HID_KEYBOARD_END}, + {"ESC", HID_KEYBOARD_ESCAPE}, + {"ESCAPE", HID_KEYBOARD_ESCAPE}, + {"HOME", HID_KEYBOARD_HOME}, + {"INSERT", HID_KEYBOARD_INSERT}, + {"NUMLOCK", HID_KEYPAD_NUMLOCK}, + {"PAGEUP", HID_KEYBOARD_PAGE_UP}, + {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, + {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, + {"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK}, + {"SPACE", HID_KEYBOARD_SPACEBAR}, + {"TAB", HID_KEYBOARD_TAB}, + {"MENU", HID_KEYBOARD_APPLICATION}, + {"APP", HID_KEYBOARD_APPLICATION}, + + {"F1", HID_KEYBOARD_F1}, + {"F2", HID_KEYBOARD_F2}, + {"F3", HID_KEYBOARD_F3}, + {"F4", HID_KEYBOARD_F4}, + {"F5", HID_KEYBOARD_F5}, + {"F6", HID_KEYBOARD_F6}, + {"F7", HID_KEYBOARD_F7}, + {"F8", HID_KEYBOARD_F8}, + {"F9", HID_KEYBOARD_F9}, + {"F10", HID_KEYBOARD_F10}, + {"F11", HID_KEYBOARD_F11}, + {"F12", HID_KEYBOARD_F12}, +}; + +static const char ducky_cmd_comment[] = {"REM"}; +static const char ducky_cmd_id[] = {"ID"}; +static const char ducky_cmd_delay[] = {"DELAY "}; +static const char ducky_cmd_string[] = {"STRING "}; +static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; +static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; +static const char ducky_cmd_repeat[] = {"REPEAT "}; +static const char ducky_cmd_sysrq[] = {"SYSRQ "}; + +static const char ducky_cmd_altchar[] = {"ALTCHAR "}; +static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; +static const char ducky_cmd_altstr_2[] = {"ALTCODE "}; + +static const char ducky_cmd_lang[] = {"DUCKY_LANG"}; + +static const uint8_t numpad_keys[10] = { + HID_KEYPAD_0, + HID_KEYPAD_1, + HID_KEYPAD_2, + HID_KEYPAD_3, + HID_KEYPAD_4, + HID_KEYPAD_5, + HID_KEYPAD_6, + HID_KEYPAD_7, + HID_KEYPAD_8, + HID_KEYPAD_9, +}; + +BadKbConnectionMode connection_mode = BadKbConnectionModeNone; +FuriHalUsbInterface* usb_mode_prev = NULL; +GapPairing bt_mode_prev = GapPairingNone; +bool bt_connected = false; +bool usb_connected = false; +uint8_t bt_timeout = 0; + +static LevelRssiRange bt_remote_rssi_range(Bt* bt) { + BtRssi rssi_data = {0}; + + if(!bt_remote_rssi(bt, &rssi_data)) return LevelRssiError; + + if(rssi_data.rssi <= 39) + return LevelRssi39_0; + else if(rssi_data.rssi <= 59) + return LevelRssi59_40; + else if(rssi_data.rssi <= 79) + return LevelRssi79_60; + else if(rssi_data.rssi <= 99) + return LevelRssi99_80; + else if(rssi_data.rssi <= 122) + return LevelRssi122_100; + + return LevelRssiError; +} + +static inline void update_bt_timeout(Bt* bt) { + LevelRssiRange r = bt_remote_rssi_range(bt); + if(r < LevelRssiNum) { + bt_timeout = bt_hid_delays[r]; + FURI_LOG_D(WORKER_TAG, "BLE Key timeout : %u", bt_timeout); + } +} + +static bool ducky_get_number(const char* param, uint32_t* val) { + uint32_t value = 0; + if(sscanf(param, "%lu", &value) == 1) { + *val = value; + return true; + } + return false; +} + +static uint32_t ducky_get_command_len(const char* line) { + uint32_t len = strlen(line); + for(uint32_t i = 0; i < len; i++) { + if(line[i] == ' ') return i; + } + return 0; +} + +static bool ducky_is_line_end(const char chr) { + return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n')); +} + +static void ducky_numlock_on(BadKbScript* bad_kb) { + if(bad_kb->bt) { + if((furi_hal_bt_hid_get_led_state() & HID_KB_LED_NUM) == 0) { // FIXME + furi_hal_bt_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); + } + } else { + if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { + furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); + furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); + } + } +} + +static bool ducky_numpad_press(BadKbScript* bad_kb, const char num) { + if((num < '0') || (num > '9')) return false; + + uint16_t key = numpad_keys[num - '0']; + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(key); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(key); + } else { + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release(key); + } + + return true; +} + +static bool ducky_altchar(BadKbScript* bad_kb, const char* charcode) { + uint8_t i = 0; + bool state = false; + + FURI_LOG_I(WORKER_TAG, "char %s", charcode); + + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT); + } else { + furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); + } + + while(!ducky_is_line_end(charcode[i])) { + state = ducky_numpad_press(bad_kb, charcode[i]); + if(state == false) break; + i++; + } + + if(bad_kb->bt) { + furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT); + } else { + furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); + } + return state; +} + +static bool ducky_altstring(BadKbScript* bad_kb, const char* param) { + uint32_t i = 0; + bool state = false; + + while(param[i] != '\0') { + if((param[i] < ' ') || (param[i] > '~')) { + i++; + continue; // Skip non-printable chars + } + + char temp_str[4]; + snprintf(temp_str, 4, "%u", param[i]); + + state = ducky_altchar(bad_kb, temp_str); + if(state == false) break; + i++; + } + return state; +} + +static bool ducky_string(BadKbScript* bad_kb, const char* param) { + uint32_t i = 0; + while(param[i] != '\0') { + uint16_t keycode = BADKB_ASCII_TO_KEY(bad_kb, param[i]); + if(keycode != HID_KEYBOARD_NONE) { + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(keycode); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(keycode); + } else { + furi_hal_hid_kb_press(keycode); + furi_hal_hid_kb_release(keycode); + } + } + i++; + } + return true; +} + +static uint16_t ducky_get_keycode(BadKbScript* bad_kb, const char* param, bool accept_chars) { + for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { + size_t key_cmd_len = strlen(ducky_keys[i].name); + if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && + (ducky_is_line_end(param[key_cmd_len]))) { + return ducky_keys[i].keycode; + } + } + if((accept_chars) && (strlen(param) > 0)) { + return (BADKB_ASCII_TO_KEY(bad_kb, param[0]) & 0xFF); + } + return 0; +} + +static int32_t + ducky_parse_line(BadKbScript* bad_kb, FuriString* line, char* error, size_t error_len) { + uint32_t line_len = furi_string_size(line); + const char* line_tmp = furi_string_get_cstr(line); + bool state = false; + + if(line_len == 0) { + return SCRIPT_STATE_NEXT_LINE; // Skip empty lines + } + + FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); + + // General commands + if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) { + // REM - comment line + return (0); + } else if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { + // ID - executed in ducky_script_preload + return (0); + } else if(strncmp(line_tmp, ducky_cmd_lang, strlen(ducky_cmd_lang)) == 0) { + // DUCKY_LANG - ignore command to retain compatibility with existing scripts + return (0); + } else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) { + // DELAY + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint32_t delay_val = 0; + state = ducky_get_number(line_tmp, &delay_val); + if((state) && (delay_val > 0)) { + return (int32_t)delay_val; + } + if(error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return SCRIPT_STATE_ERROR; + } else if( + (strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) || + (strncmp(line_tmp, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) { + // DEFAULT_DELAY + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_get_number(line_tmp, &bad_kb->defdelay); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { + // STRING + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_string(bad_kb, line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid string %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) { + // ALTCHAR + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + ducky_numlock_on(bad_kb); + state = ducky_altchar(bad_kb, line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid altchar %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if( + (strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) || + (strncmp(line_tmp, ducky_cmd_altstr_2, strlen(ducky_cmd_altstr_2)) == 0)) { + // ALTSTRING + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + ducky_numlock_on(bad_kb); + state = ducky_altstring(bad_kb, line_tmp); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid altstring %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { + // REPEAT + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + state = ducky_get_number(line_tmp, &bad_kb->repeat_cnt); + if(!state && error != NULL) { + snprintf(error, error_len, "Invalid number %s", line_tmp); + } + return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) { + // SYSRQ + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint16_t key = ducky_get_keycode(bad_kb, line_tmp, true); + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + furi_hal_bt_hid_kb_press(key); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(key); + furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + } else { + furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release_all(); + } + return (0); + } else { + // Special keys + modifiers + uint16_t key = ducky_get_keycode(bad_kb, line_tmp, false); + if(key == HID_KEYBOARD_NONE) { + if(error != NULL) { + snprintf(error, error_len, "No keycode defined for %s", line_tmp); + } + return SCRIPT_STATE_ERROR; + } + if((key & 0xFF00) != 0) { + // It's a modifier key + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + key |= ducky_get_keycode(bad_kb, line_tmp, true); + } + if(bad_kb->bt) { + furi_hal_bt_hid_kb_press(key); + furi_delay_ms(bt_timeout); + furi_hal_bt_hid_kb_release(key); + } else { + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release(key); + } + return (0); + } +} + +static bool ducky_set_usb_id(BadKbScript* bad_kb, const char* line) { + if(sscanf(line, "%lX:%lX", &bad_kb->hid_cfg.vid, &bad_kb->hid_cfg.pid) == 2) { + bad_kb->hid_cfg.manuf[0] = '\0'; + bad_kb->hid_cfg.product[0] = '\0'; + + uint8_t id_len = ducky_get_command_len(line); + if(!ducky_is_line_end(line[id_len + 1])) { + sscanf( + &line[id_len + 1], + "%31[^\r\n:]:%31[^\r\n]", + bad_kb->hid_cfg.manuf, + bad_kb->hid_cfg.product); + } + FURI_LOG_D( + WORKER_TAG, + "set id: %04lX:%04lX mfr:%s product:%s", + bad_kb->hid_cfg.vid, + bad_kb->hid_cfg.pid, + bad_kb->hid_cfg.manuf, + bad_kb->hid_cfg.product); + return true; + } + return false; +} + +static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) { + uint8_t ret = 0; + uint32_t line_len = 0; + + furi_string_reset(bad_kb->line); + + do { + ret = storage_file_read(script_file, bad_kb->file_buf, FILE_BUFFER_LEN); + for(uint16_t i = 0; i < ret; i++) { + if(bad_kb->file_buf[i] == '\n' && line_len > 0) { + bad_kb->st.line_nb++; + line_len = 0; + } else { + if(bad_kb->st.line_nb == 0) { // Save first line + furi_string_push_back(bad_kb->line, bad_kb->file_buf[i]); + } + line_len++; + } + } + if(storage_file_eof(script_file)) { + if(line_len > 0) { + bad_kb->st.line_nb++; + break; + } + } + } while(ret > 0); + + if(!bad_kb->bt) { + const char* line_tmp = furi_string_get_cstr(bad_kb->line); + bool id_set = false; // Looking for ID command at first line + if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { + id_set = ducky_set_usb_id(bad_kb, &line_tmp[strlen(ducky_cmd_id) + 1]); + } + + if(id_set) { + furi_check(furi_hal_usb_set_config(&usb_hid, &bad_kb->hid_cfg)); + } else { + furi_check(furi_hal_usb_set_config(&usb_hid, NULL)); + } + } + + storage_file_seek(script_file, 0, true); + furi_string_reset(bad_kb->line); + + return true; +} + +static int32_t ducky_script_execute_next(BadKbScript* bad_kb, File* script_file) { + int32_t delay_val = 0; + + if(bad_kb->repeat_cnt > 0) { + bad_kb->repeat_cnt--; + delay_val = ducky_parse_line( + bad_kb, bad_kb->line_prev, bad_kb->st.error, sizeof(bad_kb->st.error)); + if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line + return 0; + } else if(delay_val < 0) { // Script error + bad_kb->st.error_line = bad_kb->st.line_cur - 1; + FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_kb->st.line_cur - 1U); + return SCRIPT_STATE_ERROR; + } else { + return (delay_val + bad_kb->defdelay); + } + } + + furi_string_set(bad_kb->line_prev, bad_kb->line); + furi_string_reset(bad_kb->line); + + while(1) { + if(bad_kb->buf_len == 0) { + bad_kb->buf_len = storage_file_read(script_file, bad_kb->file_buf, FILE_BUFFER_LEN); + if(storage_file_eof(script_file)) { + if((bad_kb->buf_len < FILE_BUFFER_LEN) && (bad_kb->file_end == false)) { + bad_kb->file_buf[bad_kb->buf_len] = '\n'; + bad_kb->buf_len++; + bad_kb->file_end = true; + } + } + + bad_kb->buf_start = 0; + if(bad_kb->buf_len == 0) return SCRIPT_STATE_END; + } + for(uint8_t i = bad_kb->buf_start; i < (bad_kb->buf_start + bad_kb->buf_len); i++) { + if(bad_kb->file_buf[i] == '\n' && furi_string_size(bad_kb->line) > 0) { + bad_kb->st.line_cur++; + bad_kb->buf_len = bad_kb->buf_len + bad_kb->buf_start - (i + 1); + bad_kb->buf_start = i + 1; + furi_string_trim(bad_kb->line); + delay_val = ducky_parse_line( + bad_kb, bad_kb->line, bad_kb->st.error, sizeof(bad_kb->st.error)); + if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line + return 0; + } else if(delay_val < 0) { + bad_kb->st.error_line = bad_kb->st.line_cur; + if(delay_val == SCRIPT_STATE_NEXT_LINE) { + snprintf( + bad_kb->st.error, sizeof(bad_kb->st.error), "Forbidden empty line"); + FURI_LOG_E( + WORKER_TAG, "Forbidden empty line at line %u", bad_kb->st.line_cur); + } else { + FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_kb->st.line_cur); + } + return SCRIPT_STATE_ERROR; + } else { + return (delay_val + bad_kb->defdelay); + } + } else { + furi_string_push_back(bad_kb->line, bad_kb->file_buf[i]); + } + } + bad_kb->buf_len = 0; + if(bad_kb->file_end) return SCRIPT_STATE_END; + } +} + +static void bad_kb_bt_hid_state_callback(BtStatus status, void* context) { + furi_assert(context); + BadKbScript* bad_kb = (BadKbScript*)context; + bool state = (status == BtStatusConnected); + + if(state == true) { + LevelRssiRange r = bt_remote_rssi_range(bad_kb->bt); + if(r != LevelRssiError) { + bt_timeout = bt_hid_delays[r]; + } + bt_connected = true; + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtConnect); + } else { + bt_connected = false; + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtDisconnect); + } +} + +static void bad_kb_usb_hid_state_callback(bool state, void* context) { + furi_assert(context); + BadKbScript* bad_kb = context; + + if(state == true) { + usb_connected = true; + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtConnect); + } else { + usb_connected = false; + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtDisconnect); + } +} + +void bad_kb_bt_init(Bt* bt) { + bt_timeout = bt_hid_delays[LevelRssi39_0]; + bt_disconnect(bt); + furi_delay_ms(200); + bt_keys_storage_set_storage_path(bt, HID_BT_KEYS_STORAGE_PATH); + furi_assert(bt_set_profile(bt, BtProfileHidKeyboard)); + bt_mode_prev = bt_get_profile_pairing_method(bt); + bt_set_profile_pairing_method(bt, GapPairingNone); + furi_hal_bt_start_advertising(); + // disable peer key adding to bt SRAM storage + bt_disable_peer_key_update(bt); + + connection_mode = BadKbConnectionModeBt; +} + +void bad_kb_bt_deinit(Bt* bt) { + // release all keys + // bt_hid_hold_while_keyboard_buffer_full(6, 3000); + + // stop ble + bt_disconnect(bt); + + // Wait 2nd core to update nvm storage + furi_delay_ms(200); + + bt_keys_storage_set_default_path(bt); + + bt_set_profile_pairing_method(bt, bt_mode_prev); + + // fails if ble radio stack isn't ready when switching profile + // if it happens, maybe we should increase the delay after bt_disconnect + bt_set_profile(bt, BtProfileSerial); + + // starts saving peer keys (bounded devices) + bt_enable_peer_key_update(bt); + + connection_mode = BadKbConnectionModeNone; +} + +void bad_kb_usb_init() { + usb_mode_prev = furi_hal_usb_get_config(); + + connection_mode = BadKbConnectionModeUsb; +} + +void bad_kb_usb_deinit() { + furi_hal_usb_set_config(usb_mode_prev, NULL); + + connection_mode = BadKbConnectionModeNone; +} + +void bad_kb_connection_init(Bt* bt) { + if(connection_mode != BadKbConnectionModeNone) return; + + if(bt) { + bad_kb_bt_init(bt); + } else { + bad_kb_usb_init(); + } +} + +void bad_kb_connection_deinit(Bt* bt) { + if(connection_mode == BadKbConnectionModeNone) return; + + if(connection_mode == BadKbConnectionModeBt) { + bad_kb_bt_deinit(bt); + } else { + bad_kb_usb_deinit(); + } +} + +static int32_t bad_kb_worker(void* context) { + BadKbScript* bad_kb = context; + + BadKbWorkerState worker_state = BadKbStateInit; + int32_t delay_val = 0; + + bad_kb_connection_init(bad_kb->bt); + + if(bad_kb->bt) { + bt_set_status_changed_callback(bad_kb->bt, bad_kb_bt_hid_state_callback, bad_kb); + } else { + furi_hal_hid_set_state_callback(bad_kb_usb_hid_state_callback, bad_kb); + } + + FURI_LOG_I(WORKER_TAG, "Init"); + File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + bad_kb->line = furi_string_alloc(); + bad_kb->line_prev = furi_string_alloc(); + + while(1) { + if(worker_state == BadKbStateInit) { // State: initialization + if(storage_file_open( + script_file, + furi_string_get_cstr(bad_kb->file_path), + FSAM_READ, + FSOM_OPEN_EXISTING)) { + if((ducky_script_preload(bad_kb, script_file)) && (bad_kb->st.line_nb > 0)) { + if(bad_kb->bt) { + worker_state = BadKbStateNotConnected; // Ready to run + } else { + if(furi_hal_hid_is_connected()) { + worker_state = BadKbStateIdle; // Ready to run + } else { + worker_state = BadKbStateNotConnected; // Not connected + } + } + } else { + worker_state = BadKbStateScriptError; // Script preload error + } + } else { + FURI_LOG_E(WORKER_TAG, "File open error"); + worker_state = BadKbStateFileError; // File open error + } + bad_kb->st.state = worker_state; + + } else if(worker_state == BadKbStateNotConnected) { // State: Not connected + if((bad_kb->bt && bt_connected) || (!bad_kb->bt && usb_connected)) { + worker_state = BadKbStateIdle; // Ready to run + } else { + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, + FuriFlagWaitAny, + FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtConnect) { + worker_state = BadKbStateIdle; // Ready to run + } else if(flags & WorkerEvtToggle) { + worker_state = BadKbStateWillRun; // Will run when connected + } + } + bad_kb->st.state = worker_state; + + } else if(worker_state == BadKbStateIdle) { // State: ready to start + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, + FuriFlagWaitAny, + FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtToggle) { // Start executing script + DOLPHIN_DEED(DolphinDeedBadKbPlayScript); + delay_val = 0; + bad_kb->buf_len = 0; + bad_kb->st.line_cur = 0; + bad_kb->defdelay = 0; + bad_kb->repeat_cnt = 0; + bad_kb->file_end = false; + storage_file_seek(script_file, 0, true); + bad_kb_script_set_keyboard_layout(bad_kb, bad_kb->keyboard_layout); + worker_state = BadKbStateRunning; + } else if(flags & WorkerEvtDisconnect) { + worker_state = BadKbStateNotConnected; // Disconnected + } + bad_kb->st.state = worker_state; + + } else if(worker_state == BadKbStateWillRun) { // State: start on connection + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, + FuriFlagWaitAny, + FuriWaitForever); + furi_check((flags & FuriFlagError) == 0); + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtConnect) { // Start executing script + DOLPHIN_DEED(DolphinDeedBadKbPlayScript); + delay_val = 0; + bad_kb->buf_len = 0; + bad_kb->st.line_cur = 0; + bad_kb->defdelay = 0; + bad_kb->repeat_cnt = 0; + bad_kb->file_end = false; + storage_file_seek(script_file, 0, true); + // extra time for PC to recognize Flipper as keyboard + furi_thread_flags_wait(0, FuriFlagWaitAny, 1500); + if(bad_kb->bt) { + update_bt_timeout(bad_kb->bt); + } + bad_kb_script_set_keyboard_layout(bad_kb, bad_kb->keyboard_layout); + worker_state = BadKbStateRunning; + } else if(flags & WorkerEvtToggle) { // Cancel scheduled execution + worker_state = BadKbStateNotConnected; + } + bad_kb->st.state = worker_state; + + } else if(worker_state == BadKbStateRunning) { // State: running + uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur); + delay_val -= delay_cur; + if(!(flags & FuriFlagError)) { + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtToggle) { + worker_state = BadKbStateIdle; // Stop executing script + if(bad_kb->bt) { + furi_hal_bt_hid_kb_release_all(); + } else { + furi_hal_hid_kb_release_all(); + } + } else if(flags & WorkerEvtDisconnect) { + worker_state = BadKbStateNotConnected; // Disconnected + if(bad_kb->bt) { + furi_hal_bt_hid_kb_release_all(); + } else { + furi_hal_hid_kb_release_all(); + } + } + bad_kb->st.state = worker_state; + continue; + } else if( + (flags == (unsigned)FuriFlagErrorTimeout) || + (flags == (unsigned)FuriFlagErrorResource)) { + if(delay_val > 0) { + bad_kb->st.delay_remain--; + continue; + } + bad_kb->st.state = BadKbStateRunning; + delay_val = ducky_script_execute_next(bad_kb, script_file); + if(delay_val == SCRIPT_STATE_ERROR) { // Script error + delay_val = 0; + worker_state = BadKbStateScriptError; + bad_kb->st.state = worker_state; + } else if(delay_val == SCRIPT_STATE_END) { // End of script + delay_val = 0; + worker_state = BadKbStateIdle; + bad_kb->st.state = BadKbStateDone; + if(bad_kb->bt) { + furi_hal_bt_hid_kb_release_all(); + } else { + furi_hal_hid_kb_release_all(); + } + continue; + } else if(delay_val > 1000) { + bad_kb->st.state = BadKbStateDelay; // Show long delays + bad_kb->st.delay_remain = delay_val / 1000; + } + } else { + furi_check((flags & FuriFlagError) == 0); + } + + } else if( + (worker_state == BadKbStateFileError) || + (worker_state == BadKbStateScriptError)) { // State: error + uint32_t flags = furi_thread_flags_wait( + WorkerEvtEnd, FuriFlagWaitAny, FuriWaitForever); // Waiting for exit command + furi_check((flags & FuriFlagError) == 0); + if(flags & WorkerEvtEnd) { + break; + } + } + if(bad_kb->bt) { + update_bt_timeout(bad_kb->bt); + } + } + + if(bad_kb->bt) { + bt_set_status_changed_callback(bad_kb->bt, NULL, NULL); + } else { + furi_hal_hid_set_state_callback(NULL, NULL); + } + + storage_file_close(script_file); + storage_file_free(script_file); + furi_string_free(bad_kb->line); + furi_string_free(bad_kb->line_prev); + + FURI_LOG_I(WORKER_TAG, "End"); + + return 0; +} + +static void bad_kb_script_set_default_keyboard_layout(BadKbScript* bad_kb) { + furi_assert(bad_kb); + furi_string_set_str(bad_kb->keyboard_layout, ""); + memset(bad_kb->layout, HID_KEYBOARD_NONE, sizeof(bad_kb->layout)); + memcpy(bad_kb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_kb->layout))); +} + +BadKbScript* bad_kb_script_open(FuriString* file_path, Bt* bt) { + furi_assert(file_path); + + BadKbScript* bad_kb = malloc(sizeof(BadKbScript)); + bad_kb->file_path = furi_string_alloc(); + furi_string_set(bad_kb->file_path, file_path); + bad_kb->keyboard_layout = furi_string_alloc(); + bad_kb_script_set_default_keyboard_layout(bad_kb); + + bad_kb->st.state = BadKbStateInit; + bad_kb->st.error[0] = '\0'; + + bad_kb->bt = bt; + + bad_kb->thread = furi_thread_alloc_ex("BadKbWorker", 2048, bad_kb_worker, bad_kb); + furi_thread_start(bad_kb->thread); + return bad_kb; +} //-V773 + +void bad_kb_script_close(BadKbScript* bad_kb) { + furi_assert(bad_kb); + furi_record_close(RECORD_STORAGE); + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtEnd); + furi_thread_join(bad_kb->thread); + furi_thread_free(bad_kb->thread); + furi_string_free(bad_kb->file_path); + furi_string_free(bad_kb->keyboard_layout); + free(bad_kb); +} + +void bad_kb_script_set_keyboard_layout(BadKbScript* bad_kb, FuriString* layout_path) { + furi_assert(bad_kb); + + if((bad_kb->st.state == BadKbStateRunning) || (bad_kb->st.state == BadKbStateDelay)) { + // do not update keyboard layout while a script is running + return; + } + + File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + if(!furi_string_empty(layout_path)) { + furi_string_set(bad_kb->keyboard_layout, layout_path); + if(storage_file_open( + layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) { + uint16_t layout[128]; + if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) { + memcpy(bad_kb->layout, layout, sizeof(layout)); + } + } + storage_file_close(layout_file); + } else { + bad_kb_script_set_default_keyboard_layout(bad_kb); + } + storage_file_free(layout_file); +} + +void bad_kb_script_toggle(BadKbScript* bad_kb) { + furi_assert(bad_kb); + furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtToggle); +} + +BadKbState* bad_kb_script_get_state(BadKbScript* bad_kb) { + furi_assert(bad_kb); + return &(bad_kb->st); +} diff --git a/applications/main/bad_kb/bad_kb_script.h b/applications/main/bad_kb/bad_kb_script.h new file mode 100644 index 000000000..0ea701eb8 --- /dev/null +++ b/applications/main/bad_kb/bad_kb_script.h @@ -0,0 +1,53 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct BadKbScript BadKbScript; + +typedef enum { + BadKbStateInit, + BadKbStateNotConnected, + BadKbStateIdle, + BadKbStateWillRun, + BadKbStateRunning, + BadKbStateDelay, + BadKbStateDone, + BadKbStateScriptError, + BadKbStateFileError, +} BadKbWorkerState; + +typedef struct { + BadKbWorkerState state; + uint16_t line_cur; + uint16_t line_nb; + uint32_t delay_remain; + uint16_t error_line; + char error[64]; +} BadKbState; + +void bad_kb_connection_init(Bt* bt); + +void bad_kb_connection_deinit(Bt* bt); + +BadKbScript* bad_kb_script_open(FuriString* file_path, Bt* bt); + +void bad_kb_script_close(BadKbScript* bad_kb); + +void bad_kb_script_set_keyboard_layout(BadKbScript* bad_kb, FuriString* layout_path); + +void bad_kb_script_start(BadKbScript* bad_kb); + +void bad_kb_script_stop(BadKbScript* bad_kb); + +void bad_kb_script_toggle(BadKbScript* bad_kb); + +BadKbState* bad_kb_script_get_state(BadKbScript* bad_kb); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/bad_kb/bad_kb_settings_filename.h b/applications/main/bad_kb/bad_kb_settings_filename.h new file mode 100644 index 000000000..3eb7d3c0a --- /dev/null +++ b/applications/main/bad_kb/bad_kb_settings_filename.h @@ -0,0 +1,3 @@ +#pragma once + +#define BAD_KB_SETTINGS_FILE_NAME ".badkb.settings" diff --git a/applications/main/bad_kb/scenes/bad_kb_scene.c b/applications/main/bad_kb/scenes/bad_kb_scene.c new file mode 100644 index 000000000..f90d23a77 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene.c @@ -0,0 +1,30 @@ +#include "bad_kb_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const bad_kb_scene_on_enter_handlers[])(void*) = { +#include "bad_kb_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const bad_kb_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "bad_kb_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const bad_kb_scene_on_exit_handlers[])(void* context) = { +#include "bad_kb_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers bad_kb_scene_handlers = { + .on_enter_handlers = bad_kb_scene_on_enter_handlers, + .on_event_handlers = bad_kb_scene_on_event_handlers, + .on_exit_handlers = bad_kb_scene_on_exit_handlers, + .scene_num = BadKbSceneNum, +}; diff --git a/applications/main/bad_usb/scenes/bad_usb_scene.h b/applications/main/bad_kb/scenes/bad_kb_scene.h similarity index 68% rename from applications/main/bad_usb/scenes/bad_usb_scene.h rename to applications/main/bad_kb/scenes/bad_kb_scene.h index 68a753210..82db02873 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene.h +++ b/applications/main/bad_kb/scenes/bad_kb_scene.h @@ -3,27 +3,27 @@ #include // Generate scene id and total number -#define ADD_SCENE(prefix, name, id) BadUsbScene##id, +#define ADD_SCENE(prefix, name, id) BadKbScene##id, typedef enum { -#include "bad_usb_scene_config.h" - BadUsbSceneNum, -} BadUsbScene; +#include "bad_kb_scene_config.h" + BadKbSceneNum, +} BadKbScene; #undef ADD_SCENE -extern const SceneManagerHandlers bad_usb_scene_handlers; +extern const SceneManagerHandlers bad_kb_scene_handlers; // Generate scene on_enter handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); -#include "bad_usb_scene_config.h" +#include "bad_kb_scene_config.h" #undef ADD_SCENE // Generate scene on_event handlers declaration #define ADD_SCENE(prefix, name, id) \ bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); -#include "bad_usb_scene_config.h" +#include "bad_kb_scene_config.h" #undef ADD_SCENE // Generate scene on_exit handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); -#include "bad_usb_scene_config.h" +#include "bad_kb_scene_config.h" #undef ADD_SCENE diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config.h b/applications/main/bad_kb/scenes/bad_kb_scene_config.h new file mode 100644 index 000000000..794468eba --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config.h @@ -0,0 +1,8 @@ +ADD_SCENE(bad_kb, file_select, FileSelect) +ADD_SCENE(bad_kb, work, Work) +ADD_SCENE(bad_kb, error, Error) +ADD_SCENE(bad_kb, config_bt, ConfigBt) +ADD_SCENE(bad_kb, config_usb, ConfigUsb) +ADD_SCENE(bad_kb, config_layout, ConfigLayout) +ADD_SCENE(bad_kb, config_name, ConfigName) +ADD_SCENE(bad_kb, config_mac, ConfigMac) diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_bt.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_bt.c new file mode 100644 index 000000000..4412f0796 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_bt.c @@ -0,0 +1,87 @@ +#include "../bad_kb_app_i.h" +#include "furi_hal_power.h" +#include "furi_hal_usb.h" +#include + +enum VarItemListIndex { + VarItemListIndexConnection, + VarItemListIndexKeyboardLayout, + VarItemListIndexAdvertisementName, + VarItemListIndexMacAddress, +}; + +void bad_kb_scene_config_bt_connection_callback(VariableItem* item) { + BadKbApp* bad_kb = variable_item_get_context(item); + bad_kb->is_bt = variable_item_get_current_value_index(item); + XTREME_SETTINGS()->bad_bt = bad_kb->is_bt; + XTREME_SETTINGS_SAVE(); + variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, VarItemListIndexConnection); +} + +void bad_kb_scene_config_bt_var_item_list_callback(void* context, uint32_t index) { + BadKbApp* bad_kb = context; + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, index); +} + +void bad_kb_scene_config_bt_on_enter(void* context) { + BadKbApp* bad_kb = context; + VariableItemList* var_item_list = bad_kb->var_item_list_bt; + VariableItem* item; + + item = variable_item_list_add( + var_item_list, "Connection", 2, bad_kb_scene_config_bt_connection_callback, bad_kb); + variable_item_set_current_value_index(item, bad_kb->is_bt); + variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); + + item = variable_item_list_add(var_item_list, "Keyboard layout", 0, NULL, bad_kb); + + item = variable_item_list_add(var_item_list, "BT device name", 0, NULL, bad_kb); + + item = variable_item_list_add(var_item_list, "BT MAC address", 0, NULL, bad_kb); + + variable_item_list_set_enter_callback( + var_item_list, bad_kb_scene_config_bt_var_item_list_callback, bad_kb); + + view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfigBt); +} + +bool bad_kb_scene_config_bt_on_event(void* context, SceneManagerEvent event) { + BadKbApp* bad_kb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(bad_kb->scene_manager, BadKbSceneConfigBt, event.event); + consumed = true; + if(event.event == VarItemListIndexKeyboardLayout) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigLayout); + } else if(event.event == VarItemListIndexConnection) { + bad_kb_script_close(bad_kb->bad_kb_script); + bad_kb_connection_deinit(bad_kb->bt); + bad_kb->bad_kb_script = + bad_kb_script_open(bad_kb->file_path, bad_kb->is_bt ? bad_kb->bt : NULL); + bad_kb_script_set_keyboard_layout(bad_kb->bad_kb_script, bad_kb->keyboard_layout); + scene_manager_previous_scene(bad_kb->scene_manager); + if(bad_kb->is_bt) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigBt); + } else { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigUsb); + } + } else if(event.event == VarItemListIndexAdvertisementName) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigName); + } else if(event.event == VarItemListIndexMacAddress) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigMac); + // } else { + // furi_crash("Unknown key type"); + } + } + + return consumed; +} + +void bad_kb_scene_config_bt_on_exit(void* context) { + BadKbApp* bad_kb = context; + VariableItemList* var_item_list = bad_kb->var_item_list_bt; + + variable_item_list_reset(var_item_list); +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c new file mode 100644 index 000000000..3842c59fa --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_layout.c @@ -0,0 +1,51 @@ +#include "../bad_kb_app_i.h" +#include "furi_hal_power.h" +#include "furi_hal_usb.h" +#include + +#define KEYBOARD_FOLDER "/ext/badkb/layouts" + +static bool bad_kb_layout_select(BadKbApp* bad_kb) { + furi_assert(bad_kb); + + FuriString* predefined_path; + predefined_path = furi_string_alloc(); + if(!furi_string_empty(bad_kb->keyboard_layout)) { + furi_string_set(predefined_path, bad_kb->keyboard_layout); + } else { + furi_string_set(predefined_path, BAD_KB_APP_PATH_LAYOUT_FOLDER); + } + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options( + &browser_options, BAD_KB_APP_LAYOUT_EXTENSION, &I_keyboard_10px); + browser_options.base_path = KEYBOARD_FOLDER; + + // Input events and views are managed by file_browser + bool res = dialog_file_browser_show( + bad_kb->dialogs, bad_kb->keyboard_layout, predefined_path, &browser_options); + + furi_string_free(predefined_path); + return res; +} + +void bad_kb_scene_config_layout_on_enter(void* context) { + BadKbApp* bad_kb = context; + + if(bad_kb_layout_select(bad_kb)) { + bad_kb_script_set_keyboard_layout(bad_kb->bad_kb_script, bad_kb->keyboard_layout); + } + scene_manager_previous_scene(bad_kb->scene_manager); +} + +bool bad_kb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + // BadKbApp* bad_kb = context; + return false; +} + +void bad_kb_scene_config_layout_on_exit(void* context) { + UNUSED(context); + // BadKbApp* bad_kb = context; +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_mac.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_mac.c new file mode 100644 index 000000000..0dc4be10a --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_mac.c @@ -0,0 +1,57 @@ +#include "../bad_kb_app_i.h" + +#define TAG "BadKbConfigMac" + +static uint8_t* reverse_mac_addr(uint8_t* mac) { + uint8_t tmp; + for(int i = 0; i < 3; i++) { + tmp = mac[i]; + mac[i] = mac[5 - i]; + mac[5 - i] = tmp; + } + return mac; +} + +void bad_kb_scene_config_mac_byte_input_callback(void* context) { + BadKbApp* bad_kb = context; + + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, BadKbAppCustomEventByteInputDone); +} + +void bad_kb_scene_config_mac_on_enter(void* context) { + BadKbApp* bad_kb = context; + + // Setup view + ByteInput* byte_input = bad_kb->byte_input; + byte_input_set_header_text(byte_input, "Enter new MAC address"); + byte_input_set_result_callback( + byte_input, + bad_kb_scene_config_mac_byte_input_callback, + NULL, + bad_kb, + reverse_mac_addr(bad_kb->mac), + GAP_MAC_ADDR_SIZE); + view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfigMac); +} + +bool bad_kb_scene_config_mac_on_event(void* context, SceneManagerEvent event) { + BadKbApp* bad_kb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == BadKbAppCustomEventByteInputDone) { + bt_set_profile_mac_address(bad_kb->bt, reverse_mac_addr(bad_kb->mac)); + scene_manager_previous_scene(bad_kb->scene_manager); + consumed = true; + } + } + return consumed; +} + +void bad_kb_scene_config_mac_on_exit(void* context) { + BadKbApp* bad_kb = context; + + // Clear view + byte_input_set_result_callback(bad_kb->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(bad_kb->byte_input, ""); +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_name.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_name.c new file mode 100644 index 000000000..82dd7a850 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_name.c @@ -0,0 +1,45 @@ +#include "../bad_kb_app_i.h" + +static void bad_kb_scene_config_name_text_input_callback(void* context) { + BadKbApp* bad_kb = context; + + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, BadKbAppCustomEventTextEditResult); +} + +void bad_kb_scene_config_name_on_enter(void* context) { + BadKbApp* bad_kb = context; + TextInput* text_input = bad_kb->text_input; + + text_input_set_header_text(text_input, "Set BLE adv name"); + + text_input_set_result_callback( + text_input, + bad_kb_scene_config_name_text_input_callback, + bad_kb, + bad_kb->name, + BAD_KB_ADV_NAME_MAX_LEN, + true); + + view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfigName); +} + +bool bad_kb_scene_config_name_on_event(void* context, SceneManagerEvent event) { + BadKbApp* bad_kb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == BadKbAppCustomEventTextEditResult) { + bt_set_profile_adv_name(bad_kb->bt, bad_kb->name); + } + scene_manager_previous_scene(bad_kb->scene_manager); + } + return consumed; +} + +void bad_kb_scene_config_name_on_exit(void* context) { + BadKbApp* bad_kb = context; + TextInput* text_input = bad_kb->text_input; + + text_input_reset(text_input); +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_config_usb.c b/applications/main/bad_kb/scenes/bad_kb_scene_config_usb.c new file mode 100644 index 000000000..232ef8796 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_config_usb.c @@ -0,0 +1,77 @@ +#include "../bad_kb_app_i.h" +#include "furi_hal_power.h" +#include "furi_hal_usb.h" +#include + +enum VarItemListIndex { + VarItemListIndexConnection, + VarItemListIndexKeyboardLayout, +}; + +void bad_kb_scene_config_usb_connection_callback(VariableItem* item) { + BadKbApp* bad_kb = variable_item_get_context(item); + bad_kb->is_bt = variable_item_get_current_value_index(item); + XTREME_SETTINGS()->bad_bt = bad_kb->is_bt; + XTREME_SETTINGS_SAVE(); + variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, VarItemListIndexConnection); +} + +void bad_kb_scene_config_usb_var_item_list_callback(void* context, uint32_t index) { + BadKbApp* bad_kb = context; + view_dispatcher_send_custom_event(bad_kb->view_dispatcher, index); +} + +void bad_kb_scene_config_usb_on_enter(void* context) { + BadKbApp* bad_kb = context; + VariableItemList* var_item_list = bad_kb->var_item_list_usb; + VariableItem* item; + + item = variable_item_list_add( + var_item_list, "Connection", 2, bad_kb_scene_config_usb_connection_callback, bad_kb); + variable_item_set_current_value_index(item, bad_kb->is_bt); + variable_item_set_current_value_text(item, bad_kb->is_bt ? "BT" : "USB"); + + item = variable_item_list_add(var_item_list, "Keyboard layout", 0, NULL, bad_kb); + + variable_item_list_set_enter_callback( + var_item_list, bad_kb_scene_config_usb_var_item_list_callback, bad_kb); + + view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfigUsb); +} + +bool bad_kb_scene_config_usb_on_event(void* context, SceneManagerEvent event) { + BadKbApp* bad_kb = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(bad_kb->scene_manager, BadKbSceneConfigUsb, event.event); + consumed = true; + if(event.event == VarItemListIndexKeyboardLayout) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigLayout); + } else if(event.event == VarItemListIndexConnection) { + bad_kb_script_close(bad_kb->bad_kb_script); + bad_kb_connection_deinit(bad_kb->bt); + bad_kb->bad_kb_script = + bad_kb_script_open(bad_kb->file_path, bad_kb->is_bt ? bad_kb->bt : NULL); + bad_kb_script_set_keyboard_layout(bad_kb->bad_kb_script, bad_kb->keyboard_layout); + scene_manager_previous_scene(bad_kb->scene_manager); + if(bad_kb->is_bt) { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigBt); + } else { + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigUsb); + } + // } else { + // furi_crash("Unknown key type"); + } + } + + return consumed; +} + +void bad_kb_scene_config_usb_on_exit(void* context) { + BadKbApp* bad_kb = context; + VariableItemList* var_item_list = bad_kb->var_item_list_usb; + + variable_item_list_reset(var_item_list); +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_error.c b/applications/main/bad_kb/scenes/bad_kb_scene_error.c similarity index 64% rename from applications/main/bad_usb/scenes/bad_usb_scene_error.c rename to applications/main/bad_kb/scenes/bad_kb_scene_error.c index 2c707bbf1..bfec05652 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_error.c +++ b/applications/main/bad_kb/scenes/bad_kb_scene_error.c @@ -1,24 +1,20 @@ -#include "../bad_usb_app_i.h" -#include "../../../settings/xtreme_settings/xtreme_settings.h" - -typedef enum { - BadUsbCustomEventErrorBack, -} BadUsbCustomEvent; +#include "../bad_kb_app_i.h" +#include "xtreme/assets.h" static void - bad_usb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) { + bad_kb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); - BadUsbApp* app = context; + BadKbApp* app = context; if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { - view_dispatcher_send_custom_event(app->view_dispatcher, BadUsbCustomEventErrorBack); + view_dispatcher_send_custom_event(app->view_dispatcher, BadKbCustomEventErrorBack); } } -void bad_usb_scene_error_on_enter(void* context) { - BadUsbApp* app = context; +void bad_kb_scene_error_on_enter(void* context) { + BadKbApp* app = context; - if(app->error == BadUsbAppErrorNoFiles) { + if(app->error == BadKbAppErrorNoFiles) { widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43); widget_add_string_multiline_element( app->widget, @@ -29,10 +25,10 @@ void bad_usb_scene_error_on_enter(void* context) { FontSecondary, "No SD card or\napp data found.\nThis app will not\nwork without\nrequired files."); widget_add_button_element( - app->widget, GuiButtonTypeLeft, "Back", bad_usb_scene_error_event_callback, app); - } else if(app->error == BadUsbAppErrorCloseRpc) { + app->widget, GuiButtonTypeLeft, "Back", bad_kb_scene_error_event_callback, app); + } else if(app->error == BadKbAppErrorCloseRpc) { widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { widget_add_string_multiline_element( app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "I am not\na whore!"); widget_add_string_multiline_element( @@ -57,15 +53,15 @@ void bad_usb_scene_error_on_enter(void* context) { } } - view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError); + view_dispatcher_switch_to_view(app->view_dispatcher, BadKbAppViewError); } -bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) { - BadUsbApp* app = context; +bool bad_kb_scene_error_on_event(void* context, SceneManagerEvent event) { + BadKbApp* app = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == BadUsbCustomEventErrorBack) { + if(event.event == BadKbCustomEventErrorBack) { view_dispatcher_stop(app->view_dispatcher); consumed = true; } @@ -73,7 +69,7 @@ bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) { return consumed; } -void bad_usb_scene_error_on_exit(void* context) { - BadUsbApp* app = context; +void bad_kb_scene_error_on_exit(void* context) { + BadKbApp* app = context; widget_reset(app->widget); } diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_file_select.c b/applications/main/bad_kb/scenes/bad_kb_scene_file_select.c new file mode 100644 index 000000000..bb2ddf6ca --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_file_select.c @@ -0,0 +1,53 @@ +#include "../bad_kb_app_i.h" +#include +#include +#include + +static bool bad_kb_file_select(BadKbApp* bad_kb) { + furi_assert(bad_kb); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options( + &browser_options, BAD_KB_APP_SCRIPT_EXTENSION, &I_badkb_10px); + browser_options.base_path = BAD_KB_APP_BASE_FOLDER; + browser_options.skip_assets = true; + + // Input events and views are managed by file_browser + bool res = dialog_file_browser_show( + bad_kb->dialogs, bad_kb->file_path, bad_kb->file_path, &browser_options); + + return res; +} + +void bad_kb_scene_file_select_on_enter(void* context) { + BadKbApp* bad_kb = context; + + furi_hal_usb_disable(); + if(bad_kb->bad_kb_script) { + bad_kb_script_close(bad_kb->bad_kb_script); + bad_kb->bad_kb_script = NULL; + } + + if(bad_kb_file_select(bad_kb)) { + bad_kb->bad_kb_script = + bad_kb_script_open(bad_kb->file_path, bad_kb->is_bt ? bad_kb->bt : NULL); + bad_kb_script_set_keyboard_layout(bad_kb->bad_kb_script, bad_kb->keyboard_layout); + + scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneWork); + } else { + furi_hal_usb_enable(); + view_dispatcher_stop(bad_kb->view_dispatcher); + } +} + +bool bad_kb_scene_file_select_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + // BadKbApp* bad_kb = context; + return false; +} + +void bad_kb_scene_file_select_on_exit(void* context) { + UNUSED(context); + // BadKbApp* bad_kb = context; +} diff --git a/applications/main/bad_kb/scenes/bad_kb_scene_work.c b/applications/main/bad_kb/scenes/bad_kb_scene_work.c new file mode 100644 index 000000000..165ee0289 --- /dev/null +++ b/applications/main/bad_kb/scenes/bad_kb_scene_work.c @@ -0,0 +1,58 @@ +#include "../bad_kb_script.h" +#include "../bad_kb_app_i.h" +#include "../views/bad_kb_view.h" +#include +#include "toolbox/path.h" + +void bad_kb_scene_work_button_callback(InputKey key, void* context) { + furi_assert(context); + BadKbApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, key); +} + +bool bad_kb_scene_work_on_event(void* context, SceneManagerEvent event) { + BadKbApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InputKeyLeft) { + if(app->is_bt) { + scene_manager_next_scene(app->scene_manager, BadKbSceneConfigBt); + } else { + scene_manager_next_scene(app->scene_manager, BadKbSceneConfigUsb); + } + consumed = true; + } else if(event.event == InputKeyOk) { + bad_kb_script_toggle(app->bad_kb_script); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeTick) { + bad_kb_set_state(app->bad_kb_view, bad_kb_script_get_state(app->bad_kb_script)); + } + return consumed; +} + +void bad_kb_scene_work_on_enter(void* context) { + BadKbApp* app = context; + + FuriString* file_name; + file_name = furi_string_alloc(); + path_extract_filename(app->file_path, file_name, true); + bad_kb_set_file_name(app->bad_kb_view, furi_string_get_cstr(file_name)); + furi_string_free(file_name); + + FuriString* layout; + layout = furi_string_alloc(); + path_extract_filename(app->keyboard_layout, layout, true); + bad_kb_set_layout(app->bad_kb_view, furi_string_get_cstr(layout)); + furi_string_free(layout); + + bad_kb_set_state(app->bad_kb_view, bad_kb_script_get_state(app->bad_kb_script)); + + bad_kb_set_button_callback(app->bad_kb_view, bad_kb_scene_work_button_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, BadKbAppViewWork); +} + +void bad_kb_scene_work_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_kb/views/bad_kb_view.c similarity index 65% rename from applications/main/bad_usb/views/bad_usb_view.c rename to applications/main/bad_kb/views/bad_kb_view.c index ad889cd1c..1ffe58e9c 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_kb/views/bad_kb_view.c @@ -1,34 +1,33 @@ -#include "bad_usb_view.h" -#include "../bad_usb_script.h" +#include "bad_kb_view.h" +#include "../bad_kb_script.h" #include #include #include -#include "../../../settings/xtreme_settings/xtreme_settings.h" +#include "xtreme/assets.h" #define MAX_NAME_LEN 64 -struct BadUsb { +struct BadKb { View* view; - BadUsbButtonCallback callback; + BadKbButtonCallback callback; void* context; }; typedef struct { char file_name[MAX_NAME_LEN]; char layout[MAX_NAME_LEN]; - BadUsbState state; + BadKbState state; uint8_t anim_frame; -} BadUsbModel; +} BadKbModel; -static void bad_usb_draw_callback(Canvas* canvas, void* _model) { - BadUsbModel* model = _model; +static void bad_kb_draw_callback(Canvas* canvas, void* _model) { + BadKbModel* model = _model; FuriString* disp_str; disp_str = furi_string_alloc_set(model->file_name); elements_string_fit_width(canvas, disp_str, 128 - 2); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str)); - XtremeSettings* xtreme_settings = XTREME_SETTINGS(); if(strlen(model->layout) == 0) { furi_string_set(disp_str, "(default)"); @@ -47,49 +46,49 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22); - if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone) || - (model->state.state == BadUsbStateNotConnected)) { - if(xtreme_settings->nsfw_mode) { + if((model->state.state == BadKbStateIdle) || (model->state.state == BadKbStateDone) || + (model->state.state == BadKbStateNotConnected)) { + if(XTREME_ASSETS()->is_nsfw) { elements_button_center(canvas, "Cum"); } else { elements_button_center(canvas, "Start"); } - } else if((model->state.state == BadUsbStateRunning) || (model->state.state == BadUsbStateDelay)) { + } else if((model->state.state == BadKbStateRunning) || (model->state.state == BadKbStateDelay)) { elements_button_center(canvas, "Stop"); - } else if(model->state.state == BadUsbStateWillRun) { + } else if(model->state.state == BadKbStateWillRun) { elements_button_center(canvas, "Cancel"); } - if((model->state.state == BadUsbStateNotConnected) || - (model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone)) { + if((model->state.state == BadKbStateNotConnected) || (model->state.state == BadKbStateIdle) || + (model->state.state == BadKbStateDone)) { elements_button_left(canvas, "Config"); } - if(model->state.state == BadUsbStateNotConnected) { + if(model->state.state == BadKbStateNotConnected) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); - if(xtreme_settings->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Plug me"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "in, Daddy"); } else { canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect to"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "a device"); } - } else if(model->state.state == BadUsbStateWillRun) { + } else if(model->state.state == BadKbStateWillRun) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); - if(xtreme_settings->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will cum"); } else { canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run"); } canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect"); - } else if(model->state.state == BadUsbStateFileError) { + } else if(model->state.state == BadKbStateFileError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR"); - } else if(model->state.state == BadUsbStateScriptError) { + } else if(model->state.state == BadKbStateScriptError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); @@ -99,12 +98,12 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error); - } else if(model->state.state == BadUsbStateIdle) { + } else if(model->state.state == BadKbStateIdle) { canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0"); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateRunning) { + } else if(model->state.state == BadKbStateRunning) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); } else { @@ -117,13 +116,13 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateDone) { + } else if(model->state.state == BadKbStateDone) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100"); furi_string_reset(disp_str); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateDelay) { + } else if(model->state.state == BadKbStateDelay) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); } else { @@ -148,84 +147,78 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { furi_string_free(disp_str); } -static bool bad_usb_input_callback(InputEvent* event, void* context) { +static bool bad_kb_input_callback(InputEvent* event, void* context) { furi_assert(context); - BadUsb* bad_usb = context; + BadKb* bad_kb = context; bool consumed = false; if(event->type == InputTypeShort) { if((event->key == InputKeyLeft) || (event->key == InputKeyOk)) { consumed = true; - furi_assert(bad_usb->callback); - bad_usb->callback(event->key, bad_usb->context); + furi_assert(bad_kb->callback); + bad_kb->callback(event->key, bad_kb->context); } } return consumed; } -BadUsb* bad_usb_alloc() { - BadUsb* bad_usb = malloc(sizeof(BadUsb)); +BadKb* bad_kb_alloc() { + BadKb* bad_kb = malloc(sizeof(BadKb)); - bad_usb->view = view_alloc(); - view_allocate_model(bad_usb->view, ViewModelTypeLocking, sizeof(BadUsbModel)); - view_set_context(bad_usb->view, bad_usb); - view_set_draw_callback(bad_usb->view, bad_usb_draw_callback); - view_set_input_callback(bad_usb->view, bad_usb_input_callback); + bad_kb->view = view_alloc(); + view_allocate_model(bad_kb->view, ViewModelTypeLocking, sizeof(BadKbModel)); + view_set_context(bad_kb->view, bad_kb); + view_set_draw_callback(bad_kb->view, bad_kb_draw_callback); + view_set_input_callback(bad_kb->view, bad_kb_input_callback); - return bad_usb; + return bad_kb; } -void bad_usb_free(BadUsb* bad_usb) { - furi_assert(bad_usb); - view_free(bad_usb->view); - free(bad_usb); +void bad_kb_free(BadKb* bad_kb) { + furi_assert(bad_kb); + view_free(bad_kb->view); + free(bad_kb); } -View* bad_usb_get_view(BadUsb* bad_usb) { - furi_assert(bad_usb); - return bad_usb->view; +View* bad_kb_get_view(BadKb* bad_kb) { + furi_assert(bad_kb); + return bad_kb->view; } -void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context) { - furi_assert(bad_usb); +void bad_kb_set_button_callback(BadKb* bad_kb, BadKbButtonCallback callback, void* context) { + furi_assert(bad_kb); furi_assert(callback); with_view_model( - bad_usb->view, - BadUsbModel * model, + bad_kb->view, + BadKbModel * model, { UNUSED(model); - bad_usb->callback = callback; - bad_usb->context = context; + bad_kb->callback = callback; + bad_kb->context = context; }, true); } -void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) { +void bad_kb_set_file_name(BadKb* bad_kb, const char* name) { furi_assert(name); with_view_model( - bad_usb->view, - BadUsbModel * model, - { strlcpy(model->file_name, name, MAX_NAME_LEN); }, - true); + bad_kb->view, BadKbModel * model, { strlcpy(model->file_name, name, MAX_NAME_LEN); }, true); } -void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) { +void bad_kb_set_layout(BadKb* bad_kb, const char* layout) { furi_assert(layout); with_view_model( - bad_usb->view, - BadUsbModel * model, - { strlcpy(model->layout, layout, MAX_NAME_LEN); }, - true); + bad_kb->view, BadKbModel * model, { strlcpy(model->layout, layout, MAX_NAME_LEN); }, true); } -void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { +void bad_kb_set_state(BadKb* bad_kb, BadKbState* st) { furi_assert(st); with_view_model( - bad_usb->view, - BadUsbModel * model, + bad_kb->view, + BadKbModel * model, { - memcpy(&(model->state), st, sizeof(BadUsbState)); + memcpy(&(model->state), st, sizeof(BadKbState)); model->anim_frame ^= 1; }, true); diff --git a/applications/main/bad_kb/views/bad_kb_view.h b/applications/main/bad_kb/views/bad_kb_view.h new file mode 100644 index 000000000..24fdf4792 --- /dev/null +++ b/applications/main/bad_kb/views/bad_kb_view.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "../bad_kb_script.h" + +typedef struct BadKb BadKb; +typedef void (*BadKbButtonCallback)(InputKey key, void* context); + +BadKb* bad_kb_alloc(); + +void bad_kb_free(BadKb* bad_kb); + +View* bad_kb_get_view(BadKb* bad_kb); + +void bad_kb_set_button_callback(BadKb* bad_kb, BadKbButtonCallback callback, void* context); + +void bad_kb_set_file_name(BadKb* bad_kb, const char* name); + +void bad_kb_set_layout(BadKb* bad_kb, const char* layout); + +void bad_kb_set_state(BadKb* bad_kb, BadKbState* st); diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c deleted file mode 100644 index bb29d3be5..000000000 --- a/applications/main/bad_usb/bad_usb_app.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "bad_usb_app_i.h" -#include "bad_usb_settings_filename.h" -#include -#include -#include -#include - -#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/" BAD_USB_SETTINGS_FILE_NAME - -static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) { - furi_assert(context); - BadUsbApp* app = context; - return scene_manager_handle_custom_event(app->scene_manager, event); -} - -static bool bad_usb_app_back_event_callback(void* context) { - furi_assert(context); - BadUsbApp* app = context; - return scene_manager_handle_back_event(app->scene_manager); -} - -static void bad_usb_app_tick_event_callback(void* context) { - furi_assert(context); - BadUsbApp* app = context; - scene_manager_handle_tick_event(app->scene_manager); -} - -static void bad_usb_load_settings(BadUsbApp* app) { - File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - char chr; - while((storage_file_read(settings_file, &chr, 1) == 1) && - !storage_file_eof(settings_file) && !isspace(chr)) { - furi_string_push_back(app->keyboard_layout, chr); - } - } - storage_file_close(settings_file); - storage_file_free(settings_file); -} - -static void bad_usb_save_settings(BadUsbApp* app) { - File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { - storage_file_write( - settings_file, - furi_string_get_cstr(app->keyboard_layout), - furi_string_size(app->keyboard_layout)); - storage_file_write(settings_file, "\n", 1); - } - storage_file_close(settings_file); - storage_file_free(settings_file); -} - -BadUsbApp* bad_usb_app_alloc(char* arg) { - BadUsbApp* app = malloc(sizeof(BadUsbApp)); - - app->bad_usb_script = NULL; - - app->file_path = furi_string_alloc(); - app->keyboard_layout = furi_string_alloc(); - if(arg && strlen(arg)) { - furi_string_set(app->file_path, arg); - } - - bad_usb_load_settings(app); - - app->gui = furi_record_open(RECORD_GUI); - app->notifications = furi_record_open(RECORD_NOTIFICATION); - app->dialogs = furi_record_open(RECORD_DIALOGS); - - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - - app->scene_manager = scene_manager_alloc(&bad_usb_scene_handlers, app); - - view_dispatcher_set_event_callback_context(app->view_dispatcher, app); - view_dispatcher_set_tick_event_callback( - app->view_dispatcher, bad_usb_app_tick_event_callback, 500); - view_dispatcher_set_custom_event_callback( - app->view_dispatcher, bad_usb_app_custom_event_callback); - view_dispatcher_set_navigation_event_callback( - app->view_dispatcher, bad_usb_app_back_event_callback); - - // Custom Widget - app->widget = widget_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget)); - - app->submenu = submenu_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewConfig, submenu_get_view(app->submenu)); - - app->bad_usb_view = bad_usb_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view)); - - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - if(furi_hal_usb_is_locked()) { - app->error = BadUsbAppErrorCloseRpc; - scene_manager_next_scene(app->scene_manager, BadUsbSceneError); - } else { - if(!furi_string_empty(app->file_path)) { - app->bad_usb_script = bad_usb_script_open(app->file_path); - bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout); - scene_manager_next_scene(app->scene_manager, BadUsbSceneWork); - } else { - furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER); - scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect); - } - } - - return app; -} - -void bad_usb_app_free(BadUsbApp* app) { - furi_assert(app); - - if(app->bad_usb_script) { - bad_usb_script_close(app->bad_usb_script); - app->bad_usb_script = NULL; - } - - // Views - view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); - bad_usb_free(app->bad_usb_view); - - // Custom Widget - view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError); - widget_free(app->widget); - - // Submenu - view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig); - submenu_free(app->submenu); - - // View dispatcher - view_dispatcher_free(app->view_dispatcher); - scene_manager_free(app->scene_manager); - - // Close records - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_DIALOGS); - - bad_usb_save_settings(app); - - furi_string_free(app->file_path); - furi_string_free(app->keyboard_layout); - - free(app); -} - -int32_t bad_usb_app(void* p) { - BadUsbApp* bad_usb_app = bad_usb_app_alloc((char*)p); - - view_dispatcher_run(bad_usb_app->view_dispatcher); - - bad_usb_app_free(bad_usb_app); - return 0; -} diff --git a/applications/main/bad_usb/bad_usb_app.h b/applications/main/bad_usb/bad_usb_app.h deleted file mode 100644 index afadd87e9..000000000 --- a/applications/main/bad_usb/bad_usb_app.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct BadUsbApp BadUsbApp; - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h deleted file mode 100644 index b3fbb1679..000000000 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "bad_usb_app.h" -#include "scenes/bad_usb_scene.h" -#include "bad_usb_script.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "views/bad_usb_view.h" - -#define BAD_USB_APP_BASE_FOLDER ANY_PATH("badusb") -#define BAD_USB_APP_PATH_LAYOUT_FOLDER BAD_USB_APP_BASE_FOLDER "/layouts" -#define BAD_USB_APP_SCRIPT_EXTENSION ".txt" -#define BAD_USB_APP_LAYOUT_EXTENSION ".kl" - -typedef enum { - BadUsbAppErrorNoFiles, - BadUsbAppErrorCloseRpc, -} BadUsbAppError; - -struct BadUsbApp { - Gui* gui; - ViewDispatcher* view_dispatcher; - SceneManager* scene_manager; - NotificationApp* notifications; - DialogsApp* dialogs; - Widget* widget; - Submenu* submenu; - - BadUsbAppError error; - FuriString* file_path; - FuriString* keyboard_layout; - BadUsb* bad_usb_view; - BadUsbScript* bad_usb_script; -}; - -typedef enum { - BadUsbAppViewError, - BadUsbAppViewWork, - BadUsbAppViewConfig, -} BadUsbAppView; \ No newline at end of file diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c deleted file mode 100644 index 1a73150a5..000000000 --- a/applications/main/bad_usb/bad_usb_script.c +++ /dev/null @@ -1,724 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "bad_usb_script.h" -#include - -#define TAG "BadUSB" -#define WORKER_TAG TAG "Worker" -#define FILE_BUFFER_LEN 16 - -#define SCRIPT_STATE_ERROR (-1) -#define SCRIPT_STATE_END (-2) -#define SCRIPT_STATE_NEXT_LINE (-3) - -#define BADUSB_ASCII_TO_KEY(script, x) \ - (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) - -typedef enum { - WorkerEvtToggle = (1 << 0), - WorkerEvtEnd = (1 << 1), - WorkerEvtConnect = (1 << 2), - WorkerEvtDisconnect = (1 << 3), -} WorkerEvtFlags; - -struct BadUsbScript { - FuriHalUsbHidConfig hid_cfg; - BadUsbState st; - FuriString* file_path; - uint32_t defdelay; - uint16_t layout[128]; - FuriThread* thread; - uint8_t file_buf[FILE_BUFFER_LEN + 1]; - uint8_t buf_start; - uint8_t buf_len; - bool file_end; - FuriString* line; - - FuriString* line_prev; - uint32_t repeat_cnt; -}; - -typedef struct { - char* name; - uint16_t keycode; -} DuckyKey; - -static const DuckyKey ducky_keys[] = { - {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, - {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, - {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, - {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, - {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, - - {"CTRL", KEY_MOD_LEFT_CTRL}, - {"CONTROL", KEY_MOD_LEFT_CTRL}, - {"SHIFT", KEY_MOD_LEFT_SHIFT}, - {"ALT", KEY_MOD_LEFT_ALT}, - {"GUI", KEY_MOD_LEFT_GUI}, - {"WINDOWS", KEY_MOD_LEFT_GUI}, - - {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, - {"DOWN", HID_KEYBOARD_DOWN_ARROW}, - {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, - {"LEFT", HID_KEYBOARD_LEFT_ARROW}, - {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, - {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, - {"UPARROW", HID_KEYBOARD_UP_ARROW}, - {"UP", HID_KEYBOARD_UP_ARROW}, - - {"ENTER", HID_KEYBOARD_RETURN}, - {"BREAK", HID_KEYBOARD_PAUSE}, - {"PAUSE", HID_KEYBOARD_PAUSE}, - {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, - {"DELETE", HID_KEYBOARD_DELETE_FORWARD}, - {"BACKSPACE", HID_KEYBOARD_DELETE}, - {"END", HID_KEYBOARD_END}, - {"ESC", HID_KEYBOARD_ESCAPE}, - {"ESCAPE", HID_KEYBOARD_ESCAPE}, - {"HOME", HID_KEYBOARD_HOME}, - {"INSERT", HID_KEYBOARD_INSERT}, - {"NUMLOCK", HID_KEYPAD_NUMLOCK}, - {"PAGEUP", HID_KEYBOARD_PAGE_UP}, - {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, - {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, - {"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK}, - {"SPACE", HID_KEYBOARD_SPACEBAR}, - {"TAB", HID_KEYBOARD_TAB}, - {"MENU", HID_KEYBOARD_APPLICATION}, - {"APP", HID_KEYBOARD_APPLICATION}, - - {"F1", HID_KEYBOARD_F1}, - {"F2", HID_KEYBOARD_F2}, - {"F3", HID_KEYBOARD_F3}, - {"F4", HID_KEYBOARD_F4}, - {"F5", HID_KEYBOARD_F5}, - {"F6", HID_KEYBOARD_F6}, - {"F7", HID_KEYBOARD_F7}, - {"F8", HID_KEYBOARD_F8}, - {"F9", HID_KEYBOARD_F9}, - {"F10", HID_KEYBOARD_F10}, - {"F11", HID_KEYBOARD_F11}, - {"F12", HID_KEYBOARD_F12}, -}; - -static const char ducky_cmd_comment[] = {"REM"}; -static const char ducky_cmd_id[] = {"ID"}; -static const char ducky_cmd_delay[] = {"DELAY "}; -static const char ducky_cmd_string[] = {"STRING "}; -static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; -static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; -static const char ducky_cmd_repeat[] = {"REPEAT "}; -static const char ducky_cmd_sysrq[] = {"SYSRQ "}; - -static const char ducky_cmd_altchar[] = {"ALTCHAR "}; -static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; -static const char ducky_cmd_altstr_2[] = {"ALTCODE "}; - -static const char ducky_cmd_lang[] = {"DUCKY_LANG"}; - -static const uint8_t numpad_keys[10] = { - HID_KEYPAD_0, - HID_KEYPAD_1, - HID_KEYPAD_2, - HID_KEYPAD_3, - HID_KEYPAD_4, - HID_KEYPAD_5, - HID_KEYPAD_6, - HID_KEYPAD_7, - HID_KEYPAD_8, - HID_KEYPAD_9, -}; - -static bool ducky_get_number(const char* param, uint32_t* val) { - uint32_t value = 0; - if(sscanf(param, "%lu", &value) == 1) { - *val = value; - return true; - } - return false; -} - -static uint32_t ducky_get_command_len(const char* line) { - uint32_t len = strlen(line); - for(uint32_t i = 0; i < len; i++) { - if(line[i] == ' ') return i; - } - return 0; -} - -static bool ducky_is_line_end(const char chr) { - return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n')); -} - -static void ducky_numlock_on() { - if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { - furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); - furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); - } -} - -static bool ducky_numpad_press(const char num) { - if((num < '0') || (num > '9')) return false; - - uint16_t key = numpad_keys[num - '0']; - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release(key); - - return true; -} - -static bool ducky_altchar(const char* charcode) { - uint8_t i = 0; - bool state = false; - - FURI_LOG_I(WORKER_TAG, "char %s", charcode); - - furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); - - while(!ducky_is_line_end(charcode[i])) { - state = ducky_numpad_press(charcode[i]); - if(state == false) break; - i++; - } - - furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); - return state; -} - -static bool ducky_altstring(const char* param) { - uint32_t i = 0; - bool state = false; - - while(param[i] != '\0') { - if((param[i] < ' ') || (param[i] > '~')) { - i++; - continue; // Skip non-printable chars - } - - char temp_str[4]; - snprintf(temp_str, 4, "%u", param[i]); - - state = ducky_altchar(temp_str); - if(state == false) break; - i++; - } - return state; -} - -static bool ducky_string(BadUsbScript* bad_usb, const char* param) { - uint32_t i = 0; - while(param[i] != '\0') { - uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]); - if(keycode != HID_KEYBOARD_NONE) { - furi_hal_hid_kb_press(keycode); - furi_hal_hid_kb_release(keycode); - } - i++; - } - return true; -} - -static uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) { - for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { - size_t key_cmd_len = strlen(ducky_keys[i].name); - if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && - (ducky_is_line_end(param[key_cmd_len]))) { - return ducky_keys[i].keycode; - } - } - if((accept_chars) && (strlen(param) > 0)) { - return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF); - } - return 0; -} - -static int32_t - ducky_parse_line(BadUsbScript* bad_usb, FuriString* line, char* error, size_t error_len) { - uint32_t line_len = furi_string_size(line); - const char* line_tmp = furi_string_get_cstr(line); - bool state = false; - - if(line_len == 0) { - return SCRIPT_STATE_NEXT_LINE; // Skip empty lines - } - - FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); - - // General commands - if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) { - // REM - comment line - return (0); - } else if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { - // ID - executed in ducky_script_preload - return (0); - } else if(strncmp(line_tmp, ducky_cmd_lang, strlen(ducky_cmd_lang)) == 0) { - // DUCKY_LANG - ignore command to retain compatibility with existing scripts - return (0); - } else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) { - // DELAY - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - uint32_t delay_val = 0; - state = ducky_get_number(line_tmp, &delay_val); - if((state) && (delay_val > 0)) { - return (int32_t)delay_val; - } - if(error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return SCRIPT_STATE_ERROR; - } else if( - (strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) || - (strncmp(line_tmp, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) { - // DEFAULT_DELAY - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_get_number(line_tmp, &bad_usb->defdelay); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) { - // STRING - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_string(bad_usb, line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid string %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) { - // ALTCHAR - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - ducky_numlock_on(); - state = ducky_altchar(line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid altchar %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if( - (strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) || - (strncmp(line_tmp, ducky_cmd_altstr_2, strlen(ducky_cmd_altstr_2)) == 0)) { - // ALTSTRING - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - ducky_numlock_on(); - state = ducky_altstring(line_tmp); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid altstring %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { - // REPEAT - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); - if(!state && error != NULL) { - snprintf(error, error_len, "Invalid number %s", line_tmp); - } - return (state) ? (0) : SCRIPT_STATE_ERROR; - } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) { - // SYSRQ - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); - furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release_all(); - return (0); - } else { - // Special keys + modifiers - uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); - if(key == HID_KEYBOARD_NONE) { - if(error != NULL) { - snprintf(error, error_len, "No keycode defined for %s", line_tmp); - } - return SCRIPT_STATE_ERROR; - } - if((key & 0xFF00) != 0) { - // It's a modifier key - line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; - key |= ducky_get_keycode(bad_usb, line_tmp, true); - } - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release(key); - return (0); - } -} - -static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { - if(sscanf(line, "%lX:%lX", &bad_usb->hid_cfg.vid, &bad_usb->hid_cfg.pid) == 2) { - bad_usb->hid_cfg.manuf[0] = '\0'; - bad_usb->hid_cfg.product[0] = '\0'; - - uint8_t id_len = ducky_get_command_len(line); - if(!ducky_is_line_end(line[id_len + 1])) { - sscanf( - &line[id_len + 1], - "%31[^\r\n:]:%31[^\r\n]", - bad_usb->hid_cfg.manuf, - bad_usb->hid_cfg.product); - } - FURI_LOG_D( - WORKER_TAG, - "set id: %04lX:%04lX mfr:%s product:%s", - bad_usb->hid_cfg.vid, - bad_usb->hid_cfg.pid, - bad_usb->hid_cfg.manuf, - bad_usb->hid_cfg.product); - return true; - } - return false; -} - -static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { - uint8_t ret = 0; - uint32_t line_len = 0; - - furi_string_reset(bad_usb->line); - - do { - ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN); - for(uint16_t i = 0; i < ret; i++) { - if(bad_usb->file_buf[i] == '\n' && line_len > 0) { - bad_usb->st.line_nb++; - line_len = 0; - } else { - if(bad_usb->st.line_nb == 0) { // Save first line - furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]); - } - line_len++; - } - } - if(storage_file_eof(script_file)) { - if(line_len > 0) { - bad_usb->st.line_nb++; - break; - } - } - } while(ret > 0); - - const char* line_tmp = furi_string_get_cstr(bad_usb->line); - bool id_set = false; // Looking for ID command at first line - if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { - id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]); - } - - if(id_set) { - furi_check(furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg)); - } else { - furi_check(furi_hal_usb_set_config(&usb_hid, NULL)); - } - - storage_file_seek(script_file, 0, true); - furi_string_reset(bad_usb->line); - - return true; -} - -static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_file) { - int32_t delay_val = 0; - - if(bad_usb->repeat_cnt > 0) { - bad_usb->repeat_cnt--; - delay_val = ducky_parse_line( - bad_usb, bad_usb->line_prev, bad_usb->st.error, sizeof(bad_usb->st.error)); - if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line - return 0; - } else if(delay_val < 0) { // Script error - bad_usb->st.error_line = bad_usb->st.line_cur - 1; - FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur - 1U); - return SCRIPT_STATE_ERROR; - } else { - return (delay_val + bad_usb->defdelay); - } - } - - furi_string_set(bad_usb->line_prev, bad_usb->line); - furi_string_reset(bad_usb->line); - - while(1) { - if(bad_usb->buf_len == 0) { - bad_usb->buf_len = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN); - if(storage_file_eof(script_file)) { - if((bad_usb->buf_len < FILE_BUFFER_LEN) && (bad_usb->file_end == false)) { - bad_usb->file_buf[bad_usb->buf_len] = '\n'; - bad_usb->buf_len++; - bad_usb->file_end = true; - } - } - - bad_usb->buf_start = 0; - if(bad_usb->buf_len == 0) return SCRIPT_STATE_END; - } - for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) { - if(bad_usb->file_buf[i] == '\n' && furi_string_size(bad_usb->line) > 0) { - bad_usb->st.line_cur++; - bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1); - bad_usb->buf_start = i + 1; - furi_string_trim(bad_usb->line); - delay_val = ducky_parse_line( - bad_usb, bad_usb->line, bad_usb->st.error, sizeof(bad_usb->st.error)); - if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line - return 0; - } else if(delay_val < 0) { - bad_usb->st.error_line = bad_usb->st.line_cur; - FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur); - return SCRIPT_STATE_ERROR; - } else { - return (delay_val + bad_usb->defdelay); - } - } else { - furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]); - } - } - bad_usb->buf_len = 0; - if(bad_usb->file_end) return SCRIPT_STATE_END; - } - - return 0; -} - -static void bad_usb_hid_state_callback(bool state, void* context) { - furi_assert(context); - BadUsbScript* bad_usb = context; - - if(state == true) - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect); - else - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect); -} - -static int32_t bad_usb_worker(void* context) { - BadUsbScript* bad_usb = context; - - BadUsbWorkerState worker_state = BadUsbStateInit; - int32_t delay_val = 0; - - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); - - FURI_LOG_I(WORKER_TAG, "Init"); - File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - bad_usb->line = furi_string_alloc(); - bad_usb->line_prev = furi_string_alloc(); - - furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb); - - while(1) { - if(worker_state == BadUsbStateInit) { // State: initialization - if(storage_file_open( - script_file, - furi_string_get_cstr(bad_usb->file_path), - FSAM_READ, - FSOM_OPEN_EXISTING)) { - if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) { - if(furi_hal_hid_is_connected()) { - worker_state = BadUsbStateIdle; // Ready to run - } else { - worker_state = BadUsbStateNotConnected; // USB not connected - } - } else { - worker_state = BadUsbStateScriptError; // Script preload error - } - } else { - FURI_LOG_E(WORKER_TAG, "File open error"); - worker_state = BadUsbStateFileError; // File open error - } - bad_usb->st.state = worker_state; - - } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, - FuriFlagWaitAny, - FuriWaitForever); - furi_check((flags & FuriFlagError) == 0); - if(flags & WorkerEvtEnd) { - break; - } else if(flags & WorkerEvtConnect) { - worker_state = BadUsbStateIdle; // Ready to run - } else if(flags & WorkerEvtToggle) { - worker_state = BadUsbStateWillRun; // Will run when USB is connected - } - bad_usb->st.state = worker_state; - - } else if(worker_state == BadUsbStateIdle) { // State: ready to start - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, - FuriFlagWaitAny, - FuriWaitForever); - furi_check((flags & FuriFlagError) == 0); - if(flags & WorkerEvtEnd) { - break; - } else if(flags & WorkerEvtToggle) { // Start executing script - DOLPHIN_DEED(DolphinDeedBadUsbPlayScript); - delay_val = 0; - bad_usb->buf_len = 0; - bad_usb->st.line_cur = 0; - bad_usb->defdelay = 0; - bad_usb->repeat_cnt = 0; - bad_usb->file_end = false; - storage_file_seek(script_file, 0, true); - worker_state = BadUsbStateRunning; - } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected - } - bad_usb->st.state = worker_state; - - } else if(worker_state == BadUsbStateWillRun) { // State: start on connection - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, - FuriFlagWaitAny, - FuriWaitForever); - furi_check((flags & FuriFlagError) == 0); - if(flags & WorkerEvtEnd) { - break; - } else if(flags & WorkerEvtConnect) { // Start executing script - DOLPHIN_DEED(DolphinDeedBadUsbPlayScript); - delay_val = 0; - bad_usb->buf_len = 0; - bad_usb->st.line_cur = 0; - bad_usb->defdelay = 0; - bad_usb->repeat_cnt = 0; - bad_usb->file_end = false; - storage_file_seek(script_file, 0, true); - // extra time for PC to recognize Flipper as keyboard - furi_thread_flags_wait(0, FuriFlagWaitAny, 1500); - worker_state = BadUsbStateRunning; - } else if(flags & WorkerEvtToggle) { // Cancel scheduled execution - worker_state = BadUsbStateNotConnected; - } - bad_usb->st.state = worker_state; - - } else if(worker_state == BadUsbStateRunning) { // State: running - uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur); - delay_val -= delay_cur; - if(!(flags & FuriFlagError)) { - if(flags & WorkerEvtEnd) { - break; - } else if(flags & WorkerEvtToggle) { - worker_state = BadUsbStateIdle; // Stop executing script - furi_hal_hid_kb_release_all(); - } else if(flags & WorkerEvtDisconnect) { - worker_state = BadUsbStateNotConnected; // USB disconnected - furi_hal_hid_kb_release_all(); - } - bad_usb->st.state = worker_state; - continue; - } else if( - (flags == (unsigned)FuriFlagErrorTimeout) || - (flags == (unsigned)FuriFlagErrorResource)) { - if(delay_val > 0) { - bad_usb->st.delay_remain--; - continue; - } - bad_usb->st.state = BadUsbStateRunning; - delay_val = ducky_script_execute_next(bad_usb, script_file); - if(delay_val == SCRIPT_STATE_ERROR) { // Script error - delay_val = 0; - worker_state = BadUsbStateScriptError; - bad_usb->st.state = worker_state; - } else if(delay_val == SCRIPT_STATE_END) { // End of script - delay_val = 0; - worker_state = BadUsbStateIdle; - bad_usb->st.state = BadUsbStateDone; - furi_hal_hid_kb_release_all(); - continue; - } else if(delay_val > 1000) { - bad_usb->st.state = BadUsbStateDelay; // Show long delays - bad_usb->st.delay_remain = delay_val / 1000; - } - } else { - furi_check((flags & FuriFlagError) == 0); - } - - } else if( - (worker_state == BadUsbStateFileError) || - (worker_state == BadUsbStateScriptError)) { // State: error - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd, FuriFlagWaitAny, FuriWaitForever); // Waiting for exit command - furi_check((flags & FuriFlagError) == 0); - if(flags & WorkerEvtEnd) { - break; - } - } - } - - furi_hal_hid_set_state_callback(NULL, NULL); - - furi_hal_usb_set_config(usb_mode_prev, NULL); - - storage_file_close(script_file); - storage_file_free(script_file); - furi_string_free(bad_usb->line); - furi_string_free(bad_usb->line_prev); - - FURI_LOG_I(WORKER_TAG, "End"); - - return 0; -} - -static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) { - furi_assert(bad_usb); - memset(bad_usb->layout, HID_KEYBOARD_NONE, sizeof(bad_usb->layout)); - memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout))); -} - -BadUsbScript* bad_usb_script_open(FuriString* file_path) { - furi_assert(file_path); - - BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); - bad_usb->file_path = furi_string_alloc(); - furi_string_set(bad_usb->file_path, file_path); - bad_usb_script_set_default_keyboard_layout(bad_usb); - - bad_usb->st.state = BadUsbStateInit; - bad_usb->st.error[0] = '\0'; - - bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb); - furi_thread_start(bad_usb->thread); - return bad_usb; -} //-V773 - -void bad_usb_script_close(BadUsbScript* bad_usb) { - furi_assert(bad_usb); - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd); - furi_thread_join(bad_usb->thread); - furi_thread_free(bad_usb->thread); - furi_string_free(bad_usb->file_path); - free(bad_usb); -} - -void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path) { - furi_assert(bad_usb); - - if((bad_usb->st.state == BadUsbStateRunning) || (bad_usb->st.state == BadUsbStateDelay)) { - // do not update keyboard layout while a script is running - return; - } - - File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); - if(!furi_string_empty(layout_path)) { - if(storage_file_open( - layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) { - uint16_t layout[128]; - if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) { - memcpy(bad_usb->layout, layout, sizeof(layout)); - } - } - storage_file_close(layout_file); - } else { - bad_usb_script_set_default_keyboard_layout(bad_usb); - } - storage_file_free(layout_file); -} - -void bad_usb_script_toggle(BadUsbScript* bad_usb) { - furi_assert(bad_usb); - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle); -} - -BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) { - furi_assert(bad_usb); - return &(bad_usb->st); -} diff --git a/applications/main/bad_usb/bad_usb_script.h b/applications/main/bad_usb/bad_usb_script.h deleted file mode 100644 index 1e4d98fe7..000000000 --- a/applications/main/bad_usb/bad_usb_script.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef struct BadUsbScript BadUsbScript; - -typedef enum { - BadUsbStateInit, - BadUsbStateNotConnected, - BadUsbStateIdle, - BadUsbStateWillRun, - BadUsbStateRunning, - BadUsbStateDelay, - BadUsbStateDone, - BadUsbStateScriptError, - BadUsbStateFileError, -} BadUsbWorkerState; - -typedef struct { - BadUsbWorkerState state; - uint16_t line_cur; - uint16_t line_nb; - uint32_t delay_remain; - uint16_t error_line; - char error[64]; -} BadUsbState; - -BadUsbScript* bad_usb_script_open(FuriString* file_path); - -void bad_usb_script_close(BadUsbScript* bad_usb); - -void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path); - -void bad_usb_script_start(BadUsbScript* bad_usb); - -void bad_usb_script_stop(BadUsbScript* bad_usb); - -void bad_usb_script_toggle(BadUsbScript* bad_usb); - -BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb); - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/bad_usb/bad_usb_settings_filename.h b/applications/main/bad_usb/bad_usb_settings_filename.h deleted file mode 100644 index 12ba8f31c..000000000 --- a/applications/main/bad_usb/bad_usb_settings_filename.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings" diff --git a/applications/main/bad_usb/scenes/bad_usb_scene.c b/applications/main/bad_usb/scenes/bad_usb_scene.c deleted file mode 100644 index 03c7c4471..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "bad_usb_scene.h" - -// Generate scene on_enter handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, -void (*const bad_usb_scene_on_enter_handlers[])(void*) = { -#include "bad_usb_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_event handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, -bool (*const bad_usb_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { -#include "bad_usb_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_exit handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, -void (*const bad_usb_scene_on_exit_handlers[])(void* context) = { -#include "bad_usb_scene_config.h" -}; -#undef ADD_SCENE - -// Initialize scene handlers configuration structure -const SceneManagerHandlers bad_usb_scene_handlers = { - .on_enter_handlers = bad_usb_scene_on_enter_handlers, - .on_event_handlers = bad_usb_scene_on_event_handlers, - .on_exit_handlers = bad_usb_scene_on_exit_handlers, - .scene_num = BadUsbSceneNum, -}; diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.c b/applications/main/bad_usb/scenes/bad_usb_scene_config.c deleted file mode 100644 index 2a9f2f76c..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "../bad_usb_app_i.h" -#include "furi_hal_power.h" -#include "furi_hal_usb.h" - -enum SubmenuIndex { - SubmenuIndexKeyboardLayout, -}; - -void bad_usb_scene_config_submenu_callback(void* context, uint32_t index) { - BadUsbApp* bad_usb = context; - view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index); -} - -void bad_usb_scene_config_on_enter(void* context) { - BadUsbApp* bad_usb = context; - Submenu* submenu = bad_usb->submenu; - - submenu_add_item( - submenu, - "Keyboard layout", - SubmenuIndexKeyboardLayout, - bad_usb_scene_config_submenu_callback, - bad_usb); - - submenu_set_selected_item( - submenu, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig)); - - view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig); -} - -bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) { - BadUsbApp* bad_usb = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event); - consumed = true; - if(event.event == SubmenuIndexKeyboardLayout) { - scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout); - } else { - furi_crash("Unknown key type"); - } - } - - return consumed; -} - -void bad_usb_scene_config_on_exit(void* context) { - BadUsbApp* bad_usb = context; - Submenu* submenu = bad_usb->submenu; - - submenu_reset(submenu); -} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.h b/applications/main/bad_usb/scenes/bad_usb_scene_config.h deleted file mode 100644 index 423aedc51..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.h +++ /dev/null @@ -1,5 +0,0 @@ -ADD_SCENE(bad_usb, file_select, FileSelect) -ADD_SCENE(bad_usb, work, Work) -ADD_SCENE(bad_usb, error, Error) -ADD_SCENE(bad_usb, config, Config) -ADD_SCENE(bad_usb, config_layout, ConfigLayout) diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c deleted file mode 100644 index 44dcd55af..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "../bad_usb_app_i.h" -#include "furi_hal_power.h" -#include "furi_hal_usb.h" -#include - -static bool bad_usb_layout_select(BadUsbApp* bad_usb) { - furi_assert(bad_usb); - - FuriString* predefined_path; - predefined_path = furi_string_alloc(); - if(!furi_string_empty(bad_usb->keyboard_layout)) { - furi_string_set(predefined_path, bad_usb->keyboard_layout); - } else { - furi_string_set(predefined_path, BAD_USB_APP_PATH_LAYOUT_FOLDER); - } - - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options( - &browser_options, BAD_USB_APP_LAYOUT_EXTENSION, &I_keyboard_10px); - - // Input events and views are managed by file_browser - bool res = dialog_file_browser_show( - bad_usb->dialogs, bad_usb->keyboard_layout, predefined_path, &browser_options); - - furi_string_free(predefined_path); - return res; -} - -void bad_usb_scene_config_layout_on_enter(void* context) { - BadUsbApp* bad_usb = context; - - if(bad_usb_layout_select(bad_usb)) { - bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); - } - scene_manager_previous_scene(bad_usb->scene_manager); -} - -bool bad_usb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - // BadUsbApp* bad_usb = context; - return false; -} - -void bad_usb_scene_config_layout_on_exit(void* context) { - UNUSED(context); - // BadUsbApp* bad_usb = context; -} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c deleted file mode 100644 index 21a2ce024..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "../bad_usb_app_i.h" -#include "furi_hal_power.h" -#include "furi_hal_usb.h" -#include - -static bool bad_usb_file_select(BadUsbApp* bad_usb) { - furi_assert(bad_usb); - - DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options( - &browser_options, BAD_USB_APP_SCRIPT_EXTENSION, &I_badusb_10px); - browser_options.base_path = BAD_USB_APP_BASE_FOLDER; - browser_options.skip_assets = true; - - // Input events and views are managed by file_browser - bool res = dialog_file_browser_show( - bad_usb->dialogs, bad_usb->file_path, bad_usb->file_path, &browser_options); - - return res; -} - -void bad_usb_scene_file_select_on_enter(void* context) { - BadUsbApp* bad_usb = context; - - furi_hal_usb_disable(); - if(bad_usb->bad_usb_script) { - bad_usb_script_close(bad_usb->bad_usb_script); - bad_usb->bad_usb_script = NULL; - } - - if(bad_usb_file_select(bad_usb)) { - bad_usb->bad_usb_script = bad_usb_script_open(bad_usb->file_path); - bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); - - scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork); - } else { - furi_hal_usb_enable(); - view_dispatcher_stop(bad_usb->view_dispatcher); - } -} - -bool bad_usb_scene_file_select_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - // BadUsbApp* bad_usb = context; - return false; -} - -void bad_usb_scene_file_select_on_exit(void* context) { - UNUSED(context); - // BadUsbApp* bad_usb = context; -} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c deleted file mode 100644 index 2971c01e9..000000000 --- a/applications/main/bad_usb/scenes/bad_usb_scene_work.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "../bad_usb_script.h" -#include "../bad_usb_app_i.h" -#include "../views/bad_usb_view.h" -#include "furi_hal.h" -#include "toolbox/path.h" - -void bad_usb_scene_work_button_callback(InputKey key, void* context) { - furi_assert(context); - BadUsbApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, key); -} - -bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { - BadUsbApp* app = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == InputKeyLeft) { - scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig); - consumed = true; - } else if(event.event == InputKeyOk) { - bad_usb_script_toggle(app->bad_usb_script); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeTick) { - bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); - } - return consumed; -} - -void bad_usb_scene_work_on_enter(void* context) { - BadUsbApp* app = context; - - FuriString* file_name; - file_name = furi_string_alloc(); - path_extract_filename(app->file_path, file_name, true); - bad_usb_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name)); - furi_string_free(file_name); - - FuriString* layout; - layout = furi_string_alloc(); - path_extract_filename(app->keyboard_layout, layout, true); - bad_usb_set_layout(app->bad_usb_view, furi_string_get_cstr(layout)); - furi_string_free(layout); - - bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script)); - - bad_usb_set_button_callback(app->bad_usb_view, bad_usb_scene_work_button_callback, app); - view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWork); -} - -void bad_usb_scene_work_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/main/bad_usb/views/bad_usb_view.h b/applications/main/bad_usb/views/bad_usb_view.h deleted file mode 100644 index 8447fb055..000000000 --- a/applications/main/bad_usb/views/bad_usb_view.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include "../bad_usb_script.h" - -typedef struct BadUsb BadUsb; -typedef void (*BadUsbButtonCallback)(InputKey key, void* context); - -BadUsb* bad_usb_alloc(); - -void bad_usb_free(BadUsb* bad_usb); - -View* bad_usb_get_view(BadUsb* bad_usb); - -void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context); - -void bad_usb_set_file_name(BadUsb* bad_usb, const char* name); - -void bad_usb_set_layout(BadUsb* bad_usb, const char* layout); - -void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st); diff --git a/applications/main/gpio/gpio_app.c b/applications/main/gpio/gpio_app.c index 19e53f453..3fecc5427 100644 --- a/applications/main/gpio/gpio_app.c +++ b/applications/main/gpio/gpio_app.c @@ -25,6 +25,7 @@ GpioApp* gpio_app_alloc() { GpioApp* app = malloc(sizeof(GpioApp)); app->gui = furi_record_open(RECORD_GUI); + app->gpio_items = gpio_items_alloc(); app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app); @@ -47,7 +48,7 @@ GpioApp* gpio_app_alloc() { app->view_dispatcher, GpioAppViewVarItemList, variable_item_list_get_view(app->var_item_list)); - app->gpio_test = gpio_test_alloc(); + app->gpio_test = gpio_test_alloc(app->gpio_items); view_dispatcher_add_view( app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test)); @@ -105,6 +106,7 @@ void gpio_app_free(GpioApp* app) { furi_record_close(RECORD_GUI); furi_record_close(RECORD_NOTIFICATION); + gpio_items_free(app->gpio_items); free(app); } diff --git a/applications/main/gpio/gpio_app_i.h b/applications/main/gpio/gpio_app_i.h index ac6c77a8e..20140f07a 100644 --- a/applications/main/gpio/gpio_app_i.h +++ b/applications/main/gpio/gpio_app_i.h @@ -1,7 +1,7 @@ #pragma once #include "gpio_app.h" -#include "gpio_item.h" +#include "gpio_items.h" #include "scenes/gpio_scene.h" #include "gpio_custom_event.h" #include "usb_uart_bridge.h" @@ -30,6 +30,7 @@ struct GpioApp { VariableItem* var_item_flow; GpioTest* gpio_test; GpioUsbUart* gpio_usb_uart; + GPIOItems* gpio_items; UsbUartBridge* usb_uart_bridge; GpioI2CScanner* gpio_i2c_scanner; GpioI2CSfp* gpio_i2c_sfp; diff --git a/applications/main/gpio/gpio_item.c b/applications/main/gpio/gpio_item.c deleted file mode 100644 index 2d0f5f676..000000000 --- a/applications/main/gpio/gpio_item.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "gpio_item.h" - -#include - -typedef struct { - const char* name; - const GpioPin* pin; -} GpioItem; - -static const GpioItem gpio_item[GPIO_ITEM_COUNT] = { - {"1.2: PA7", &gpio_ext_pa7}, - {"1.3: PA6", &gpio_ext_pa6}, - {"1.4: PA4", &gpio_ext_pa4}, - {"1.5: PB3", &gpio_ext_pb3}, - {"1.6: PB2", &gpio_ext_pb2}, - {"1.7: PC3", &gpio_ext_pc3}, - {"2.7: PC1", &gpio_ext_pc1}, - {"2.8: PC0", &gpio_ext_pc0}, -}; - -void gpio_item_configure_pin(uint8_t index, GpioMode mode) { - furi_assert(index < GPIO_ITEM_COUNT); - furi_hal_gpio_write(gpio_item[index].pin, false); - furi_hal_gpio_init(gpio_item[index].pin, mode, GpioPullNo, GpioSpeedVeryHigh); -} - -void gpio_item_configure_all_pins(GpioMode mode) { - for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) { - gpio_item_configure_pin(i, mode); - } -} - -void gpio_item_set_pin(uint8_t index, bool level) { - furi_assert(index < GPIO_ITEM_COUNT); - furi_hal_gpio_write(gpio_item[index].pin, level); -} - -void gpio_item_set_all_pins(bool level) { - for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) { - gpio_item_set_pin(i, level); - } -} - -const char* gpio_item_get_pin_name(uint8_t index) { - furi_assert(index < GPIO_ITEM_COUNT + 1); - if(index == GPIO_ITEM_COUNT) { - return "ALL"; - } else { - return gpio_item[index].name; - } -} diff --git a/applications/main/gpio/gpio_item.h b/applications/main/gpio/gpio_item.h deleted file mode 100644 index 5cb2b86c1..000000000 --- a/applications/main/gpio/gpio_item.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#define GPIO_ITEM_COUNT 8 - -void gpio_item_configure_pin(uint8_t index, GpioMode mode); - -void gpio_item_configure_all_pins(GpioMode mode); - -void gpio_item_set_pin(uint8_t index, bool level); - -void gpio_item_set_all_pins(bool level); - -const char* gpio_item_get_pin_name(uint8_t index); diff --git a/applications/main/gpio/gpio_items.c b/applications/main/gpio/gpio_items.c new file mode 100644 index 000000000..02f7d95b0 --- /dev/null +++ b/applications/main/gpio/gpio_items.c @@ -0,0 +1,69 @@ +#include "gpio_items.h" + +#include + +struct GPIOItems { + GpioPinRecord* pins; + size_t count; +}; + +GPIOItems* gpio_items_alloc() { + GPIOItems* items = malloc(sizeof(GPIOItems)); + + items->count = 0; + for(size_t i = 0; i < gpio_pins_count; i++) { + if(!gpio_pins[i].debug) { + items->count++; + } + } + + items->pins = malloc(sizeof(GpioPinRecord) * items->count); + for(size_t i = 0; i < items->count; i++) { + if(!gpio_pins[i].debug) { + items->pins[i].pin = gpio_pins[i].pin; + items->pins[i].name = gpio_pins[i].name; + } + } + return items; +} + +void gpio_items_free(GPIOItems* items) { + free(items->pins); + free(items); +} + +uint8_t gpio_items_get_count(GPIOItems* items) { + return items->count; +} + +void gpio_items_configure_pin(GPIOItems* items, uint8_t index, GpioMode mode) { + furi_assert(index < items->count); + furi_hal_gpio_write(items->pins[index].pin, false); + furi_hal_gpio_init(items->pins[index].pin, mode, GpioPullNo, GpioSpeedVeryHigh); +} + +void gpio_items_configure_all_pins(GPIOItems* items, GpioMode mode) { + for(uint8_t i = 0; i < items->count; i++) { + gpio_items_configure_pin(items, i, mode); + } +} + +void gpio_items_set_pin(GPIOItems* items, uint8_t index, bool level) { + furi_assert(index < items->count); + furi_hal_gpio_write(items->pins[index].pin, level); +} + +void gpio_items_set_all_pins(GPIOItems* items, bool level) { + for(uint8_t i = 0; i < items->count; i++) { + gpio_items_set_pin(items, i, level); + } +} + +const char* gpio_items_get_pin_name(GPIOItems* items, uint8_t index) { + furi_assert(index < items->count + 1); + if(index == items->count) { + return "ALL"; + } else { + return items->pins[index].name; + } +} diff --git a/applications/main/gpio/gpio_items.h b/applications/main/gpio/gpio_items.h new file mode 100644 index 000000000..68afbe693 --- /dev/null +++ b/applications/main/gpio/gpio_items.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GPIOItems GPIOItems; + +GPIOItems* gpio_items_alloc(); + +void gpio_items_free(GPIOItems* items); + +uint8_t gpio_items_get_count(GPIOItems* items); + +void gpio_items_configure_pin(GPIOItems* items, uint8_t index, GpioMode mode); + +void gpio_items_configure_all_pins(GPIOItems* items, GpioMode mode); + +void gpio_items_set_pin(GPIOItems* items, uint8_t index, bool level); + +void gpio_items_set_all_pins(GPIOItems* items, bool level); + +const char* gpio_items_get_pin_name(GPIOItems* items, uint8_t index); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/gpio/scenes/gpio_scene_start.c b/applications/main/gpio/scenes/gpio_scene_start.c index 08b77238f..1c1a665c7 100644 --- a/applications/main/gpio/scenes/gpio_scene_start.c +++ b/applications/main/gpio/scenes/gpio_scene_start.c @@ -1,6 +1,10 @@ +#ifndef __GPIO_SCENE_START_H__ +#define __GPIO_SCENE_START_H__ + #include "../gpio_app_i.h" -#include "furi_hal_power.h" -#include "furi_hal_usb.h" +#include +#include +#include enum GpioItem { GpioItemUsbUart, @@ -117,3 +121,5 @@ void gpio_scene_start_on_exit(void* context) { GpioApp* app = context; variable_item_list_reset(app->var_item_list); } + +#endif // __GPIO_SCENE_START_H__ \ No newline at end of file diff --git a/applications/main/gpio/scenes/gpio_scene_test.c b/applications/main/gpio/scenes/gpio_scene_test.c index b015d8090..9940b95d4 100644 --- a/applications/main/gpio/scenes/gpio_scene_test.c +++ b/applications/main/gpio/scenes/gpio_scene_test.c @@ -12,8 +12,9 @@ void gpio_scene_test_ok_callback(InputType type, void* context) { } void gpio_scene_test_on_enter(void* context) { + furi_assert(context); GpioApp* app = context; - gpio_item_configure_all_pins(GpioModeOutputPushPull); + gpio_items_configure_all_pins(app->gpio_items, GpioModeOutputPushPull); gpio_test_set_ok_callback(app->gpio_test, gpio_scene_test_ok_callback, app); view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewGpioTest); } @@ -25,6 +26,7 @@ bool gpio_scene_test_on_event(void* context, SceneManagerEvent event) { } void gpio_scene_test_on_exit(void* context) { - UNUSED(context); - gpio_item_configure_all_pins(GpioModeAnalog); + furi_assert(context); + GpioApp* app = context; + gpio_items_configure_all_pins(app->gpio_items, GpioModeAnalog); } diff --git a/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c b/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c index 776343fb0..e2ab66264 100644 --- a/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c +++ b/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c @@ -1,6 +1,6 @@ #include "../usb_uart_bridge.h" #include "../gpio_app_i.h" -#include "furi_hal.h" +#include typedef enum { UsbUartLineIndexVcp, diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index 1a82dbdc2..9bc759dc8 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -1,10 +1,10 @@ #include "usb_uart_bridge.h" -#include "furi_hal.h" -#include #include "usb_cdc.h" -#include "cli/cli_vcp.h" +#include +#include #include -#include "cli/cli.h" +#include +#include #define USB_CDC_PKT_LEN CDC_DATA_SZ #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) diff --git a/applications/main/gpio/views/gpio_i2c_scanner.c b/applications/main/gpio/views/gpio_i2c_scanner.c index 0f00639d6..fc9ed78a7 100644 --- a/applications/main/gpio/views/gpio_i2c_scanner.c +++ b/applications/main/gpio/views/gpio_i2c_scanner.c @@ -1,6 +1,6 @@ #include #include "gpio_i2c_scanner.h" -#include "../gpio_item.h" +#include "../gpio_items.h" #include diff --git a/applications/main/gpio/views/gpio_i2c_sfp.c b/applications/main/gpio/views/gpio_i2c_sfp.c index 85492e783..c8e14ce7a 100644 --- a/applications/main/gpio/views/gpio_i2c_sfp.c +++ b/applications/main/gpio/views/gpio_i2c_sfp.c @@ -1,6 +1,6 @@ #include #include "gpio_i2c_sfp.h" -#include "../gpio_item.h" +#include "../gpio_items.h" #include diff --git a/applications/main/gpio/views/gpio_test.c b/applications/main/gpio/views/gpio_test.c index 69dc0f67b..c154a7275 100644 --- a/applications/main/gpio/views/gpio_test.c +++ b/applications/main/gpio/views/gpio_test.c @@ -1,5 +1,5 @@ #include "gpio_test.h" -#include "../gpio_item.h" +#include "../gpio_items.h" #include @@ -11,6 +11,7 @@ struct GpioTest { typedef struct { uint8_t pin_idx; + GPIOItems* gpio_items; } GpioTestModel; static bool gpio_test_process_left(GpioTest* gpio_test); @@ -25,7 +26,12 @@ static void gpio_test_draw_callback(Canvas* canvas, void* _model) { elements_multiline_text_aligned( canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin"); elements_multiline_text_aligned( - canvas, 64, 32, AlignCenter, AlignTop, gpio_item_get_pin_name(model->pin_idx)); + canvas, + 64, + 32, + AlignCenter, + AlignTop, + gpio_items_get_pin_name(model->gpio_items, model->pin_idx)); } static bool gpio_test_input_callback(InputEvent* event, void* context) { @@ -64,7 +70,7 @@ static bool gpio_test_process_right(GpioTest* gpio_test) { gpio_test->view, GpioTestModel * model, { - if(model->pin_idx < GPIO_ITEM_COUNT) { + if(model->pin_idx < gpio_items_get_count(model->gpio_items)) { model->pin_idx++; } }, @@ -80,17 +86,17 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) { GpioTestModel * model, { if(event->type == InputTypePress) { - if(model->pin_idx < GPIO_ITEM_COUNT) { - gpio_item_set_pin(model->pin_idx, true); + if(model->pin_idx < gpio_items_get_count(model->gpio_items)) { + gpio_items_set_pin(model->gpio_items, model->pin_idx, true); } else { - gpio_item_set_all_pins(true); + gpio_items_set_all_pins(model->gpio_items, true); } consumed = true; } else if(event->type == InputTypeRelease) { - if(model->pin_idx < GPIO_ITEM_COUNT) { - gpio_item_set_pin(model->pin_idx, false); + if(model->pin_idx < gpio_items_get_count(model->gpio_items)) { + gpio_items_set_pin(model->gpio_items, model->pin_idx, false); } else { - gpio_item_set_all_pins(false); + gpio_items_set_all_pins(model->gpio_items, false); } consumed = true; } @@ -101,11 +107,15 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) { return consumed; } -GpioTest* gpio_test_alloc() { +GpioTest* gpio_test_alloc(GPIOItems* gpio_items) { GpioTest* gpio_test = malloc(sizeof(GpioTest)); gpio_test->view = view_alloc(); view_allocate_model(gpio_test->view, ViewModelTypeLocking, sizeof(GpioTestModel)); + + with_view_model( + gpio_test->view, GpioTestModel * model, { model->gpio_items = gpio_items; }, false); + view_set_context(gpio_test->view, gpio_test); view_set_draw_callback(gpio_test->view, gpio_test_draw_callback); view_set_input_callback(gpio_test->view, gpio_test_input_callback); diff --git a/applications/main/gpio/views/gpio_test.h b/applications/main/gpio/views/gpio_test.h index 5cbd11e82..38fcbc5fb 100644 --- a/applications/main/gpio/views/gpio_test.h +++ b/applications/main/gpio/views/gpio_test.h @@ -1,11 +1,13 @@ #pragma once +#include "../gpio_items.h" + #include typedef struct GpioTest GpioTest; typedef void (*GpioTestOkCallback)(InputType type, void* context); -GpioTest* gpio_test_alloc(); +GpioTest* gpio_test_alloc(GPIOItems* gpio_items); void gpio_test_free(GpioTest* gpio_test); diff --git a/applications/main/gpio/views/gpio_usb_uart.c b/applications/main/gpio/views/gpio_usb_uart.c index c7406d29b..837f2e3ec 100644 --- a/applications/main/gpio/views/gpio_usb_uart.c +++ b/applications/main/gpio/views/gpio_usb_uart.c @@ -1,6 +1,6 @@ #include "../usb_uart_bridge.h" #include "../gpio_app_i.h" -#include "furi_hal.h" +#include #include struct GpioUsbUart { diff --git a/applications/main/ibutton/application.fam b/applications/main/ibutton/application.fam index 77bb9a33c..06968bba4 100644 --- a/applications/main/ibutton/application.fam +++ b/applications/main/ibutton/application.fam @@ -2,6 +2,7 @@ App( appid="ibutton", name="iButton", apptype=FlipperAppType.APP, + targets=["f7"], entry_point="ibutton_app", cdefines=["APP_IBUTTON"], requires=[ diff --git a/applications/main/ibutton/scenes/ibutton_scene_delete_success.c b/applications/main/ibutton/scenes/ibutton_scene_delete_success.c index 5f12d49d7..e2b7e3837 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_delete_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_delete_success.c @@ -1,5 +1,5 @@ #include "../ibutton_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" static void ibutton_scene_delete_success_popup_callback(void* context) { iButton* ibutton = context; diff --git a/applications/main/ibutton/scenes/ibutton_scene_read.c b/applications/main/ibutton/scenes/ibutton_scene_read.c index 718cb8bfc..1ccd2562b 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read.c @@ -1,6 +1,6 @@ #include "../ibutton_i.h" #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" static void ibutton_scene_read_callback(void* context) { iButton* ibutton = context; diff --git a/applications/main/ibutton/scenes/ibutton_scene_save_success.c b/applications/main/ibutton/scenes/ibutton_scene_save_success.c index ee49b432c..03e88e047 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_save_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_save_success.c @@ -1,5 +1,5 @@ #include "../ibutton_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" static void ibutton_scene_save_success_popup_callback(void* context) { iButton* ibutton = context; diff --git a/applications/main/ibutton/scenes/ibutton_scene_write_success.c b/applications/main/ibutton/scenes/ibutton_scene_write_success.c index e77f3f049..3f565e274 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_write_success.c +++ b/applications/main/ibutton/scenes/ibutton_scene_write_success.c @@ -1,5 +1,5 @@ #include "../ibutton_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" static void ibutton_scene_write_success_popup_callback(void* context) { iButton* ibutton = context; diff --git a/applications/main/infrared/application.fam b/applications/main/infrared/application.fam index 9c5eaf392..e5483e9ff 100644 --- a/applications/main/infrared/application.fam +++ b/applications/main/infrared/application.fam @@ -3,6 +3,7 @@ App( name="Infrared", apptype=FlipperAppType.APP, entry_point="infrared_app", + targets=["f7"], cdefines=["APP_INFRARED"], requires=[ "gui", diff --git a/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c index 3d7a9d081..36224f418 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c @@ -1,5 +1,5 @@ #include "../infrared_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void infrared_scene_edit_rename_done_on_enter(void* context) { Infrared* infrared = context; diff --git a/applications/main/infrared/scenes/infrared_scene_learn_done.c b/applications/main/infrared/scenes/infrared_scene_learn_done.c index dce74db54..0d2522946 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_done.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_done.c @@ -1,5 +1,5 @@ #include "../infrared_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void infrared_scene_learn_done_on_enter(void* context) { Infrared* infrared = context; diff --git a/applications/main/infrared/scenes/infrared_scene_learn_success.c b/applications/main/infrared/scenes/infrared_scene_learn_success.c index 3340a6342..bbc84ba3b 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_success.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_success.c @@ -1,5 +1,5 @@ #include "../infrared_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" static void infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { diff --git a/applications/main/infrared/scenes/infrared_scene_rpc.c b/applications/main/infrared/scenes/infrared_scene_rpc.c index 8044e8318..04f17416d 100644 --- a/applications/main/infrared/scenes/infrared_scene_rpc.c +++ b/applications/main/infrared/scenes/infrared_scene_rpc.c @@ -1,5 +1,5 @@ #include "../infrared_i.h" -#include "gui/canvas.h" +#include typedef enum { InfraredRpcStateIdle, diff --git a/applications/main/infrared/views/infrared_debug_view.c b/applications/main/infrared/views/infrared_debug_view.c index ab2c679c4..ec0896281 100644 --- a/applications/main/infrared/views/infrared_debug_view.c +++ b/applications/main/infrared/views/infrared_debug_view.c @@ -1,11 +1,11 @@ #include "infrared_debug_view.h" -#include -#include - #include #include +#include +#include + #define INFRARED_DEBUG_TEXT_LENGTH 64 struct InfraredDebugView { diff --git a/applications/main/infrared/views/infrared_progress_view.c b/applications/main/infrared/views/infrared_progress_view.c index 3c50f89e4..432da7ff1 100644 --- a/applications/main/infrared/views/infrared_progress_view.c +++ b/applications/main/infrared/views/infrared_progress_view.c @@ -1,13 +1,15 @@ -#include -#include "furi_hal_resources.h" -#include "assets_icons.h" -#include "gui/canvas.h" -#include "gui/view.h" -#include "input/input.h" -#include -#include #include "infrared_progress_view.h" -#include "gui/modules/button_panel.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include struct InfraredProgressView { diff --git a/applications/main/lfrfid/application.fam b/applications/main/lfrfid/application.fam index 150a6f3db..8fe1bac4d 100644 --- a/applications/main/lfrfid/application.fam +++ b/applications/main/lfrfid/application.fam @@ -2,6 +2,7 @@ App( appid="lfrfid", name="125 kHz RFID", apptype=FlipperAppType.APP, + targets=["f7"], entry_point="lfrfid_app", cdefines=["APP_LF_RFID"], requires=[ diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c index 7d9d50765..888288a31 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c @@ -1,6 +1,6 @@ #include "../lfrfid_i.h" #include "../helpers/rfid_writer.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" static void writer_initialize(T55xxTiming* t55xxtiming) { t55xxtiming->wait_time = 400; diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c index 873382b6c..991748515 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_delete_success.c @@ -1,5 +1,5 @@ #include "../lfrfid_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void lfrfid_scene_delete_success_on_enter(void* context) { LfRfid* app = context; diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c b/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c index 9132f4a91..eff92dc37 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_emulate.c @@ -1,5 +1,5 @@ #include "../lfrfid_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void lfrfid_scene_emulate_on_enter(void* context) { LfRfid* app = context; diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_raw_read.c b/applications/main/lfrfid/scenes/lfrfid_scene_raw_read.c index 73e1dbbb9..3213297d7 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_raw_read.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_raw_read.c @@ -1,5 +1,5 @@ #include "../lfrfid_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define RAW_READ_TIME 5000 diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c b/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c index c11dd1109..181346e9d 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c @@ -1,5 +1,5 @@ #include "../lfrfid_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void lfrfid_scene_rpc_on_enter(void* context) { LfRfid* app = context; diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c index 4003ee405..738e90bfd 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_success.c @@ -1,5 +1,5 @@ #include "../lfrfid_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void lfrfid_scene_save_success_on_enter(void* context) { LfRfid* app = context; diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_write.c b/applications/main/lfrfid/scenes/lfrfid_scene_write.c index 9cae43c96..0f74ece45 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_write.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_write.c @@ -1,5 +1,5 @@ #include "../lfrfid_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* context) { LfRfid* app = context; diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c b/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c index 48d046227..5eeb88616 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_write_success.c @@ -1,5 +1,5 @@ #include "../lfrfid_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void lfrfid_scene_write_success_on_enter(void* context) { LfRfid* app = context; diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index ce21bfd27..f09127045 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -2,6 +2,7 @@ App( appid="nfc", name="NFC", apptype=FlipperAppType.APP, + targets=["f7"], entry_point="nfc_app", cdefines=["APP_NFC"], requires=[ diff --git a/applications/main/nfc/nfc.c b/applications/main/nfc/nfc.c index 2ff224ec2..b6ea9cfb8 100644 --- a/applications/main/nfc/nfc.c +++ b/applications/main/nfc/nfc.c @@ -1,5 +1,5 @@ #include "nfc_i.h" -#include "furi_hal_nfc.h" +#include #include bool nfc_custom_event_callback(void* context, uint32_t event) { diff --git a/applications/main/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c index a732f5384..4994dd8d4 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc/scenes/nfc_scene_delete_success.c @@ -1,5 +1,5 @@ #include "../nfc_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void nfc_scene_delete_success_popup_callback(void* context) { Nfc* nfc = context; diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c b/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c index f423efc38..0e9f6b428 100644 --- a/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c +++ b/applications/main/nfc/scenes/nfc_scene_emulate_nfcv.c @@ -1,5 +1,5 @@ #include "../nfc_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (100) diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_uid.c b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c index a583ac12d..7c016ceda 100644 --- a/applications/main/nfc/scenes/nfc_scene_emulate_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c @@ -1,5 +1,5 @@ #include "../nfc_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c index 1d2e1784f..7f5cac406 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c @@ -1,5 +1,5 @@ #include "../nfc_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) #define NFC_MF_CLASSIC_DATA_CHANGED (1UL) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c index 3c2c724bd..9544721b6 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c @@ -1,6 +1,6 @@ #include "../nfc_i.h" #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void nfc_scene_mf_classic_update_success_popup_callback(void* context) { Nfc* nfc = context; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c index f16d2f733..e82dedeaf 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c @@ -1,6 +1,6 @@ #include "../nfc_i.h" #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void nfc_scene_mf_classic_write_success_popup_callback(void* context) { Nfc* nfc = context; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index d50ad5b84..77d831cf8 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -1,6 +1,6 @@ #include "../nfc_i.h" #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define NFC_SCENE_MF_ULTRALIGHT_EMULATE_LOG_SIZE_MAX (200) diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original.c b/applications/main/nfc/scenes/nfc_scene_restore_original.c index 3794b438d..409785e26 100644 --- a/applications/main/nfc/scenes/nfc_scene_restore_original.c +++ b/applications/main/nfc/scenes/nfc_scene_restore_original.c @@ -1,5 +1,5 @@ #include "../nfc_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void nfc_scene_restore_original_popup_callback(void* context) { Nfc* nfc = context; diff --git a/applications/main/nfc/scenes/nfc_scene_rpc.c b/applications/main/nfc/scenes/nfc_scene_rpc.c index e6b31fffa..6adacfda5 100644 --- a/applications/main/nfc/scenes/nfc_scene_rpc.c +++ b/applications/main/nfc/scenes/nfc_scene_rpc.c @@ -1,5 +1,5 @@ #include "../nfc_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void nfc_scene_rpc_on_enter(void* context) { Nfc* nfc = context; diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index a9359c434..c5d8a6872 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -1,5 +1,5 @@ #include "../nfc_i.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void nfc_scene_save_success_popup_callback(void* context) { Nfc* nfc = context; diff --git a/applications/main/subghz/application.fam b/applications/main/subghz/application.fam index 7d31ecae5..f0dc66e89 100644 --- a/applications/main/subghz/application.fam +++ b/applications/main/subghz/application.fam @@ -2,6 +2,7 @@ App( appid="subghz", name="Sub-GHz", apptype=FlipperAppType.APP, + targets=["f7"], entry_point="subghz_app", cdefines=["APP_SUBGHZ"], requires=[ @@ -11,7 +12,7 @@ App( ], provides=["subghz_start"], icon="A_Sub1ghz_14", - stack_size=2 * 1024, + stack_size=3 * 1024, order=10, ) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 0559ac67e..350e68ee6 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -50,7 +50,6 @@ typedef enum { SubGhzCustomEventSceneAnalyzerLock, SubGhzCustomEventSceneAnalyzerUnlock, SubGhzCustomEventSceneSettingLock, - SubGhzCustomEventSceneSettingError, SubGhzCustomEventSceneExit, SubGhzCustomEventSceneStay, diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index 7dc67c9f2..6452792a6 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -36,13 +36,13 @@ struct SubGhzFrequencyAnalyzerWorker { }; static void subghz_frequency_analyzer_worker_load_registers(const uint8_t data[][2]) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); size_t i = 0; while(data[i][0]) { - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i][0], data[i][1]); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, data[i][0], data[i][1]); i++; } - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } // running average with adaptive coefficient @@ -80,26 +80,26 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { //Start CC1101 furi_hal_subghz_reset(); - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_flush_rx(&furi_hal_spi_bus_handle_subghz); - cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_MDMCFG3, + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_flush_rx(furi_hal_subghz.spi_bus_handle); + cc1101_flush_tx(furi_hal_subghz.spi_bus_handle); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_MDMCFG3, 0b01111111); // symbol rate cc1101_write_reg( - &furi_hal_spi_bus_handle_subghz, + furi_hal_subghz.spi_bus_handle, CC1101_AGCCTRL2, 0b00000111); // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAGN_TARGET 42 dB cc1101_write_reg( - &furi_hal_spi_bus_handle_subghz, + furi_hal_subghz.spi_bus_handle, CC1101_AGCCTRL1, 0b00001000); // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 1000 - Absolute carrier sense threshold disabled cc1101_write_reg( - &furi_hal_spi_bus_handle_subghz, + furi_hal_subghz.spi_bus_handle, CC1101_AGCCTRL0, 0b00110000); // 00 - No hysteresis, medium asymmetric dead zone, medium gain ; 11 - 64 samples agc; 00 - Normal AGC, 00 - 4dB boundary - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); @@ -118,20 +118,23 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { // First stage: coarse scan for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) { if(furi_hal_subghz_is_frequency_valid( - subghz_setting_get_frequency(instance->setting, i))) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz); + subghz_setting_get_frequency(instance->setting, i)) && + !((furi_hal_subghz.radio_type == SubGhzRadioExternal) && + (subghz_setting_get_frequency(instance->setting, i) >= 311900000 && + subghz_setting_get_frequency(instance->setting, i) <= 312200000))) { + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle); frequency = cc1101_set_frequency( - &furi_hal_spi_bus_handle_subghz, + furi_hal_subghz.spi_bus_handle, subghz_setting_get_frequency(instance->setting, i)); - cc1101_calibrate(&furi_hal_spi_bus_handle_subghz); + cc1101_calibrate(furi_hal_subghz.spi_bus_handle); do { - status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz); + status = cc1101_get_status(furi_hal_subghz.spi_bus_handle); } while(status.STATE != CC1101StateIDLE); - cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + cc1101_switch_to_rx(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); furi_delay_ms(2); @@ -166,17 +169,17 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { i < frequency_rssi.frequency_coarse + 300000; i += 20000) { if(furi_hal_subghz_is_frequency_valid(i)) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz); - frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, i); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle); + frequency = cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, i); - cc1101_calibrate(&furi_hal_spi_bus_handle_subghz); + cc1101_calibrate(furi_hal_subghz.spi_bus_handle); do { - status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz); + status = cc1101_get_status(furi_hal_subghz.spi_bus_handle); } while(status.STATE != CC1101StateIDLE); - cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + cc1101_switch_to_rx(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); furi_delay_ms(2); diff --git a/applications/main/subghz/scenes/subghz_scene_config.h b/applications/main/subghz/scenes/subghz_scene_config.h index 1ad41a8b5..5acd534dc 100644 --- a/applications/main/subghz/scenes/subghz_scene_config.h +++ b/applications/main/subghz/scenes/subghz_scene_config.h @@ -26,6 +26,7 @@ ADD_SCENE(subghz, set_fix_bft, SetFixBft) ADD_SCENE(subghz, set_cnt_bft, SetCntBft) ADD_SCENE(subghz, set_seed_bft, SetSeedBft) ADD_SCENE(subghz, frequency_analyzer, FrequencyAnalyzer) +ADD_SCENE(subghz, ext_module_settings, ExtModuleSettings) ADD_SCENE(subghz, read_raw, ReadRAW) ADD_SCENE(subghz, more_raw, MoreRAW) ADD_SCENE(subghz, decode_raw, DecodeRAW) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index 6194d0dba..5746efbed 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -170,11 +170,6 @@ void subghz_scene_decode_raw_on_enter(void* context) { subghz_receiver_set_rx_callback( subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz); - // make sure we're not in auto-detect mode, which is only meant for the Read app - subghz_protocol_decoder_raw_set_auto_mode( - subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME), - false); subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); if(subghz->decode_raw_state == SubGhzDecodeRawStateStart) { diff --git a/applications/main/subghz/scenes/subghz_scene_delete_success.c b/applications/main/subghz/scenes/subghz_scene_delete_success.c index 4f00df70b..8e3ca5c78 100644 --- a/applications/main/subghz/scenes/subghz_scene_delete_success.c +++ b/applications/main/subghz/scenes/subghz_scene_delete_success.c @@ -1,6 +1,6 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void subghz_scene_delete_success_popup_callback(void* context) { SubGhz* subghz = context; @@ -32,7 +32,6 @@ bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); } else if(scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { - //scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); } else { scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); diff --git a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c new file mode 100644 index 000000000..7d7a505cb --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c @@ -0,0 +1,92 @@ +#include "../subghz_i.h" +#include "../helpers/subghz_custom_event.h" + +uint8_t value_index; +uint8_t value_index2; + +#define EXT_MODULES_COUNT (sizeof(radio_modules_variables_text) / sizeof(char* const)) +const char* const radio_modules_variables_text[] = { + "Internal", + "External", +}; + +#define DEBUG_P_COUNT 2 +const char* const debug_pin_text[DEBUG_P_COUNT] = { + "OFF", + "A7", +}; + +static void subghz_scene_ext_module_changed(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + value_index = variable_item_get_current_value_index(item); + UNUSED(subghz); + + variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]); +} +static void subghz_ext_module_start_var_list_enter_callback(void* context, uint32_t index) { + SubGhz* subghz = context; + view_dispatcher_send_custom_event(subghz->view_dispatcher, index); +} + +static void subghz_scene_receiver_config_set_debug_pin(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, debug_pin_text[index]); + + subghz->txrx->debug_pin_state = index == 1; +} + +void subghz_scene_ext_module_settings_on_enter(void* context) { + SubGhz* subghz = context; + + VariableItemList* variable_item_list = subghz->variable_item_list; + + value_index = furi_hal_subghz.radio_type; + VariableItem* item = variable_item_list_add( + variable_item_list, "Module", EXT_MODULES_COUNT, subghz_scene_ext_module_changed, subghz); + + variable_item_list_set_enter_callback( + variable_item_list, subghz_ext_module_start_var_list_enter_callback, subghz); + + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + item = variable_item_list_add( + subghz->variable_item_list, + "Debug Pin:", + DEBUG_P_COUNT, + subghz_scene_receiver_config_set_debug_pin, + subghz); + value_index2 = subghz->txrx->debug_pin_state; + variable_item_set_current_value_index(item, value_index2); + variable_item_set_current_value_text(item, debug_pin_text[value_index2]); + } + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); +} + +bool subghz_scene_ext_module_settings_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + UNUSED(subghz); + UNUSED(event); + + // Set selected radio module + furi_hal_subghz_set_radio_type(value_index); + + // Check if module is present, if no -> show error + if(!furi_hal_subghz_check_radio()) { + value_index = 0; + furi_hal_subghz_set_radio_type(value_index); + furi_string_set(subghz->error_str, "Please connect\nexternal radio"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); + } + + return false; +} + +void subghz_scene_ext_module_settings_on_exit(void* context) { + SubGhz* subghz = context; + variable_item_list_reset(subghz->variable_item_list); +} diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index fea4b6aef..e396527cc 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -119,9 +119,6 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME); furi_assert(subghz->txrx->decoder_result); - // make sure we're not in auto-detect mode, which is only meant for the Read app - subghz_protocol_decoder_raw_set_auto_mode(subghz->txrx->decoder_result, false); - //set filter RAW feed subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW); @@ -422,10 +419,6 @@ void subghz_scene_read_raw_on_exit(void* context) { subghz->state_notifications = SubGhzNotificationStateIDLE; notification_message(subghz->notifications, &sequence_reset_rgb); -//filter restoration -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - subghz_last_settings_set_detect_raw_values(subghz); -#else - subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); -#endif + //filter restoration + subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); } \ No newline at end of file diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index cab19f730..e1ea08497 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -1,6 +1,7 @@ #include "../subghz_i.h" #include "../views/receiver.h" #include +#include #define TAG "SubGhzSceneReceiver" @@ -53,7 +54,10 @@ static void subghz_scene_receiver_update_statusbar(void* context) { } else { subghz_get_frequency_modulation(subghz, frequency_str, NULL); furi_string_printf( - modulation_str, "Mod: %s", furi_string_get_cstr(subghz->txrx->preset->name)); + modulation_str, + "%s Mod: %s", + furi_hal_subghz_get_radio_type() ? "Ext" : "Int", + furi_string_get_cstr(subghz->txrx->preset->name)); } #else subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); @@ -157,6 +161,11 @@ void subghz_scene_receiver_on_enter(void* context) { } subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen); + //to use a universal decoder, we are looking for a link to it + subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( + subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME); + furi_assert(subghz->txrx->decoder_result); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); } @@ -173,7 +182,6 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_sleep(subghz); } subghz->txrx->hopper_state = SubGhzHopperStateOFF; - subghz_history_set_hopper_state(subghz->txrx->history, false); subghz->txrx->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); @@ -221,6 +229,13 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_hopper_update(subghz); subghz_scene_receiver_update_statusbar(subghz); } + + //get RSSI + float rssi = furi_hal_subghz_get_rssi(); + subghz_receiver_rssi(subghz->subghz_receiver, rssi); + subghz_protocol_decoder_bin_raw_data_input_rssi( + (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi); + switch(subghz->state_notifications) { case SubGhzNotificationStateRx: notification_message(subghz->notifications, &sequence_blink_cyan_10); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index c23d93496..af4c6aca3 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -1,16 +1,11 @@ #include "../subghz_i.h" #include -#include - -#define TAG "SubGhzSceneReceiverConfig" - enum SubGhzSettingIndex { SubGhzSettingIndexFrequency, SubGhzSettingIndexHopping, SubGhzSettingIndexModulation, - SubGhzSettingIndexDetectRaw, - SubGhzSettingIndexRSSIThreshold, + SubGhzSettingIndexBinRAW, SubGhzSettingIndexSound, SubGhzSettingIndexLock, SubGhzSettingIndexRAWThesholdRSSI, @@ -45,35 +40,6 @@ const float raw_theshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = { -40.0f, }; -#define BANDWIDTH_COUNT 16 -const char* const bandwidth_labels[BANDWIDTH_COUNT] = { - "58 kHz", - "68 kHz", - "81 kHz", - "102 kHz", - "116 kHz", - "135 kHz", - "162 kHz", - "203 kHz", - "232 kHz", - "270 kHz", - "325 kHz", - "406 kHz", - "464 kHz", - "541 kHz", - "650 kHz", - "812 kHz", -}; - -// Bandwidths values are ordered from F (58kHz) to 0 (812kHz) -#define BANDWIDTH_INDEX(value) ((uint8_t)15 - ((uint8_t)(value >> 4) & 0x0F)) - -#define MANCHESTER_FLAG_COUNT 2 -const char* const manchester_flag_text[MANCHESTER_FLAG_COUNT] = { - "OFF", - "ON", -}; - #define HOPPING_COUNT 2 const char* const hopping_text[HOPPING_COUNT] = { "OFF", @@ -84,40 +50,6 @@ const uint32_t hopping_value[HOPPING_COUNT] = { SubGhzHopperStateRunnig, }; -#define DETECT_RAW_COUNT 2 -const char* const detect_raw_text[DETECT_RAW_COUNT] = { - "OFF", - "ON", -}; - -#ifndef SUBGHZ_SAVE_DETECT_RAW_SETTING -const SubGhzProtocolFlag detect_raw_value[DETECT_RAW_COUNT] = { - SubGhzProtocolFlag_Decodable, - SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_RAW, -}; -#endif - -#define RSSI_THRESHOLD_COUNT 7 -const char* const rssi_threshold_text[RSSI_THRESHOLD_COUNT] = { - "-72db", - "-67db", - "-62db", - "-57db", - "-52db", - "-47db", - "-42db", -}; - -const int rssi_threshold_value[RSSI_THRESHOLD_COUNT] = { - -72, - -67, - -62, - -57, - -52, - -47, - -42, -}; - #define SPEAKER_COUNT 2 const char* const speaker_text[SPEAKER_COUNT] = { "OFF", @@ -127,18 +59,15 @@ const uint32_t speaker_value[SPEAKER_COUNT] = { SubGhzSpeakerStateShutdown, SubGhzSpeakerStateEnable, }; - -// Allow advanced edit only on specific preset -bool subghz_scene_receiver_config_can_edit_current_preset(SubGhz* subghz) { - SubGhzRadioPreset* preset = subghz->txrx->preset; - - bool preset_name_allow_edit = - !strcmp(furi_string_get_cstr(preset->name), ADVANCED_AM_PRESET_NAME) || - !strcmp(furi_string_get_cstr(preset->name), "CUSTOM"); - - return preset && preset_name_allow_edit && - subghz_preset_custom_is_ook_modulation(preset->data, preset->data_size); -} +#define BIN_RAW_COUNT 2 +const char* const bin_raw_text[BIN_RAW_COUNT] = { + "OFF", + "ON", +}; +const uint32_t bin_raw_value[BIN_RAW_COUNT] = { + SubGhzProtocolFlag_Decodable, + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_BinRAW, +}; uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { furi_assert(context); @@ -170,52 +99,6 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* return index; } -// Advanced settings of preset may change if preset was changed. -// In that case - update values -static void subghz_scene_receiver_config_update_advanced(SubGhz* subghz) { - uint8_t value_index; - - if(subghz->variable_item_bandwidth) { - value_index = BANDWIDTH_INDEX(subghz->txrx->raw_bandwidth); - variable_item_set_current_value_index(subghz->variable_item_bandwidth, value_index); - variable_item_set_current_value_text( - subghz->variable_item_bandwidth, bandwidth_labels[value_index]); - } - - if(subghz->variable_item_datarate) { - variable_item_set_current_value_index(subghz->variable_item_datarate, 0); - - char datarate_str[16] = {0}; - subghz_preset_custom_printf_datarate( - subghz->txrx->raw_datarate, datarate_str, sizeof(datarate_str)); - variable_item_set_current_value_text(subghz->variable_item_datarate, datarate_str); - } - - if(subghz->variable_item_manchester) { - value_index = subghz->txrx->raw_manchester_enabled ? 1 : 0; - - variable_item_set_current_value_index(subghz->variable_item_manchester, value_index); - variable_item_set_current_value_text( - subghz->variable_item_manchester, manchester_flag_text[value_index]); - } -} - -// Apply advanced configuration to advanced am preset -static void subghz_scene_receiver_config_apply_advanced(SubGhz* subghz) { - if(subghz_scene_receiver_config_can_edit_current_preset(subghz)) { - SubGhzRadioPreset* preset = subghz->txrx->preset; - - subghz_preset_custom_set_bandwidth( - preset->data, preset->data_size, subghz->txrx->raw_bandwidth); - - subghz_preset_custom_set_machester_enable( - preset->data, preset->data_size, subghz->txrx->raw_manchester_enabled); - - subghz_preset_custom_set_datarate( - preset->data, preset->data_size, subghz->txrx->raw_datarate); - } -} - uint8_t subghz_scene_receiver_config_hopper_value_index( const uint32_t value, const uint32_t values[], @@ -236,36 +119,6 @@ uint8_t subghz_scene_receiver_config_hopper_value_index( } } -#ifndef SUBGHZ_SAVE_DETECT_RAW_SETTING -uint8_t subghz_scene_receiver_config_detect_raw_value_index( - const SubGhzProtocolFlag value, - const SubGhzProtocolFlag values[], - uint8_t values_count) { - uint8_t index = 0; - for(uint8_t i = 0; i < values_count; i++) { - if(value == values[i]) { - index = i; - break; - } - } - return index; -} -#endif - -uint8_t subghz_scene_receiver_config_rssi_threshold_value_index( - const int value, - const int values[], - uint8_t values_count) { - uint8_t index = 0; - for(uint8_t i = 0; i < values_count; i++) { - if(value == values[i]) { - index = i; - break; - } - } - return index; -} - static void subghz_scene_receiver_config_set_frequency(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -301,49 +154,12 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) { subghz->txrx->preset->frequency, subghz_setting_get_preset_data(subghz->setting, index), subghz_setting_get_preset_data_size(subghz->setting, index)); - - subghz_scene_receiver_config_update_advanced(subghz); -} - -static void subghz_scene_receiver_config_set_rssi_threshold(VariableItem* item) { - SubGhz* subghz = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - variable_item_set_current_value_text(item, rssi_threshold_text[index]); - subghz_protocol_decoder_raw_set_rssi_threshold( - subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME), - rssi_threshold_value[index]); -} - -static void subghz_scene_receiver_config_set_detect_raw(VariableItem* item) { - SubGhz* subghz = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - //if(subghz->txrx->hopper_state == 0) { - variable_item_set_current_value_text(item, detect_raw_text[index]); -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - subghz->last_settings->detect_raw = index; - - subghz_last_settings_set_detect_raw_values(subghz); -#else - subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]); - - subghz_protocol_decoder_raw_set_auto_mode( - subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME), - (index == 1)); -#endif - /*} else { - variable_item_set_current_value_index(item, 0); - }*/ } static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - //if(subghz_receiver_get_filter(subghz->txrx->receiver) == SubGhzProtocolFlag_Decodable) { variable_item_set_current_value_text(item, hopping_text[index]); if(hopping_value[index] == SubGhzHopperStateOFF) { char text_buf[10] = {0}; @@ -374,10 +190,6 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) } subghz->txrx->hopper_state = hopping_value[index]; - subghz_history_set_hopper_state(subghz->txrx->history, (index == 1)); - /*} else { - variable_item_set_current_value_index(item, 0); - }*/ } static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { @@ -388,6 +200,15 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { subghz->txrx->speaker_state = speaker_value[index]; } +static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, bin_raw_text[index]); + subghz->txrx->filter = bin_raw_value[index]; + subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); +} + static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -396,107 +217,6 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; } -static void subghz_scene_receiver_config_set_raw_ook_bandwidth(VariableItem* item) { - SubGhz* subghz = variable_item_get_context(item); - if(subghz_scene_receiver_config_can_edit_current_preset(subghz)) { - // update bandwidth value from selected index - uint8_t index = variable_item_get_current_value_index(item); - subghz->txrx->raw_bandwidth = subghz_preset_custom_bandwidth_values[index]; - - subghz_scene_receiver_config_update_advanced(subghz); - } else { - furi_string_set( - subghz->error_str, "Read-only\nsetting!\nUse '" ADVANCED_AM_PRESET_NAME "'\npreset."); - view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubGhzCustomEventSceneSettingError); - } -} - -static void subghz_scene_receiver_config_set_manchester_flag(VariableItem* item) { - SubGhz* subghz = variable_item_get_context(item); - if(subghz_scene_receiver_config_can_edit_current_preset(subghz)) { - // update enable flag from view - uint8_t index = variable_item_get_current_value_index(item); - subghz->txrx->raw_manchester_enabled = index == 0 ? false : true; - - subghz_scene_receiver_config_update_advanced(subghz); - } else { - furi_string_set( - subghz->error_str, "Read-only\nsetting!\nUse '" ADVANCED_AM_PRESET_NAME "'\npreset."); - view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubGhzCustomEventSceneSettingError); - } -} - -static void subghz_scene_receiver_config_datarate_input_callback(void* context) { - furi_assert(context); - SubGhz* subghz = context; - - float value = atoff(subghz->datarate_input_str); - if(value != 0 && value > 0) { - subghz->txrx->raw_datarate = value; - subghz_scene_receiver_config_update_advanced(subghz); - } - - // show list view - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); -} - -static bool subghz_scene_receiver_config_datarate_input_validate( - const char* text, - FuriString* error, - void* context) { - UNUSED(context); - - float value = atoff(text); - if(value == 0) { - furi_string_printf(error, "Cannot parse\r\nvalue"); - } else if(value < 0) { - furi_string_printf(error, "Value\r\nshould be\r\ngreater\r\nthan 0"); - } else { - return true; - } - - return false; -} - -static void subghz_scene_receiver_config_show_datarate_input(SubGhz* subghz) { - TextInput* text_input = subghz->text_input; - - snprintf( - subghz->datarate_input_str, - sizeof(subghz->datarate_input_str), - "%.2f", - (double)subghz->txrx->raw_datarate); - - text_input_set_header_text(text_input, "Datarate bauds (not kBauds)"); - text_input_set_result_callback( - text_input, - subghz_scene_receiver_config_datarate_input_callback, - subghz, - subghz->datarate_input_str, - sizeof(subghz->datarate_input_str), - false); - - text_input_set_validator( - text_input, subghz_scene_receiver_config_datarate_input_validate, NULL); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTextInput); -} - -static void subghz_scene_receiver_config_set_datarate(VariableItem* item) { - SubGhz* subghz = variable_item_get_context(item); - if(subghz_scene_receiver_config_can_edit_current_preset(subghz)) { - // reset value index in order to show '>' symbol always - variable_item_set_current_value_index(item, 0); - subghz_scene_receiver_config_show_datarate_input(subghz); - } else { - furi_string_set( - subghz->error_str, "Read-only\nsetting!\nUse '" ADVANCED_AM_PRESET_NAME "'\npreset."); - view_dispatcher_send_custom_event( - subghz->view_dispatcher, SubGhzCustomEventSceneSettingError); - } -} - static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { furi_assert(context); SubGhz* subghz = context; @@ -511,13 +231,6 @@ void subghz_scene_receiver_config_on_enter(void* context) { VariableItem* item; uint8_t value_index; -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "Last frequency: %ld, Preset: %ld", - subghz->last_settings->frequency, - subghz->last_settings->preset); -#endif item = variable_item_list_add( subghz->variable_item_list, "Frequency:", @@ -563,52 +276,35 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, hopping_text[value_index]); + } - // Detect Raw + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != + SubGhzCustomEventManagerSet) { item = variable_item_list_add( subghz->variable_item_list, - "Detect Raw:", - DETECT_RAW_COUNT, - subghz_scene_receiver_config_set_detect_raw, + "Bin RAW:", + BIN_RAW_COUNT, + subghz_scene_receiver_config_set_bin_raw, subghz); -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - value_index = subghz->last_settings->detect_raw; -#else - value_index = subghz_scene_receiver_config_detect_raw_value_index( - subghz_receiver_get_filter(subghz->txrx->receiver), - detect_raw_value, - DETECT_RAW_COUNT); -#endif + value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, detect_raw_text[value_index]); + variable_item_set_current_value_text(item, bin_raw_text[value_index]); + } - // RSSI - item = variable_item_list_add( - subghz->variable_item_list, - "RSSI for Raw:", - RSSI_THRESHOLD_COUNT, - subghz_scene_receiver_config_set_rssi_threshold, - subghz); - value_index = subghz_scene_receiver_config_rssi_threshold_value_index( - subghz_protocol_encoder_get_rssi_threshold(subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME)), - rssi_threshold_value, - RSSI_THRESHOLD_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, rssi_threshold_text[value_index]); + // Enable speaker, will send all incoming noises and signals to speaker so you can listen how your remote sounds like :) + item = variable_item_list_add( + subghz->variable_item_list, + "Sound:", + SPEAKER_COUNT, + subghz_scene_receiver_config_set_speaker, + subghz); + value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, speaker_text[value_index]); + if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != + SubGhzCustomEventManagerSet) { // Lock keyboard - item = variable_item_list_add( - subghz->variable_item_list, - "Sound:", - SPEAKER_COUNT, - subghz_scene_receiver_config_set_speaker, - subghz); - value_index = - value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, speaker_text[value_index]); - variable_item_list_add(subghz->variable_item_list, "Lock Keyboard", 1, NULL, NULL); variable_item_list_set_enter_callback( subghz->variable_item_list, @@ -627,33 +323,6 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); - - // Advanced MODEM settings. RW only for ADVANCED_AM_PRESET_NAME - // Bandwidth - subghz->variable_item_bandwidth = variable_item_list_add( - subghz->variable_item_list, - "Bandwidth:", - BANDWIDTH_COUNT, - subghz_scene_receiver_config_set_raw_ook_bandwidth, - subghz); - - // Data rate (editable via OK click) - subghz->variable_item_datarate = variable_item_list_add( - subghz->variable_item_list, - "Data rate:", - 2, - subghz_scene_receiver_config_set_datarate, - subghz); - - // Manchester codec flag - subghz->variable_item_manchester = variable_item_list_add( - subghz->variable_item_list, - "Manch. Enc.:", - MANCHESTER_FLAG_COUNT, - subghz_scene_receiver_config_set_manchester_flag, - subghz); - - subghz_scene_receiver_config_update_advanced(subghz); } view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); } @@ -667,11 +336,6 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even subghz->lock = SubGhzLockOn; scene_manager_previous_scene(subghz->scene_manager); consumed = true; - } else if(event.event == SubGhzCustomEventSceneSettingError) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneShowErrorSub, event.event); - consumed = true; } } return consumed; @@ -679,16 +343,6 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even void subghz_scene_receiver_config_on_exit(void* context) { SubGhz* subghz = context; - - // reset UI variable list items (next scene may be not RAW config) - subghz->variable_item_bandwidth = NULL; - subghz->variable_item_datarate = NULL; - subghz->variable_item_manchester = NULL; - text_input_set_validator(subghz->text_input, NULL, NULL); - - // apply advanced preset variables (if applicable) - subghz_scene_receiver_config_apply_advanced(subghz); - variable_item_list_set_selected_item(subghz->variable_item_list, 0); variable_item_list_reset(subghz->variable_item_list); subghz_last_settings_save(subghz->last_settings); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index e9c849e1e..0b265cca2 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -92,8 +92,6 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { // Removed static check if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && - // disable "Send" for auto-captured RAW signals for now. They can still be saved and sent by loading them. - subghz->txrx->decoder_result->protocol->type != SubGhzProtocolTypeRAW && subghz->txrx->decoder_result->protocol->encoder->deserialize) { widget_add_button_element( subghz->widget, @@ -138,6 +136,21 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_history_get_raw_data( subghz->txrx->history, subghz->txrx->idx_menu_chosen))) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); + if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { + subghz_tx_stop(subghz); + } + if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { + subghz_begin( + subghz, + subghz_setting_get_preset_data_by_name( + subghz->setting, + furi_string_get_cstr(subghz->txrx->preset->name))); + subghz_rx(subghz, subghz->txrx->preset->frequency); + } + if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { + subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + } + subghz->state_notifications = SubGhzNotificationStateRx; } else { subghz->state_notifications = SubGhzNotificationStateTx; } diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 2a61d5dc5..609b4a71d 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -1,7 +1,7 @@ #include "../subghz_i.h" #include #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" typedef enum { SubGhzRpcStateIdle, diff --git a/applications/main/subghz/scenes/subghz_scene_save_success.c b/applications/main/subghz/scenes/subghz_scene_save_success.c index bf8ed0185..48804fe54 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_success.c +++ b/applications/main/subghz/scenes/subghz_scene_save_success.c @@ -1,6 +1,6 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void subghz_scene_save_success_popup_callback(void* context) { SubGhz* subghz = context; diff --git a/applications/main/subghz/scenes/subghz_scene_show_error_sub.c b/applications/main/subghz/scenes/subghz_scene_show_error_sub.c index 2943c764a..113e7ae74 100644 --- a/applications/main/subghz/scenes/subghz_scene_show_error_sub.c +++ b/applications/main/subghz/scenes/subghz_scene_show_error_sub.c @@ -26,16 +26,8 @@ bool subghz_scene_show_error_sub_on_event(void* context, SceneManagerEvent event SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneShowErrorSub) { - if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowErrorSub) == - SubGhzCustomEventSceneSettingError) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet); - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneReceiverConfig); - } else { - scene_manager_search_and_switch_to_previous_scene( - subghz->scene_manager, SubGhzSceneStart); - } + scene_manager_search_and_switch_to_previous_scene( + subghz->scene_manager, SubGhzSceneStart); return true; } } diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index 62e30784f..69e6cbea7 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -10,27 +10,9 @@ enum SubmenuIndex { SubmenuIndexAddManually, SubmenuIndexFrequencyAnalyzer, SubmenuIndexReadRAW, + SubmenuIndexExtSettings, }; -void subghz_scene_start_remove_advanced_preset(SubGhz* subghz) { - // delete operation is harmless - subghz_setting_delete_custom_preset(subghz->setting, ADVANCED_AM_PRESET_NAME); -} - -void subghz_scene_start_load_advanced_preset(SubGhz* subghz) { - for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) { - if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), ADVANCED_AM_PRESET_NAME)) { - return; // already exists - } - } - - // Load custom advanced AM preset with configurable CFGMDM settings - FlipperFormat* advanced_am_preset = subghz_preset_custom_advanced_am_preset_alloc(); - subghz_setting_load_custom_preset( - subghz->setting, ADVANCED_AM_PRESET_NAME, advanced_am_preset); - flipper_format_free(advanced_am_preset); -} - void subghz_scene_start_submenu_callback(void* context, uint32_t index) { SubGhz* subghz = context; view_dispatcher_send_custom_event(subghz->view_dispatcher, index); @@ -41,15 +23,6 @@ void subghz_scene_start_on_enter(void* context) { if(subghz->state_notifications == SubGhzNotificationStateStarting) { subghz->state_notifications = SubGhzNotificationStateIDLE; } -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - subghz_last_settings_set_detect_raw_values(subghz); -#else - subghz_protocol_decoder_raw_set_auto_mode( - subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME), - false); - subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); -#endif submenu_add_item( subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz); @@ -73,6 +46,12 @@ void subghz_scene_start_on_enter(void* context) { SubmenuIndexFrequencyAnalyzer, subghz_scene_start_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Radio Settings", + SubmenuIndexExtSettings, + subghz_scene_start_submenu_callback, + subghz); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { submenu_add_item( subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); @@ -91,15 +70,23 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(subghz->view_dispatcher); return true; } else if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexReadRAW) { - subghz_scene_start_load_advanced_preset(subghz); + if(event.event == SubmenuIndexExtSettings) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexExtSettings); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneExtModuleSettings); + return true; + + } else if(!furi_hal_subghz_check_radio()) { + furi_string_set(subghz->error_str, "Please connect\nexternal radio"); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); + return true; + } else if(event.event == SubmenuIndexReadRAW) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); return true; } else if(event.event == SubmenuIndexRead) { - subghz_scene_start_remove_advanced_preset(subghz); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver); @@ -120,7 +107,6 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer); DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); return true; - } else if(event.event == SubmenuIndexTest) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest); diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index c39c35679..78295f08c 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -208,27 +208,38 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { flipper_format_free(temp_fm_preset2); - // # HND - FM presets + // Pagers FlipperFormat* temp_fm_preset3 = flipper_format_string_alloc(); flipper_format_write_string_cstr( temp_fm_preset3, (const char*)"Custom_preset_data", - (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); + (const char*)"02 0D 07 04 08 32 0B 06 10 64 11 93 12 0C 13 02 14 00 15 15 18 18 19 16 1B 07 1C 00 1D 91 20 FB 21 56 22 10 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset3); - subghz_setting_load_custom_preset(subghz->setting, (const char*)"HND_1", temp_fm_preset3); + subghz_setting_load_custom_preset(subghz->setting, (const char*)"Pagers", temp_fm_preset3); flipper_format_free(temp_fm_preset3); + // # HND - FM presets FlipperFormat* temp_fm_preset4 = flipper_format_string_alloc(); flipper_format_write_string_cstr( temp_fm_preset4, (const char*)"Custom_preset_data", - (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); + (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); flipper_format_rewind(temp_fm_preset4); - subghz_setting_load_custom_preset(subghz->setting, (const char*)"HND_2", temp_fm_preset4); + subghz_setting_load_custom_preset(subghz->setting, (const char*)"HND_1", temp_fm_preset4); flipper_format_free(temp_fm_preset4); + FlipperFormat* temp_fm_preset5 = flipper_format_string_alloc(); + flipper_format_write_string_cstr( + temp_fm_preset5, + (const char*)"Custom_preset_data", + (const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"); + flipper_format_rewind(temp_fm_preset5); + subghz_setting_load_custom_preset(subghz->setting, (const char*)"HND_2", temp_fm_preset5); + + flipper_format_free(temp_fm_preset5); + // custom presets loading - end // Load last used values for Read, Read RAW, etc. or default @@ -236,20 +247,11 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->last_settings = subghz_last_settings_alloc(); subghz_last_settings_load(subghz->last_settings, 0); #if FURI_DEBUG -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - FURI_LOG_D( - TAG, - "last frequency: %ld, preset: %ld, detect_raw: %d", - subghz->last_settings->frequency, - subghz->last_settings->preset, - subghz->last_settings->detect_raw); -#else FURI_LOG_D( TAG, "last frequency: %ld, preset: %ld", subghz->last_settings->frequency, subghz->last_settings->preset); -#endif #endif subghz_setting_set_default_frequency(subghz->setting, subghz->last_settings->frequency); } @@ -268,6 +270,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz->txrx->debug_pin_state = false; if(!alloc_for_tx_only) { subghz->txrx->history = subghz_history_alloc(); } @@ -281,16 +284,15 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->environment = subghz_environment_alloc(); subghz_environment_set_came_atomo_rainbow_table_file_name( subghz->txrx->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + subghz->txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n")); subghz_environment_set_nice_flor_s_rainbow_table_file_name( subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s")); subghz_environment_set_protocol_registry( subghz->txrx->environment, (void*)&subghz_protocol_registry); subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment); -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - subghz_last_settings_set_detect_raw_values(subghz); -#else - subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable); -#endif + subghz->txrx->filter = SubGhzProtocolFlag_Decodable; + subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); subghz_worker_set_overrun_callback( subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); @@ -314,6 +316,8 @@ void subghz_free(SubGhz* subghz, bool alloc_for_tx_only) { subghz->rpc_ctx = NULL; } + subghz_speaker_off(subghz); + #if FURI_DEBUG // Packet Test view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index ed1648083..be7143643 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -42,8 +42,9 @@ void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) { furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); frequency = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_write(&gpio_cc1101_g0, true); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, true); furi_hal_power_suppress_charge_enter(); @@ -252,6 +253,8 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); subghz_environment_set_came_atomo_rainbow_table_file_name( environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + environment, EXT_PATH("subghz/assets/alutech_at_4n")); subghz_environment_set_nice_flor_s_rainbow_table_file_name( environment, EXT_PATH("subghz/assets/nice_flor_s")); subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry); @@ -264,7 +267,7 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { furi_hal_subghz_reset(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); frequency = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_power_suppress_charge_enter(); @@ -304,6 +307,81 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { free(instance); } +void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { + UNUSED(context); + uint32_t frequency = 433920000; + + if(furi_string_size(args)) { + int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency); + if(ret != 1) { + printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency); + cli_print_usage("subghz rx", "", furi_string_get_cstr(args)); + return; + } + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + printf( + "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", + frequency); + return; + } + } + + // Allocate context and buffers + SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx)); + instance->stream = + furi_stream_buffer_alloc(sizeof(LevelDuration) * 1024, sizeof(LevelDuration)); + furi_check(instance->stream); + + // Configure radio + furi_hal_subghz_reset(); + furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok270Async); + frequency = furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + + furi_hal_power_suppress_charge_enter(); + + // Prepare and start RX + furi_hal_subghz_start_async_rx(subghz_cli_command_rx_capture_callback, instance); + + // Wait for packets to arrive + printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency); + LevelDuration level_duration; + size_t counter = 0; + while(!cli_cmd_interrupt_received(cli)) { + int ret = furi_stream_buffer_receive( + instance->stream, &level_duration, sizeof(LevelDuration), 10); + if(ret == 0) { + continue; + } + if(ret != sizeof(LevelDuration)) { + puts("stream corrupt"); + break; + } + if(level_duration_is_reset(level_duration)) { + puts(". "); + } else { + bool level = level_duration_get_level(level_duration); + uint32_t duration = level_duration_get_duration(level_duration); + printf("%c%lu ", level ? '+' : '-', duration); + } + furi_thread_stdout_flush(); + counter++; + if(counter > 255) { + puts("\r\n"); + counter = 0; + } + } + + // Shutdown radio + furi_hal_subghz_stop_async_rx(); + furi_hal_subghz_sleep(); + + furi_hal_power_suppress_charge_exit(); + + // Cleanup + furi_stream_buffer_free(instance->stream); + free(instance); +} void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); FuriString* file_name; @@ -372,6 +450,8 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { } subghz_environment_set_came_atomo_rainbow_table_file_name( environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + environment, EXT_PATH("subghz/assets/alutech_at_4n")); subghz_environment_set_nice_flor_s_rainbow_table_file_name( environment, EXT_PATH("subghz/assets/nice_flor_s")); subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry); @@ -387,7 +467,7 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { } printf( - "Listening at %s.\r\n\r\nPress CTRL+C to stop\r\n\r\n", + "Listening at \033[0;33m%s\033[0m.\r\n\r\nPress CTRL+C to stop\r\n\r\n", furi_string_get_cstr(file_name)); LevelDuration level_duration; @@ -426,7 +506,8 @@ static void subghz_cli_command_print_usage() { printf("\tchat \t - Chat with other Flippers\r\n"); printf( "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); - printf("\trx \t - Reception key\r\n"); + printf("\trx \t - Receive\r\n"); + printf("\trx_raw \t - Receive RAW\r\n"); printf("\tdecode_raw \t - Testing\r\n"); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { @@ -578,7 +659,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args, void* context) { NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - furi_string_printf(name, "%s: ", furi_hal_version_get_name_ptr()); + furi_string_printf(name, "\033[0;33m%s\033[0m: ", furi_hal_version_get_name_ptr()); furi_string_set(input, name); printf("%s", furi_string_get_cstr(input)); fflush(stdout); @@ -659,14 +740,18 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args, void* context) { notification_message(notification, &sequence_single_vibro); break; case SubGhzChatEventUserEntrance: - furi_string_printf(sysmsg, "%s joined chat.\r\n", furi_hal_version_get_name_ptr()); + furi_string_printf( + sysmsg, + "\033[0;34m%s joined chat.\033[0m\r\n", + furi_hal_version_get_name_ptr()); subghz_chat_worker_write( subghz_chat, (uint8_t*)furi_string_get_cstr(sysmsg), strlen(furi_string_get_cstr(sysmsg))); break; case SubGhzChatEventUserExit: - furi_string_printf(sysmsg, "%s left chat.\r\n", furi_hal_version_get_name_ptr()); + furi_string_printf( + sysmsg, "\033[0;31m%s left chat.\033[0m\r\n", furi_hal_version_get_name_ptr()); subghz_chat_worker_write( subghz_chat, (uint8_t*)furi_string_get_cstr(sysmsg), @@ -725,6 +810,11 @@ static void subghz_cli_command(Cli* cli, FuriString* args, void* context) { break; } + if(furi_string_cmp_str(cmd, "rx_raw") == 0) { + subghz_cli_command_rx_raw(cli, args, context); + break; + } + if(furi_string_cmp_str(cmd, "decode_raw") == 0) { subghz_cli_command_decode_raw(cli, args, context); break; @@ -763,6 +853,7 @@ void subghz_on_system_start() { Cli* cli = furi_record_open(RECORD_CLI); cli_add_command(cli, "subghz", CliCommandFlagDefault, subghz_cli_command, NULL); + // psst RM... i know you dont care much about errors, but if you ever see this... incompatible pointer type :3 cli_add_command(cli, "chat", CliCommandFlagDefault, subghz_cli_command_chat, NULL); @@ -770,4 +861,4 @@ void subghz_on_system_start() { #else UNUSED(subghz_cli_command); #endif -} \ No newline at end of file +} diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index e8d3acfd7..184146698 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -1,33 +1,15 @@ #include "subghz_history.h" -#include "subghz_history_private.h" #include -#include -#include -#include "flipper_format_stream_i.h" -#include -#define SUBGHZ_HISTORY_MAX 60 - -/** - * @brief Settings for temporary files - * - */ -#define SUBGHZ_HISTORY_TMP_DIR EXT_PATH("subghz/tmp_history") -#define SUBGHZ_HISTORY_TMP_EXTENSION ".tmp" -#define SUBGHZ_HISTORY_TMP_SIGNAL_MAX 700 -#define SUBGHZ_HISTORY_TMP_SIGNAL_MIN 100 -#define SUBGHZ_HISTORY_TMP_REMOVE_FILES true -#define SUBGHZ_HISTORY_TMP_RAW_KEY "RAW_Data" -#define MAX_LINE 500 -const size_t buffer_size = 32; +#include +#define SUBGHZ_HISTORY_MAX 55 +#define SUBGHZ_HISTORY_FREE_HEAP 20480 #define TAG "SubGhzHistory" typedef struct { FuriString* item_str; FlipperFormat* flipper_string; - FuriString* protocol_name; - bool is_file; uint8_t type; SubGhzRadioPreset* preset; } SubGhzHistoryItem; @@ -45,146 +27,30 @@ struct SubGhzHistory { uint16_t last_index_write; uint8_t code_last_hash_data; FuriString* tmp_string; - bool write_tmp_files; - bool is_hopper_running; - Storage* storage; SubGhzHistoryStruct* history; }; -#ifdef FURI_DEBUG -#define LOG_DELAY 0 -#endif - -FuriString* subghz_history_generate_temp_filename(uint32_t index) { - FuriHalRtcDateTime datetime = {0}; - furi_hal_rtc_get_datetime(&datetime); - return furi_string_alloc_printf("%03ld%s", index, SUBGHZ_HISTORY_TMP_EXTENSION); -} - -bool subghz_history_is_tmp_dir_exists(SubGhzHistory* instance) { - FileInfo file_info; - FS_Error error = storage_common_stat(instance->storage, SUBGHZ_HISTORY_TMP_DIR, &file_info); - - if(error == FSE_OK) { - if(file_info.flags & FSF_DIRECTORY) { - return true; - } - } - - return false; -} - -bool subghz_history_check_sdcard(SubGhzHistory* instance) { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "check_sdcard"); - uint32_t start_time = furi_get_tick(); -#endif - - bool result = false; - // Stage 0 - check SD Card - FS_Error status = storage_sd_status(instance->storage); - if(status == FSE_OK) { - result = subghz_history_is_tmp_dir_exists(instance); - if(!subghz_history_is_tmp_dir_exists(instance)) { - result = storage_simply_mkdir(instance->storage, SUBGHZ_HISTORY_TMP_DIR); - } - } else { - FURI_LOG_W(TAG, "SD storage not installed! Status: %d", status); - } -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Running time (check_sdcard): %ld ms", furi_get_tick() - start_time); -#endif - - return result; -} - -void subghz_history_clear_tmp_dir(SubGhzHistory* instance) { - furi_assert(instance); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "clear_tmp_dir"); -#endif - - if(!instance->write_tmp_files) { - // Nothing to do here! - return; - } - //uint32_t start_time = furi_get_tick(); -#ifdef SUBGHZ_HISTORY_TMP_REMOVE_FILES - // Stage 0 - Dir exists? - bool res = subghz_history_is_tmp_dir_exists(instance); - if(res) { - // Stage 1 - delete all content if exists - FileInfo fileinfo; - storage_common_stat(instance->storage, SUBGHZ_HISTORY_TMP_DIR, &fileinfo); - - res = fileinfo.flags & FSF_DIRECTORY ? - storage_simply_remove_recursive(instance->storage, SUBGHZ_HISTORY_TMP_DIR) : - (storage_common_remove(instance->storage, SUBGHZ_HISTORY_TMP_DIR) == FSE_OK); - } - - // Stage 2 - create dir if necessary - res = storage_simply_mkdir(instance->storage, SUBGHZ_HISTORY_TMP_DIR); - if(!res) { - FURI_LOG_E(TAG, "Cannot process temp dir!"); - } -#endif - /* uint32_t stop_time = furi_get_tick() - start_time; - FURI_LOG_I(TAG, "Running time (clear_tmp_dir): %d ms", stop_time);*/ -} - SubGhzHistory* subghz_history_alloc(void) { SubGhzHistory* instance = malloc(sizeof(SubGhzHistory)); instance->tmp_string = furi_string_alloc(); instance->history = malloc(sizeof(SubGhzHistoryStruct)); SubGhzHistoryItemArray_init(instance->history->data); - instance->storage = furi_record_open(RECORD_STORAGE); - instance->write_tmp_files = subghz_history_check_sdcard(instance); - - instance->is_hopper_running = false; - - if(!instance->write_tmp_files) { - FURI_LOG_E(TAG, "Unstable work! Cannot use SD Card!"); - } - return instance; } -void subghz_history_item_free(void* current_item) { - furi_assert(current_item); - SubGhzHistoryItem* item = (SubGhzHistoryItem*)current_item; - furi_string_free(item->item_str); - furi_string_free(item->preset->name); - furi_string_free(item->protocol_name); - - free(item->preset); - item->type = 0; - item->is_file = false; - - if(item->flipper_string != NULL) { - flipper_format_free(item->flipper_string); - } -} - -void subghz_history_clean_item_array(SubGhzHistory* instance) { - for - M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) { - subghz_history_item_free(item); - } -} - void subghz_history_free(SubGhzHistory* instance) { furi_assert(instance); furi_string_free(instance->tmp_string); - - subghz_history_clean_item_array(instance); + for + M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) { + furi_string_free(item->item_str); + furi_string_free(item->preset->name); + free(item->preset); + flipper_format_free(item->flipper_string); + item->type = 0; + } SubGhzHistoryItemArray_clear(instance->history->data); free(instance->history); - - // Delete all temporary file, on exit it's ok - subghz_history_clear_tmp_dir(instance); - - furi_record_close(RECORD_STORAGE); - free(instance); } @@ -209,20 +75,19 @@ const char* subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) { void subghz_history_reset(SubGhzHistory* instance) { furi_assert(instance); furi_string_reset(instance->tmp_string); - - subghz_history_clean_item_array(instance); - + for + M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) { + furi_string_free(item->item_str); + furi_string_free(item->preset->name); + free(item->preset); + flipper_format_free(item->flipper_string); + item->type = 0; + } SubGhzHistoryItemArray_reset(instance->history->data); instance->last_index_write = 0; instance->code_last_hash_data = 0; } -void subghz_history_set_hopper_state(SubGhzHistory* instance, bool hopper_state) { - furi_assert(instance); - - instance->is_hopper_running = hopper_state; -} - uint16_t subghz_history_get_item(SubGhzHistory* instance) { furi_assert(instance); return instance->last_index_write; @@ -237,8 +102,12 @@ uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx) const char* subghz_history_get_protocol_name(SubGhzHistory* instance, uint16_t idx) { furi_assert(instance); SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); - - return furi_string_get_cstr(item->protocol_name); + flipper_format_rewind(item->flipper_string); + if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) { + FURI_LOG_E(TAG, "Missing Protocol"); + furi_string_reset(instance->tmp_string); + } + return furi_string_get_cstr(instance->tmp_string); } FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx) { @@ -247,72 +116,27 @@ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx if(item->flipper_string) { return item->flipper_string; } else { - bool result_ok = false; - if(instance->write_tmp_files && item->is_file) { - // We have files! - FuriString* filename = subghz_history_generate_temp_filename(idx); - FuriString* dir_path; - - dir_path = furi_string_alloc_printf( - "%s/%s", SUBGHZ_HISTORY_TMP_DIR, furi_string_get_cstr(filename)); - - if(storage_file_exists(instance->storage, furi_string_get_cstr(dir_path))) { -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Exist: %s", furi_string_get_cstr(dir_path)); - furi_delay_ms(LOG_DELAY); -#endif - // Set to current anyway it has NULL value - item->flipper_string = flipper_format_string_alloc(); - Stream* dst_stream = flipper_format_get_raw_stream(item->flipper_string); - stream_clean(dst_stream); - - size_t size = stream_load_from_file( - dst_stream, instance->storage, furi_string_get_cstr(dir_path)); - if(size > 0) { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Save ok!"); - furi_delay_ms(LOG_DELAY); -#endif - // We changed contents of file, so we no needed to load - // content from disk for the next time - item->is_file = false; - result_ok = true; - } else { - FURI_LOG_E(TAG, "Stream copy failed!"); - flipper_format_free(item->flipper_string); - } - } else { - FURI_LOG_E(TAG, "Can't convert filename to file"); - } - - furi_string_free(filename); - furi_string_free(dir_path); - } else { -#ifdef FURI_DEBUG - FURI_LOG_W(TAG, "Write TMP files failed!"); - furi_delay_ms(LOG_DELAY); -#endif - } - return result_ok ? item->flipper_string : NULL; + return NULL; } } - bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) { furi_assert(instance); - if(instance->last_index_write == SUBGHZ_HISTORY_MAX) { - if(output != NULL) furi_string_printf(output, "Memory is FULL"); + if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) { + if(output != NULL) furi_string_printf(output, " Free heap LOW"); return true; } - if(output != NULL) { - furi_string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); + if(instance->last_index_write == SUBGHZ_HISTORY_MAX) { + if(output != NULL) furi_string_printf(output, " Memory is FULL"); + return true; } + if(output != NULL) + furi_string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); return false; } uint16_t subghz_history_get_last_index(SubGhzHistory* instance) { return instance->last_index_write; } - void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* output, uint16_t idx) { SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); furi_string_set(output, item->item_str); @@ -325,9 +149,8 @@ bool subghz_history_add_to_history( furi_assert(instance); furi_assert(context); - if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) { - return false; - } + if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) return false; + if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false; SubGhzProtocolDecoderBase* decoder_base = context; if((instance->code_last_hash_data == @@ -339,6 +162,7 @@ bool subghz_history_add_to_history( instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base); instance->last_update_timestamp = furi_get_tick(); + FuriString* text; text = furi_string_alloc(); SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data); @@ -351,11 +175,6 @@ bool subghz_history_add_to_history( item->preset->data_size = preset->data_size; item->item_str = furi_string_alloc(); - item->protocol_name = furi_string_alloc(); - - bool tmp_file_for_raw = false; - - // At this point file mapped to memory otherwise file cannot decode item->flipper_string = flipper_format_string_alloc(); subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_string, preset); @@ -367,30 +186,8 @@ bool subghz_history_add_to_history( if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) { FURI_LOG_E(TAG, "Missing Protocol"); break; - } else { - furi_string_printf( - item->protocol_name, "%s", furi_string_get_cstr(instance->tmp_string)); } - if(!strcmp(furi_string_get_cstr(instance->tmp_string), "RAW")) { - // Check if hopper enabled we need to add little delay - if(instance->is_hopper_running) { - furi_delay_ms(40); - } - // Enable writing temp files to micro sd - tmp_file_for_raw = true; - // Write display name - furi_string_printf( - item->item_str, - "RAW %03ld.%02ld", - preset->frequency / 1000000 % 1000, - preset->frequency / 10000 % 100); - // Rewind - if(!flipper_format_rewind(item->flipper_string)) { - FURI_LOG_E(TAG, "Rewind error"); - } - - break; - } else if(!strcmp(furi_string_get_cstr(instance->tmp_string), "KeeLoq")) { + if(!strcmp(furi_string_get_cstr(instance->tmp_string), "KeeLoq")) { furi_string_set(instance->tmp_string, "KL "); if(!flipper_format_read_string(item->flipper_string, "Manufacture", text)) { FURI_LOG_E(TAG, "Missing Protocol"); @@ -411,484 +208,34 @@ bool subghz_history_add_to_history( } uint8_t key_data[sizeof(uint64_t)] = {0}; if(!flipper_format_read_hex(item->flipper_string, "Key", key_data, sizeof(uint64_t))) { - FURI_LOG_E(TAG, "Missing Key"); - break; + FURI_LOG_D(TAG, "No Key"); } uint64_t data = 0; for(uint8_t i = 0; i < sizeof(uint64_t); i++) { data = (data << 8) | key_data[i]; } - if(!(uint32_t)(data >> 32)) { - furi_string_printf( - item->item_str, - "%s %lX", - furi_string_get_cstr(instance->tmp_string), - (uint32_t)(data & 0xFFFFFFFF)); + if(data != 0) { + if(!(uint32_t)(data >> 32)) { + furi_string_printf( + item->item_str, + "%s %lX", + furi_string_get_cstr(instance->tmp_string), + (uint32_t)(data & 0xFFFFFFFF)); + } else { + furi_string_printf( + item->item_str, + "%s %lX%08lX", + furi_string_get_cstr(instance->tmp_string), + (uint32_t)(data >> 32), + (uint32_t)(data & 0xFFFFFFFF)); + } } else { - furi_string_printf( - item->item_str, - "%s %lX%08lX", - furi_string_get_cstr(instance->tmp_string), - (uint32_t)(data >> 32), - (uint32_t)(data & 0xFFFFFFFF)); + furi_string_printf(item->item_str, "%s", furi_string_get_cstr(instance->tmp_string)); } + } while(false); - // If we can write to files - if(instance->write_tmp_files && tmp_file_for_raw) { - FuriString* filename = subghz_history_generate_temp_filename(instance->last_index_write); - FuriString* dir_path; - dir_path = furi_string_alloc(); - - furi_string_cat_printf( - dir_path, "%s/%s", SUBGHZ_HISTORY_TMP_DIR, furi_string_get_cstr(filename)); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Save temp file: %s", furi_string_get_cstr(dir_path)); -#endif - if(!subghz_history_tmp_write_file_split(instance, item, furi_string_get_cstr(dir_path))) { - // Plan B! - subghz_history_tmp_write_file_full(instance, item, dir_path); - } - if(item->is_file) { - flipper_format_free(item->flipper_string); - item->flipper_string = NULL; - } - furi_string_free(filename); - furi_string_free(dir_path); - - } else { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Old fashion way"); -#endif - } - furi_string_free(text); - instance->last_index_write++; return true; } - -static inline bool is_space_playground(char c) { - return c == ' ' || c == '\t' || c == flipper_format_eolr; -} - -bool subghz_history_stream_read_valid_key(Stream* stream, FuriString* key) { - furi_string_reset(key); - uint8_t buffer[buffer_size]; - - bool found = false; - bool error = false; - bool accumulate = true; - bool new_line = true; - - while(true) { - size_t was_read = stream_read(stream, buffer, buffer_size); - if(was_read == 0) break; - - for(size_t i = 0; i < was_read; i++) { - uint8_t data = buffer[i]; - if(data == flipper_format_eoln) { - // EOL found, clean data, start accumulating data and set the new_line flag - furi_string_reset(key); - accumulate = true; - new_line = true; - } else if(data == flipper_format_eolr) { - // ignore - } else if(data == flipper_format_comment && new_line) { - // if there is a comment character and we are at the beginning of a new line - // do not accumulate comment data and reset the new_line flag - accumulate = false; - new_line = false; - } else if(data == flipper_format_delimiter) { - if(new_line) { - // we are on a "new line" and found the delimiter - // this can only be if we have previously found some kind of key, so - // clear the data, set the flag that we no longer want to accumulate data - // and reset the new_line flag - furi_string_reset(key); - accumulate = false; - new_line = false; - } else { - // parse the delimiter only if we are accumulating data - if(accumulate) { - // we found the delimiter, move the rw pointer to the delimiter location - // and signal that we have found something - if(!stream_seek(stream, i - was_read, StreamOffsetFromCurrent)) { - error = true; - break; - } - - found = true; - break; - } - } - } else { - // just new symbol, reset the new_line flag - new_line = false; - if(accumulate) { - // and accumulate data if we want - furi_string_push_back(key, data); - } - } - } - - if(found || error) break; - } - - return found; -} - -bool subghz_history_stream_seek_to_key(Stream* stream, const char* key, bool strict_mode) { - bool found = false; - FuriString* read_key; - - read_key = furi_string_alloc(); - - while(!stream_eof(stream)) { - if(subghz_history_stream_read_valid_key(stream, read_key)) { - if(furi_string_cmp_str(read_key, key) == 0) { - if(!stream_seek(stream, 2, StreamOffsetFromCurrent)) { - break; - } - found = true; - break; - } else if(strict_mode) { - found = false; - break; - } - } - } - furi_string_free(read_key); - - return found; -} - -bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last) { - enum { LeadingSpace, ReadValue, TrailingSpace } state = LeadingSpace; - const size_t buffer_size = 32; - uint8_t buffer[buffer_size]; - bool result = false; - bool error = false; - - furi_string_reset(value); - - while(true) { - size_t was_read = stream_read(stream, buffer, buffer_size); - - if(was_read == 0) { - if(state != LeadingSpace && stream_eof(stream)) { - result = true; - *last = true; - } else { - error = true; - } - } - - for(uint16_t i = 0; i < was_read; i++) { - const uint8_t data = buffer[i]; - - if(state == LeadingSpace) { - if(is_space_playground(data)) { - continue; - } else if(data == flipper_format_eoln) { - stream_seek(stream, i - was_read, StreamOffsetFromCurrent); - error = true; - break; - } else { - state = ReadValue; - furi_string_push_back(value, data); - } - } else if(state == ReadValue) { - if(is_space_playground(data)) { - state = TrailingSpace; - } else if(data == flipper_format_eoln) { - if(!stream_seek(stream, i - was_read, StreamOffsetFromCurrent)) { - error = true; - } else { - result = true; - *last = true; - } - break; - } else { - furi_string_push_back(value, data); - } - } else if(state == TrailingSpace) { - if(is_space_playground(data)) { - continue; - } else if(!stream_seek(stream, i - was_read, StreamOffsetFromCurrent)) { - error = true; - } else { - *last = (data == flipper_format_eoln); - result = true; - } - break; - } - } - - if(error || result) break; - } - - return result; -} - -bool subghz_history_read_int32(Stream* stream, int32_t* _data, const uint16_t data_size) { - bool result = false; - result = true; - FuriString* value; - value = furi_string_alloc(); - - for(size_t i = 0; i < data_size; i++) { - bool last = false; - result = subghz_history_stream_read_value(stream, value, &last); - if(result) { - int scan_values = 0; - - int32_t* data = _data; - scan_values = sscanf(furi_string_get_cstr(value), "%" PRIi32, &data[i]); - - if(scan_values != 1) { - result = false; - break; - } - } else { - break; - } - - if(last && ((i + 1) != data_size)) { - result = false; - break; - } - } - - furi_string_free(value); - return result; -} - -uint32_t subghz_history_rand_range(uint32_t min, uint32_t max) { - // size of range, inclusive - const uint32_t length_of_range = max - min + 1; - - // add n so that we don't return a number below our range - return (uint32_t)(rand() % length_of_range + min); -} - -bool subghz_history_write_file_noise( - Stream* file, - bool is_negative_start, - size_t current_position, - bool empty_line) { - size_t was_write = 0; - if(empty_line) { - was_write = stream_write_format(file, "%s: ", SUBGHZ_HISTORY_TMP_RAW_KEY); - - if(was_write <= 0) { - FURI_LOG_E(TAG, "Can't write key!"); - return false; - } - } - - int8_t first; - int8_t second; - if(is_negative_start) { - first = -1; - second = 1; - } else { - first = 1; - second = -1; - } - while(current_position < MAX_LINE) { - was_write = stream_write_format( - file, - "%ld %ld ", - subghz_history_rand_range( - SUBGHZ_HISTORY_TMP_SIGNAL_MIN, SUBGHZ_HISTORY_TMP_SIGNAL_MAX) * - first, - subghz_history_rand_range( - SUBGHZ_HISTORY_TMP_SIGNAL_MIN, SUBGHZ_HISTORY_TMP_SIGNAL_MAX) * - second); - - if(was_write <= 0) { - FURI_LOG_E(TAG, "Can't write random values!"); - return false; - } - - current_position += was_write; - } - - // Step back to write \n instead of space - size_t offset = stream_tell(file); - if(stream_seek(file, offset - 1, StreamOffsetFromCurrent)) { - FURI_LOG_E(TAG, "Step back failed!"); - return false; - } - - return stream_write_char(file, flipper_format_eoln) > 0; -} - -bool subghz_history_write_file_data( - Stream* src, - Stream* file, - bool* is_negative_start, - size_t* current_position) { - size_t offset_file = 0; - bool result = false; - int32_t value = 0; - - do { - if(!subghz_history_read_int32(src, &value, 1)) { - result = true; - break; - } - offset_file = stream_tell(file); - stream_write_format(file, "%ld ", value); - *current_position += stream_tell(file) - offset_file; - - if(*current_position > MAX_LINE) { - if((is_negative_start && value > 0) || (!is_negative_start && value < 0)) { - // Align values - continue; - } - - if(stream_write_format(file, "\n%s: ", SUBGHZ_HISTORY_TMP_RAW_KEY) == 0) { - FURI_LOG_E(TAG, "Can't write new line!"); - result = false; - break; - } - *current_position = 0; - } - } while(true); - - *is_negative_start = value < 0; - - return result; -} - -bool subghz_history_tmp_write_file_split( - SubGhzHistory* instance, - void* current_item, - const char* dir_path) { - furi_assert(instance); - furi_assert(current_item); - furi_assert(dir_path); -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Save temp file splitted: %s", dir_path); -#endif - SubGhzHistoryItem* item = (SubGhzHistoryItem*)current_item; - - uint8_t buffer[buffer_size]; - Stream* src = flipper_format_get_raw_stream(item->flipper_string); - stream_rewind(src); - - FlipperFormat* flipper_format_file = flipper_format_file_alloc(instance->storage); - bool result = false; - FuriString* temp_str = furi_string_alloc(); - - do { - if(storage_file_exists(instance->storage, dir_path) && - storage_common_remove(instance->storage, dir_path) != FSE_OK) { - FURI_LOG_E(TAG, "Can't delete old file!"); - break; - } - path_extract_dirname(dir_path, temp_str); - FS_Error fs_result = - storage_common_mkdir(instance->storage, furi_string_get_cstr(temp_str)); - if(fs_result != FSE_OK && fs_result != FSE_EXIST) { - FURI_LOG_E(TAG, "Can't create dir!"); - break; - } - result = flipper_format_file_open_always(flipper_format_file, dir_path); - if(!result) { - FURI_LOG_E(TAG, "Can't open file for write!"); - break; - } - Stream* file = flipper_format_get_raw_stream(flipper_format_file); - - if(!subghz_history_stream_seek_to_key(src, SUBGHZ_HISTORY_TMP_RAW_KEY, false)) { - FURI_LOG_E(TAG, "Can't find key!"); - break; - } - bool is_negative_start = false; - bool found = false; - - size_t offset_start; - offset_start = stream_tell(src); - - // Check for negative value at the start and end to align file by correct values - size_t was_read = stream_read(src, buffer, 1); - if(was_read <= 0) { - FURI_LOG_E(TAG, "Can't obtain first mark!"); - break; - } - - is_negative_start = buffer[0] == '-'; - - // Ready to write stream to file - size_t current_position; - stream_rewind(src); - current_position = stream_copy(src, file, offset_start); - if(current_position != offset_start) { - FURI_LOG_E(TAG, "Invalid copy header data from one stream to another!"); - break; - } - - found = true; - - current_position = 0; - if(!subghz_history_write_file_noise(file, is_negative_start, current_position, false)) { - FURI_LOG_E(TAG, "Add start noise failed!"); - break; - } - - if(stream_write_format(file, "%s: ", SUBGHZ_HISTORY_TMP_RAW_KEY) == 0) { - FURI_LOG_E(TAG, "Can't write new line!"); - result = false; - break; - } - - if(!subghz_history_write_file_data(src, file, &is_negative_start, ¤t_position)) { - FURI_LOG_E(TAG, "Split by lines failed!"); - break; - } - - if(!subghz_history_write_file_noise(file, is_negative_start, current_position, false)) { - FURI_LOG_E(TAG, "Add end noise failed!"); - break; - } - - if(!subghz_history_write_file_noise(file, is_negative_start, 0, true)) { - FURI_LOG_E(TAG, "Add end noise failed!"); - break; - } - - result = found; - } while(false); - flipper_format_file_close(flipper_format_file); - flipper_format_free(flipper_format_file); - furi_string_free(temp_str); - - item->is_file = result; - - return result; -} - -void subghz_history_tmp_write_file_full( - SubGhzHistory* instance, - void* current_item, - FuriString* dir_path) { - SubGhzHistoryItem* item = (SubGhzHistoryItem*)current_item; -#ifdef FURI_DEBUG - FURI_LOG_W(TAG, "Save temp file full: %s", furi_string_get_cstr(dir_path)); -#endif - Stream* dst = flipper_format_get_raw_stream(item->flipper_string); - stream_rewind(dst); - if(stream_save_to_file( - dst, instance->storage, furi_string_get_cstr(dir_path), FSOM_CREATE_ALWAYS) > 0) { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Save done!"); -#endif - // This item contains fake data to load from SD - item->is_file = true; - } else { - FURI_LOG_E(TAG, "Stream copy failed!"); - } -} \ No newline at end of file diff --git a/applications/main/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h index ee1ee1a4d..607dbeae2 100644 --- a/applications/main/subghz/subghz_history.h +++ b/applications/main/subghz/subghz_history.h @@ -110,10 +110,3 @@ bool subghz_history_add_to_history( * @return SubGhzProtocolCommonLoad* */ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); - -/** Set hopper state for internal usage in history - * - * @param instance - SubGhzHistory instance - * @param hopper_state - bool is hopper running? - */ -void subghz_history_set_hopper_state(SubGhzHistory* instance, bool hopper_state); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index bac25759a..1fbe662ed 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -30,12 +30,6 @@ void subghz_preset_init( subghz->txrx->preset->frequency = frequency; subghz->txrx->preset->data = preset_data; subghz->txrx->preset->data_size = preset_data_size; - - subghz->txrx->raw_bandwidth = - subghz_preset_custom_get_bandwidth(preset_data, preset_data_size); - subghz->txrx->raw_manchester_enabled = - subghz_preset_custom_get_machester_enable(preset_data, preset_data_size); - subghz->txrx->raw_datarate = subghz_preset_custom_get_datarate(preset_data, preset_data_size); } bool subghz_set_preset(SubGhz* subghz, const char* preset) { @@ -75,7 +69,7 @@ void subghz_begin(SubGhz* subghz, uint8_t* preset_data) { furi_hal_subghz_reset(); furi_hal_subghz_idle(); furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; } @@ -90,7 +84,7 @@ uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) { furi_hal_subghz_idle(); uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_flush_rx(); subghz_speaker_on(subghz); furi_hal_subghz_rx(); @@ -109,8 +103,9 @@ static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep); furi_hal_subghz_idle(); furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_write(&gpio_cc1101_g0, false); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); subghz_speaker_on(subghz); bool ret = furi_hal_subghz_tx(); subghz->txrx->txrx_state = SubGhzTxRxStateTx; @@ -602,9 +597,15 @@ void subghz_hopper_update(SubGhz* subghz) { } void subghz_speaker_on(SubGhz* subghz) { + if(subghz->txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_ext_pa7); + } + if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_acquire(30)) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + if(!subghz->txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } } else { subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; } @@ -612,9 +613,14 @@ void subghz_speaker_on(SubGhz* subghz) { } void subghz_speaker_off(SubGhz* subghz) { + if(subghz->txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); + if(!subghz->txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } furi_hal_speaker_release(); if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown) subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; @@ -623,17 +629,27 @@ void subghz_speaker_off(SubGhz* subghz) { } void subghz_speaker_mute(SubGhz* subghz) { + if(subghz->txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); + if(!subghz->txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } } } } void subghz_speaker_unmute(SubGhz* subghz) { + if(subghz->txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_ext_pa7); + } if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + if(!subghz->txrx->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } } } } diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index a6c96cb69..393dd667d 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -3,7 +3,6 @@ #include "helpers/subghz_types.h" #include "helpers/subghz_error_type.h" #include -#include #include "subghz.h" #include "views/receiver.h" #include "views/transmitter.h" @@ -63,6 +62,7 @@ struct SubGhzTxRx { SubGhzEnvironment* environment; SubGhzReceiver* receiver; SubGhzTransmitter* transmitter; + SubGhzProtocolFlag filter; SubGhzProtocolDecoderBase* decoder_result; FlipperFormat* fff_data; SecureData* secure_data; @@ -77,15 +77,10 @@ struct SubGhzTxRx { uint8_t hopper_idx_frequency; SubGhzRxKeyState rx_key_state; + bool debug_pin_state; + float raw_threshold_rssi; uint8_t raw_threshold_rssi_low_count; - - // one of the 16 possible bandwidth values - uint8_t raw_bandwidth; - // datarate in bauds - float raw_datarate; - // flag if manchester encoding/decoding enabled - bool raw_manchester_enabled; }; typedef struct SubGhzTxRx SubGhzTxRx; @@ -114,13 +109,6 @@ struct SubGhz { SubGhzViewTransmitter* subghz_transmitter; VariableItemList* variable_item_list; - // Advanced config items - VariableItem* variable_item_bandwidth; // specific config list view item: bandwidth - VariableItem* variable_item_datarate; // specific config list view item: data rate - VariableItem* variable_item_manchester; // specific config list view item: manchester enc flag - // Advanced config strings - char datarate_input_str[16]; - SubGhzFrequencyAnalyzer* subghz_frequency_analyzer; SubGhzReadRAW* subghz_read_raw; bool raw_send_only; diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index 478e32347..8e7016df7 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -1,8 +1,5 @@ #include "subghz_last_settings.h" #include "subghz_i.h" -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING -#include -#endif #define TAG "SubGhzLastSettings" @@ -16,11 +13,6 @@ #define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL 2 #define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER -93.0f -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING -#define SUBGHZ_LAST_SETTING_DEFAULT_READ_RAW 0 -#define SUBGHZ_LAST_SETTING_FIELD_DETECT_RAW "DetectRaw" -#endif - #define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY "Frequency" //#define SUBGHZ_LAST_SETTING_FIELD_PRESET "Preset" #define SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_FEEDBACK_LEVEL "FeedbackLevel" @@ -52,9 +44,6 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count //int32_t temp_preset = 0; bool frequency_analyzer_feedback_level_was_read = false; bool frequency_analyzer_trigger_was_read = false; -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - uint32_t temp_read_raw = 0; -#endif if(FSE_OK == storage_sd_status(storage) && SUBGHZ_LAST_SETTINGS_PATH && flipper_format_file_open_existing(fff_data_file, SUBGHZ_LAST_SETTINGS_PATH)) { @@ -73,10 +62,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count SUBGHZ_LAST_SETTING_FIELD_FREQUENCY_ANALYZER_TRIGGER, (float*)&temp_frequency_analyzer_trigger, 1); -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - flipper_format_read_uint32( - fff_data_file, SUBGHZ_LAST_SETTING_FIELD_DETECT_RAW, (uint32_t*)&temp_read_raw, 1); -#endif + } else { FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH); } @@ -88,9 +74,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->frequency_analyzer_feedback_level = SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL; instance->frequency_analyzer_trigger = SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER; -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - instance->detect_raw = SUBGHZ_LAST_SETTING_DEFAULT_READ_RAW; -#endif + } else { instance->frequency = temp_frequency; instance->frequency_analyzer_feedback_level = @@ -101,9 +85,6 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->frequency_analyzer_trigger = frequency_analyzer_trigger_was_read ? temp_frequency_analyzer_trigger : SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_TRIGGER; -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - instance->detect_raw = temp_read_raw; -#endif /*if(temp_preset > (int32_t)preset_count - 1 || temp_preset < 0) { FURI_LOG_W(TAG, "Last used preset no found");*/ @@ -164,12 +145,6 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) { 1)) { break; } -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - if(!flipper_format_insert_or_update_uint32( - file, SUBGHZ_LAST_SETTING_FIELD_DETECT_RAW, &instance->detect_raw, 1)) { - break; - } -#endif saved = true; } while(0); @@ -183,17 +158,3 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) { return saved; } - -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING -void subghz_last_settings_set_detect_raw_values(void* context) { - furi_assert(context); - SubGhz* instance = (SubGhz*)context; - bool is_detect_raw = instance->last_settings->detect_raw > 0; - subghz_receiver_set_filter( - instance->txrx->receiver, is_detect_raw ? DETECT_RAW_TRUE : DETECT_RAW_FALSE); - subghz_protocol_decoder_raw_set_auto_mode( - subghz_receiver_search_decoder_base_by_name( - instance->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME), - is_detect_raw); -} -#endif \ No newline at end of file diff --git a/applications/main/subghz/subghz_last_settings.h b/applications/main/subghz/subghz_last_settings.h index ef3674d69..f08d99c81 100644 --- a/applications/main/subghz/subghz_last_settings.h +++ b/applications/main/subghz/subghz_last_settings.h @@ -1,23 +1,12 @@ #pragma once -// Enable saving detect raw setting state -// #define SUBGHZ_SAVE_DETECT_RAW_SETTING 1 - #include #include #include #include -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING -#include -#define DETECT_RAW_FALSE SubGhzProtocolFlag_Decodable -#define DETECT_RAW_TRUE SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_RAW -#endif typedef struct { uint32_t frequency; -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - uint32_t detect_raw; -#endif int32_t preset; uint32_t frequency_analyzer_feedback_level; float frequency_analyzer_trigger; @@ -30,6 +19,3 @@ void subghz_last_settings_free(SubGhzLastSettings* instance); void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count); bool subghz_last_settings_save(SubGhzLastSettings* instance); -#ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING -void subghz_last_settings_set_detect_raw_values(void* context); -#endif \ No newline at end of file diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 0a219a48c..fa3569245 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -7,13 +7,15 @@ #include #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define FRAME_HEIGHT 12 #define MAX_LEN_PX 111 #define MENU_ITEMS 4u #define UNLOCK_CNT 3 +#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f + typedef struct { FuriString* item_str; uint8_t type; @@ -34,7 +36,7 @@ static const Icon* ReceiverItemIcons[] = { [SubGhzProtocolTypeUnknown] = &I_Quest_7x8, [SubGhzProtocolTypeStatic] = &I_Static_9x7, [SubGhzProtocolTypeDynamic] = &I_Dynamic_9x7, - [SubGhzProtocolTypeRAW] = &I_Raw_9x7, + [SubGhzProtocolTypeBinRAW] = &I_Raw_9x7, }; typedef enum { @@ -64,6 +66,7 @@ typedef struct { uint16_t history_item; SubGhzViewReceiverBarShow bar_show; SubGhzViewReceiverMode mode; + uint8_t u_rssi; } SubGhzViewReceiverModel; void subghz_view_receiver_set_mode( @@ -73,6 +76,21 @@ void subghz_view_receiver_set_mode( subghz_receiver->view, SubGhzViewReceiverModel * model, { model->mode = mode; }, true); } +void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { + furi_assert(instance); + with_view_model( + instance->view, + SubGhzViewReceiverModel * model, + { + if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + model->u_rssi = 0; + } else { + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + } + }, + true); +} + void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) { furi_assert(subghz_receiver); subghz_receiver->lock_count = 0; @@ -191,6 +209,16 @@ static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool s canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); } +static void subghz_view_rssi_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { + for(uint8_t i = 1; i < model->u_rssi; i++) { + if(i % 5) { + canvas_draw_dot(canvas, 46 + i, 50); + canvas_draw_dot(canvas, 47 + i, 51); + canvas_draw_dot(canvas, 46 + i, 52); + } + } +} + void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); @@ -198,8 +226,9 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { if(model->mode == SubGhzViewReceiverModeLive) { elements_button_left(canvas, "Config"); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); } else { + canvas_draw_line(canvas, 2, 52, 125, 52); canvas_draw_str(canvas, 3, 62, furi_string_get_cstr(model->progress_str)); } @@ -235,7 +264,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_draw_icon(canvas, 0, 0, XTREME_ASSETS()->I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } else { canvas_draw_icon(canvas, 0, 0, XTREME_ASSETS()->I_Scanning_123x52); @@ -245,6 +274,9 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } } + if(model->mode == SubGhzViewReceiverModeLive) { + subghz_view_rssi_draw(canvas, model); + } switch(model->bar_show) { case SubGhzViewReceiverBarShowLock: canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); @@ -252,7 +284,28 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { break; case SubGhzViewReceiverBarShowToUnlockPress: canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str)); +#ifdef SUBGHZ_EXT_PRESET_NAME + if(model->history_item == 0 && model->mode == SubGhzViewReceiverModeLive) { + canvas_draw_str( + canvas, + 44 + canvas_string_width(canvas, furi_string_get_cstr(model->frequency_str)) + 1, + 62, + "MHz"); + const char* str = furi_string_get_cstr(model->preset_str); + const uint8_t vertical_offset = 7; + const uint8_t horizontal_offset = 3; + const uint8_t string_width = canvas_string_width(canvas, str); + canvas_draw_str( + canvas, + canvas_width(canvas) - (string_width + horizontal_offset), + vertical_offset, + str); + } else { + canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); + } +#else canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); +#endif canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); canvas_set_font(canvas, FontSecondary); elements_bold_rounded_frame(canvas, 14, 8, 99, 48); diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index 829277174..37eb473de 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -12,6 +12,8 @@ void subghz_view_receiver_set_mode( SubGhzViewReceiver* subghz_receiver, SubGhzViewReceiverMode mode); +void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi); + void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard); void subghz_view_receiver_set_callback( diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index ff971fd3b..ce2e34297 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -21,11 +21,12 @@ #define MAX_HISTORY 4 static const uint32_t subghz_frequency_list[] = { - 300000000, 302757000, 303875000, 304250000, 307000000, 307500000, 307800000, 309000000, - 310000000, 312000000, 312100000, 313000000, 313850000, 314000000, 314350000, 314980000, - 315000000, 318000000, 330000000, 345000000, 348000000, 387000000, 390000000, 418000000, - 433075000, 433220000, 433420000, 433657070, 433889000, 433920000, 434075000, 434176948, - 434390000, 434420000, 434775000, 438900000, 440175000, 464000000, 779000000, 868350000, + 300000000, 302757000, 303875000, 304250000, 307000000, 307500000, 307800000, + 309000000, 310000000, 312000000, 312100000, 313000000, 313850000, 314000000, + 314350000, 314980000, 315000000, 318000000, 330000000, 345000000, 348000000, + 350000000, 387000000, 390000000, 418000000, 433075000, 433220000, 433420000, + 433657070, 433889000, 433920000, 434075000, 434176948, 434390000, 434420000, + 434775000, 438900000, 440175000, 464000000, 467750000, 779000000, 868350000, 868400000, 868800000, 868950000, 906400000, 915000000, 925000000, 928000000}; typedef enum { @@ -165,6 +166,7 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel // Title canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 0, 7, furi_hal_subghz_get_radio_type() ? "Ext" : "Int"); canvas_draw_str(canvas, 20, 7, "Frequency Analyzer"); // RSSI @@ -644,4 +646,4 @@ SubGHzFrequencyAnalyzerFeedbackLevel subghz_frequency_analyzer_feedback_level( float subghz_frequency_analyzer_get_trigger_level(SubGhzFrequencyAnalyzer* instance) { furi_assert(instance); return subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); -} \ No newline at end of file +} diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index dcfc281d2..7ba2f4434 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -30,6 +30,7 @@ typedef struct { SubGhzReadRAWStatus status; bool raw_send_only; float raw_threshold_rssi; + bool not_showing_samples; } SubGhzReadRAWModel; void subghz_read_raw_set_callback( @@ -92,7 +93,10 @@ void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample) with_view_model( instance->view, SubGhzReadRAWModel * model, - { furi_string_printf(model->sample_write, "%zu spl.", sample); }, + { + model->not_showing_samples = false; + furi_string_printf(model->sample_write, "%zu spl.", sample); + }, false); } @@ -280,8 +284,15 @@ void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) { uint8_t graphics_mode = 1; canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 5, 7, furi_string_get_cstr(model->frequency_str)); - canvas_draw_str(canvas, 40, 7, furi_string_get_cstr(model->preset_str)); + canvas_draw_str(canvas, 0, 7, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 35, 7, furi_string_get_cstr(model->preset_str)); + + if(model->not_showing_samples) { + canvas_draw_str(canvas, 77, 7, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int"); + } else { + canvas_draw_str(canvas, 70, 7, furi_hal_subghz_get_radio_type() ? "E" : "I"); + } + canvas_draw_str_aligned( canvas, 126, 0, AlignRight, AlignTop, furi_string_get_cstr(model->sample_write)); @@ -448,6 +459,7 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { model->status = SubGhzReadRAWStatusStart; model->rssi_history_end = false; model->ind_write = 0; + model->not_showing_samples = true; furi_string_set(model->sample_write, "0 spl."); furi_string_reset(model->file_name); instance->callback(SubGhzCustomEventViewReadRAWErase, instance->context); @@ -509,6 +521,7 @@ void subghz_read_raw_set_status( model->status = SubGhzReadRAWStatusStart; model->rssi_history_end = false; model->ind_write = 0; + model->not_showing_samples = true; furi_string_reset(model->file_name); furi_string_set(model->sample_write, "0 spl."); model->raw_threshold_rssi = raw_threshold_rssi; @@ -530,6 +543,7 @@ void subghz_read_raw_set_status( model->status = SubGhzReadRAWStatusLoadKeyIDLE; model->rssi_history_end = false; model->ind_write = 0; + model->not_showing_samples = true; furi_string_set(model->file_name, file_name); furi_string_set(model->sample_write, "RAW"); }, @@ -542,6 +556,7 @@ void subghz_read_raw_set_status( { model->status = SubGhzReadRAWStatusLoadKeyIDLE; if(!model->ind_write) { + model->not_showing_samples = true; furi_string_set(model->file_name, file_name); furi_string_set(model->sample_write, "RAW"); } else { diff --git a/applications/main/subghz/views/subghz_test_carrier.c b/applications/main/subghz/views/subghz_test_carrier.c index e533a6aac..2cbde6e32 100644 --- a/applications/main/subghz/views/subghz_test_carrier.c +++ b/applications/main/subghz/views/subghz_test_carrier.c @@ -115,14 +115,19 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { furi_hal_subghz_set_path(model->path); if(model->status == SubGhzTestCarrierModelStatusRx) { - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_rx(); } else { furi_hal_gpio_init( - &gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_write(&gpio_cc1101_g0, true); + furi_hal_subghz.cc1101_g0_pin, + GpioModeOutputPushPull, + GpioPullNo, + GpioSpeedLow); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, true); if(!furi_hal_subghz_tx()) { - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); subghz_test_carrier->callback( SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context); } @@ -140,7 +145,7 @@ void subghz_test_carrier_enter(void* context) { furi_hal_subghz_reset(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); with_view_model( subghz_test_carrier->view, diff --git a/applications/main/subghz/views/subghz_test_static.c b/applications/main/subghz/views/subghz_test_static.c index 6abefda76..b9e5a8c9c 100644 --- a/applications/main/subghz/views/subghz_test_static.c +++ b/applications/main/subghz/views/subghz_test_static.c @@ -143,8 +143,9 @@ void subghz_test_static_enter(void* context) { furi_hal_subghz_reset(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_write(&gpio_cc1101_g0, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); instance->status_tx = SubGhzTestStaticStatusIDLE; with_view_model( diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index dc324a6a5..102639924 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -84,10 +84,15 @@ void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* mo canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); - elements_multiline_text(canvas, 0, 7, furi_string_get_cstr(model->key_str)); + elements_multiline_text_aligned( + canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str)); canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str)); canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str)); - if(model->show_button) subghz_view_transmitter_button_right(canvas, "Send"); + + if(model->show_button) { + canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int"); + subghz_view_transmitter_button_right(canvas, "Send"); + } } bool subghz_view_transmitter_input(InputEvent* event, void* context) { diff --git a/applications/main/u2f/scenes/u2f_scene_error.c b/applications/main/u2f/scenes/u2f_scene_error.c index 162faf2f1..d87b13063 100644 --- a/applications/main/u2f/scenes/u2f_scene_error.c +++ b/applications/main/u2f/scenes/u2f_scene_error.c @@ -1,5 +1,5 @@ #include "../u2f_app_i.h" -#include "../../../settings/xtreme_settings/xtreme_settings.h" +#include "xtreme/assets.h" static void u2f_scene_error_event_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); @@ -27,7 +27,7 @@ void u2f_scene_error_on_enter(void* context) { app->widget, GuiButtonTypeLeft, "Back", u2f_scene_error_event_callback, app); } else if(app->error == U2fAppErrorCloseRpc) { widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { widget_add_string_multiline_element( app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "I am not\na whore!"); widget_add_string_multiline_element( diff --git a/applications/main/u2f/scenes/u2f_scene_main.c b/applications/main/u2f/scenes/u2f_scene_main.c index af7f1159b..251bc4d99 100644 --- a/applications/main/u2f/scenes/u2f_scene_main.c +++ b/applications/main/u2f/scenes/u2f_scene_main.c @@ -1,7 +1,7 @@ #include "../u2f_app_i.h" #include "../views/u2f_view.h" #include -#include "furi_hal.h" +#include #include "../u2f.h" #define U2F_REQUEST_TIMEOUT 500 diff --git a/applications/main/u2f/views/u2f_view.c b/applications/main/u2f/views/u2f_view.c index eecd32702..7bd2cf94f 100644 --- a/applications/main/u2f/views/u2f_view.c +++ b/applications/main/u2f/views/u2f_view.c @@ -1,7 +1,7 @@ #include "u2f_view.h" #include #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" struct U2fView { View* view; @@ -21,7 +21,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) { if(model->display_msg == U2fMsgNotConnected) { canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connect_me_62x31); - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { canvas_draw_str_aligned( canvas, 128 / 2, 3, AlignCenter, AlignTop, "Plug me in d-daddy"); } else { @@ -32,7 +32,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) { canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connected_62x31); canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Connected!"); } else if(model->display_msg == U2fMsgRegister) { - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { elements_button_center(canvas, "CUM"); canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Auth_62x31); canvas_draw_str_aligned( @@ -44,7 +44,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) { canvas, 128 / 2, 3, AlignCenter, AlignTop, "Press OK to register"); } } else if(model->display_msg == U2fMsgAuth) { - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { elements_button_center(canvas, "CUM"); canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Auth_62x31); canvas_draw_str_aligned( @@ -57,7 +57,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) { } } else if(model->display_msg == U2fMsgSuccess) { canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Connected_62x31); - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Cum released~"); } else { canvas_draw_str_aligned( @@ -65,7 +65,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) { } } else if(model->display_msg == U2fMsgError) { canvas_draw_icon(canvas, 22, 15, XTREME_ASSETS()->I_Error_62x31); - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Unable to cum"); } else { canvas_draw_str_aligned( diff --git a/applications/main/unirfremix/unirfremix_app.c b/applications/main/unirfremix/unirfremix_app.c index 2c0b68ae7..2b12a12b2 100644 --- a/applications/main/unirfremix/unirfremix_app.c +++ b/applications/main/unirfremix/unirfremix_app.c @@ -706,7 +706,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { void unirfremix_subghz_alloc(UniRFRemix* app) { // load subghz presets app->setting = subghz_setting_alloc(); - subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user.txt")); // load mfcodes app->environment = subghz_environment_alloc(); diff --git a/applications/plugins/application.fam b/applications/plugins/application.fam index 3e5a654aa..3331888f2 100644 --- a/applications/plugins/application.fam +++ b/applications/plugins/application.fam @@ -3,7 +3,7 @@ App( name="Basic applications for plug-in menu", apptype=FlipperAppType.METAPACKAGE, provides=[ - "music_player", + "music_player", "music_beeper", "snake_game", "bt_hid", diff --git a/applications/plugins/asteroids/application.fam b/applications/plugins/asteroids/application.fam index 0a56122e7..f5ad2cdb9 100644 --- a/applications/plugins/asteroids/application.fam +++ b/applications/plugins/asteroids/application.fam @@ -5,7 +5,7 @@ App( entry_point="asteroids_app_entry", cdefines=["APP_PROTOVIEW"], requires=["gui"], - stack_size=8*1024, + stack_size=8 * 1024, order=50, fap_icon="appicon.png", fap_category="Games", diff --git a/applications/plugins/blackjack/application.fam b/applications/plugins/blackjack/application.fam index 8230cd047..489ce2aeb 100644 --- a/applications/plugins/blackjack/application.fam +++ b/applications/plugins/blackjack/application.fam @@ -4,10 +4,10 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="blackjack_app", cdefines=["APP_BLACKJACK"], - requires=["gui","storage","canvas"], + requires=["gui", "storage", "canvas"], stack_size=2 * 1024, order=30, fap_icon="blackjack_10px.png", fap_category="Games", - fap_icon_assets="assets" -) \ No newline at end of file + fap_icon_assets="assets", +) diff --git a/applications/plugins/brainfuck/application.fam b/applications/plugins/brainfuck/application.fam new file mode 100644 index 000000000..6e2b6d1f9 --- /dev/null +++ b/applications/plugins/brainfuck/application.fam @@ -0,0 +1,15 @@ +App( + appid="Brainfuck", + name="Brainfuck", + apptype=FlipperAppType.EXTERNAL, + entry_point="brainfuck_app", + requires=[ + "storage", + "gui", + ], + stack_size=8 * 1024, + fap_icon="bfico.png", + fap_category="Misc", + fap_icon_assets="icons", + fap_icon_assets_symbol="brainfuck", +) diff --git a/applications/plugins/brainfuck/bfico.png b/applications/plugins/brainfuck/bfico.png new file mode 100644 index 000000000..b25368fb5 Binary files /dev/null and b/applications/plugins/brainfuck/bfico.png differ diff --git a/applications/plugins/brainfuck/brainfuck.c b/applications/plugins/brainfuck/brainfuck.c new file mode 100644 index 000000000..4577de68b --- /dev/null +++ b/applications/plugins/brainfuck/brainfuck.c @@ -0,0 +1,149 @@ +#include "brainfuck_i.h" + +/* + Due to the lack of documentation on the flipper i copied the picopass app, + ripped its insides out and used its hollow corpse to build this app inside of. + + i dont know how this stuff works and after 6 hours of trying to learn it, i dont care +*/ + +bool brainfuck_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + BFApp* brainfuck = context; + return scene_manager_handle_custom_event(brainfuck->scene_manager, event); +} + +bool brainfuck_back_event_callback(void* context) { + furi_assert(context); + BFApp* brainfuck = context; + return scene_manager_handle_back_event(brainfuck->scene_manager); +} + +BFApp* brainfuck_alloc() { + BFApp* brainfuck = malloc(sizeof(BFApp)); + + brainfuck->dataSize = 0; + brainfuck->view_dispatcher = view_dispatcher_alloc(); + brainfuck->scene_manager = scene_manager_alloc(&brainfuck_scene_handlers, brainfuck); + view_dispatcher_enable_queue(brainfuck->view_dispatcher); + view_dispatcher_set_event_callback_context(brainfuck->view_dispatcher, brainfuck); + view_dispatcher_set_custom_event_callback( + brainfuck->view_dispatcher, brainfuck_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + brainfuck->view_dispatcher, brainfuck_back_event_callback); + + // Open GUI record + brainfuck->gui = furi_record_open(RECORD_GUI); + view_dispatcher_attach_to_gui( + brainfuck->view_dispatcher, brainfuck->gui, ViewDispatcherTypeFullscreen); + + // Open Notification record + brainfuck->notifications = furi_record_open(RECORD_NOTIFICATION); + + // Submenu + brainfuck->submenu = submenu_alloc(); + view_dispatcher_add_view( + brainfuck->view_dispatcher, brainfuckViewMenu, submenu_get_view(brainfuck->submenu)); + + // Popup + brainfuck->popup = popup_alloc(); + view_dispatcher_add_view( + brainfuck->view_dispatcher, brainfuckViewPopup, popup_get_view(brainfuck->popup)); + + // Text Input + brainfuck->text_input = text_input_alloc(); + view_dispatcher_add_view( + brainfuck->view_dispatcher, + brainfuckViewTextInput, + text_input_get_view(brainfuck->text_input)); + + // Textbox + brainfuck->text_box = text_box_alloc(); + view_dispatcher_add_view( + brainfuck->view_dispatcher, brainfuckViewTextBox, text_box_get_view(brainfuck->text_box)); + brainfuck->text_box_store = furi_string_alloc(); + + // Dev environment + brainfuck->BF_dev_env = bf_dev_env_alloc(brainfuck); + view_dispatcher_add_view( + brainfuck->view_dispatcher, brainfuckViewDev, bf_dev_env_get_view(brainfuck->BF_dev_env)); + + // File path + brainfuck->BF_file_path = furi_string_alloc(); + + return brainfuck; +} + +void brainfuck_free(BFApp* brainfuck) { + furi_assert(brainfuck); + + // Submenu + view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewMenu); + submenu_free(brainfuck->submenu); + + // Popup + view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewPopup); + popup_free(brainfuck->popup); + + // TextInput + view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewTextInput); + text_input_free(brainfuck->text_input); + + // TextBox + view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewTextBox); + text_box_free(brainfuck->text_box); + furi_string_free(brainfuck->text_box_store); + + //dev env + view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewDev); + bf_dev_env_free(brainfuck->BF_dev_env); + + // View Dispatcher + view_dispatcher_free(brainfuck->view_dispatcher); + + // Scene Manager + scene_manager_free(brainfuck->scene_manager); + + // GUI + furi_record_close(RECORD_GUI); + brainfuck->gui = NULL; + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + brainfuck->notifications = NULL; + + free(brainfuck); +} + +void brainfuck_show_loading_popup(void* context, bool show) { + BFApp* brainfuck = context; + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_dispatcher_switch_to_view(brainfuck->view_dispatcher, brainfuckViewLoading); + } else { + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + +int32_t brainfuck_app(void* p) { + UNUSED(p); + BFApp* brainfuck = brainfuck_alloc(); + if(!brainfuck) { + return 0; + } + + Storage* storage = furi_record_open(RECORD_STORAGE); + storage_simply_mkdir(storage, "/ext/brainfuck"); + + scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneStart); + + view_dispatcher_run(brainfuck->view_dispatcher); + + brainfuck_free(brainfuck); + + return 0; +} \ No newline at end of file diff --git a/applications/plugins/brainfuck/brainfuck.h b/applications/plugins/brainfuck/brainfuck.h new file mode 100644 index 000000000..2e58321a6 --- /dev/null +++ b/applications/plugins/brainfuck/brainfuck.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct BFApp BFApp; \ No newline at end of file diff --git a/applications/plugins/brainfuck/brainfuck_i.h b/applications/plugins/brainfuck/brainfuck_i.h new file mode 100644 index 000000000..d3d27dcbd --- /dev/null +++ b/applications/plugins/brainfuck/brainfuck_i.h @@ -0,0 +1,89 @@ +#pragma once + +typedef struct BFDevEnv BFDevEnv; +typedef struct BFExecEnv BFExecEnv; +typedef unsigned char byte; + +#include "brainfuck.h" +#include "worker.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "scenes/brainfuck_scene.h" + +#include "views/bf_dev_env.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define BF_INST_BUFFER_SIZE 2048 +#define BF_OUTPUT_SIZE 512 +#define BF_STACK_INITIAL_SIZE 128 +#define BF_INPUT_BUFFER_SIZE 64 +#define BF_STACK_STEP_SIZE 32 + +enum brainfuckCustomEvent { + // Reserve first 100 events for button types and indexes, starting from 0 + brainfuckCustomEventReserved = 100, + + brainfuckCustomEventViewExit, + brainfuckCustomEventWorkerExit, + brainfuckCustomEventByteInputDone, + brainfuckCustomEventTextInputDone, +}; + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +struct BFApp { + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notifications; + SceneManager* scene_manager; + Submenu* submenu; + Popup* popup; + TextInput* text_input; + TextBox* text_box; + FuriString* text_box_store; + FuriString* BF_file_path; + BFDevEnv* BF_dev_env; + int dataSize; + char dataBuffer[BF_INST_BUFFER_SIZE]; + char inputBuffer[BF_INPUT_BUFFER_SIZE]; +}; + +typedef enum { + brainfuckViewMenu, + brainfuckViewPopup, + brainfuckViewLoading, + brainfuckViewTextInput, + brainfuckViewTextBox, + brainfuckViewWidget, + brainfuckViewDev, + brainfuckViewExec, +} brainfuckView; diff --git a/applications/plugins/brainfuck/icons/ButtonRightSmall_3x5.png b/applications/plugins/brainfuck/icons/ButtonRightSmall_3x5.png new file mode 100644 index 000000000..b9d5f87db Binary files /dev/null and b/applications/plugins/brainfuck/icons/ButtonRightSmall_3x5.png differ diff --git a/applications/plugins/brainfuck/icons/KeyBackspaceSelected_24x11.png b/applications/plugins/brainfuck/icons/KeyBackspaceSelected_24x11.png new file mode 100644 index 000000000..c79cfb6c6 Binary files /dev/null and b/applications/plugins/brainfuck/icons/KeyBackspaceSelected_24x11.png differ diff --git a/applications/plugins/brainfuck/icons/KeyBackspace_24x11.png b/applications/plugins/brainfuck/icons/KeyBackspace_24x11.png new file mode 100644 index 000000000..00e66428d Binary files /dev/null and b/applications/plugins/brainfuck/icons/KeyBackspace_24x11.png differ diff --git a/applications/plugins/brainfuck/icons/KeyInputSelected_30x11.png b/applications/plugins/brainfuck/icons/KeyInputSelected_30x11.png new file mode 100644 index 000000000..4c04a0856 Binary files /dev/null and b/applications/plugins/brainfuck/icons/KeyInputSelected_30x11.png differ diff --git a/applications/plugins/brainfuck/icons/KeyInput_30x11.png b/applications/plugins/brainfuck/icons/KeyInput_30x11.png new file mode 100644 index 000000000..d23e24aaf Binary files /dev/null and b/applications/plugins/brainfuck/icons/KeyInput_30x11.png differ diff --git a/applications/plugins/brainfuck/icons/KeyRunSelected_24x11.png b/applications/plugins/brainfuck/icons/KeyRunSelected_24x11.png new file mode 100644 index 000000000..3ff5ac5e6 Binary files /dev/null and b/applications/plugins/brainfuck/icons/KeyRunSelected_24x11.png differ diff --git a/applications/plugins/brainfuck/icons/KeyRun_24x11.png b/applications/plugins/brainfuck/icons/KeyRun_24x11.png new file mode 100644 index 000000000..cce46c972 Binary files /dev/null and b/applications/plugins/brainfuck/icons/KeyRun_24x11.png differ diff --git a/applications/plugins/brainfuck/icons/KeySaveSelected_24x11.png b/applications/plugins/brainfuck/icons/KeySaveSelected_24x11.png new file mode 100644 index 000000000..eeb3569d3 Binary files /dev/null and b/applications/plugins/brainfuck/icons/KeySaveSelected_24x11.png differ diff --git a/applications/plugins/brainfuck/icons/KeySave_24x11.png b/applications/plugins/brainfuck/icons/KeySave_24x11.png new file mode 100644 index 000000000..e7dba987a Binary files /dev/null and b/applications/plugins/brainfuck/icons/KeySave_24x11.png differ diff --git a/applications/plugins/brainfuck/icons/bfico.png b/applications/plugins/brainfuck/icons/bfico.png new file mode 100644 index 000000000..b25368fb5 Binary files /dev/null and b/applications/plugins/brainfuck/icons/bfico.png differ diff --git a/applications/plugins/brainfuck/scenes/brainfuck_scene.c b/applications/plugins/brainfuck/scenes/brainfuck_scene.c new file mode 100644 index 000000000..90707c926 --- /dev/null +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene.c @@ -0,0 +1,30 @@ +#include "brainfuck_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const brainfuck_on_enter_handlers[])(void*) = { +#include "brainfuck_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const brainfuck_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "brainfuck_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const brainfuck_on_exit_handlers[])(void* context) = { +#include "brainfuck_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers brainfuck_scene_handlers = { + .on_enter_handlers = brainfuck_on_enter_handlers, + .on_event_handlers = brainfuck_on_event_handlers, + .on_exit_handlers = brainfuck_on_exit_handlers, + .scene_num = brainfuckSceneNum, +}; diff --git a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene.h b/applications/plugins/brainfuck/scenes/brainfuck_scene.h similarity index 63% rename from applications/settings/xtreme_settings/scenes/xtreme_settings_scene.h rename to applications/plugins/brainfuck/scenes/brainfuck_scene.h index 70abf4f77..f7131a56c 100644 --- a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene.h +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene.h @@ -3,27 +3,27 @@ #include // Generate scene id and total number -#define ADD_SCENE(prefix, name, id) XtremeSettingsAppScene##id, +#define ADD_SCENE(prefix, name, id) brainfuckScene##id, typedef enum { -#include "xtreme_settings_scene_config.h" - XtremeSettingsAppSceneNum, -} XtremeSettingsAppScene; +#include "brainfuck_scene_config.h" + brainfuckSceneNum, +} brainfuckScene; #undef ADD_SCENE -extern const SceneManagerHandlers xtreme_settings_scene_handlers; +extern const SceneManagerHandlers brainfuck_scene_handlers; // Generate scene on_enter handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); -#include "xtreme_settings_scene_config.h" +#include "brainfuck_scene_config.h" #undef ADD_SCENE // Generate scene on_event handlers declaration #define ADD_SCENE(prefix, name, id) \ bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); -#include "xtreme_settings_scene_config.h" +#include "brainfuck_scene_config.h" #undef ADD_SCENE // Generate scene on_exit handlers declaration #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); -#include "xtreme_settings_scene_config.h" +#include "brainfuck_scene_config.h" #undef ADD_SCENE diff --git a/applications/plugins/brainfuck/scenes/brainfuck_scene_config.h b/applications/plugins/brainfuck/scenes/brainfuck_scene_config.h new file mode 100644 index 000000000..0efc41641 --- /dev/null +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene_config.h @@ -0,0 +1,6 @@ +ADD_SCENE(brainfuck, start, Start) +ADD_SCENE(brainfuck, file_select, FileSelect) +ADD_SCENE(brainfuck, file_create, FileCreate) +ADD_SCENE(brainfuck, dev_env, DevEnv) +ADD_SCENE(brainfuck, exec_env, ExecEnv) +ADD_SCENE(brainfuck, set_input, SetInput) \ No newline at end of file diff --git a/applications/plugins/brainfuck/scenes/brainfuck_scene_dev.c b/applications/plugins/brainfuck/scenes/brainfuck_scene_dev.c new file mode 100644 index 000000000..475e9e573 --- /dev/null +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene_dev.c @@ -0,0 +1,16 @@ +#include "../brainfuck_i.h" + +void brainfuck_scene_dev_env_on_enter(void* context) { + BFApp* app = context; + view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewDev); +} + +bool brainfuck_scene_dev_env_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void brainfuck_scene_dev_env_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/plugins/brainfuck/scenes/brainfuck_scene_exec.c b/applications/plugins/brainfuck/scenes/brainfuck_scene_exec.c new file mode 100644 index 000000000..d344f7271 --- /dev/null +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene_exec.c @@ -0,0 +1,16 @@ +#include "../brainfuck_i.h" + +void brainfuck_scene_exec_env_on_enter(void* context) { + BFApp* app = context; + view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextBox); +} + +bool brainfuck_scene_exec_env_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void brainfuck_scene_exec_env_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/plugins/brainfuck/scenes/brainfuck_scene_file_create.c b/applications/plugins/brainfuck/scenes/brainfuck_scene_file_create.c new file mode 100644 index 000000000..9f8885977 --- /dev/null +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene_file_create.c @@ -0,0 +1,50 @@ +#include "../brainfuck_i.h" + +void file_name_text_input_callback(void* context) { + BFApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, brainfuckCustomEventTextInputDone); +} + +char tmpName[64] = {}; +byte empty[1] = {0x00}; +void brainfuck_scene_file_create_on_enter(void* context) { + BFApp* app = context; + TextInput* text_input = app->text_input; + + text_input_set_header_text(text_input, "New script name"); + text_input_set_result_callback( + text_input, file_name_text_input_callback, app, tmpName, 64, true); + + view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextInput); +} + +bool brainfuck_scene_file_create_on_event(void* context, SceneManagerEvent event) { + BFApp* app = context; + UNUSED(app); + + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == brainfuckCustomEventTextInputDone) { + furi_string_cat_printf(app->BF_file_path, "/ext/brainfuck/%s.b", tmpName); + + //remove old file + Storage* storage = furi_record_open(RECORD_STORAGE); + storage_simply_remove(storage, furi_string_get_cstr(app->BF_file_path)); + + //save new file + Stream* stream = buffered_file_stream_alloc(storage); + buffered_file_stream_open( + stream, furi_string_get_cstr(app->BF_file_path), FSAM_WRITE, FSOM_CREATE_ALWAYS); + stream_write(stream, (const uint8_t*)empty, 1); + buffered_file_stream_close(stream); + + //scene_manager_next_scene(app->scene_manager, brainfuckSceneFileSelect); + scene_manager_next_scene(app->scene_manager, brainfuckSceneDevEnv); + } + } + return consumed; +} + +void brainfuck_scene_file_create_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/plugins/brainfuck/scenes/brainfuck_scene_file_select.c b/applications/plugins/brainfuck/scenes/brainfuck_scene_file_select.c new file mode 100644 index 000000000..33c06ee81 --- /dev/null +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene_file_select.c @@ -0,0 +1,34 @@ +#include "../brainfuck_i.h" + +void brainfuck_scene_file_select_on_enter(void* context) { + BFApp* app = context; + + DialogsApp* dialogs = furi_record_open("dialogs"); + FuriString* path; + path = furi_string_alloc(); + furi_string_set(path, "/ext/brainfuck"); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, ".b", &I_bfico); + browser_options.base_path = "/ext/brainfuck"; + browser_options.hide_ext = false; + + bool selected = dialog_file_browser_show(dialogs, path, path, &browser_options); + + if(selected) { + furi_string_set(app->BF_file_path, path); + scene_manager_next_scene(app->scene_manager, brainfuckSceneDevEnv); + } else { + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, brainfuckSceneStart); + } +} + +bool brainfuck_scene_file_select_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void brainfuck_scene_file_select_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/plugins/brainfuck/scenes/brainfuck_scene_set_input.c b/applications/plugins/brainfuck/scenes/brainfuck_scene_set_input.c new file mode 100644 index 000000000..efb9237cb --- /dev/null +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene_set_input.c @@ -0,0 +1,35 @@ +#include "../brainfuck_i.h" + +void set_input_text_input_callback(void* context) { + BFApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, brainfuckCustomEventTextInputDone); +} + +void brainfuck_scene_set_input_on_enter(void* context) { + BFApp* app = context; + TextInput* text_input = app->text_input; + + text_input_set_header_text(text_input, "Edit input buffer"); + text_input_set_result_callback( + text_input, set_input_text_input_callback, app, app->inputBuffer, 64, true); + + view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextInput); +} + +bool brainfuck_scene_set_input_on_event(void* context, SceneManagerEvent event) { + BFApp* app = context; + + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == brainfuckCustomEventTextInputDone) { + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, brainfuckSceneDevEnv); + } + } + return consumed; +} + +void brainfuck_scene_set_input_on_exit(void* context) { + BFApp* app = context; + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, brainfuckSceneDevEnv); +} diff --git a/applications/plugins/brainfuck/scenes/brainfuck_scene_start.c b/applications/plugins/brainfuck/scenes/brainfuck_scene_start.c new file mode 100644 index 000000000..8eaaf751a --- /dev/null +++ b/applications/plugins/brainfuck/scenes/brainfuck_scene_start.c @@ -0,0 +1,55 @@ +#include "../brainfuck_i.h" +enum SubmenuIndex { + SubmenuIndexNew, + SubmenuIndexOpen, + SubmenuIndexAbout, +}; + +void brainfuck_scene_start_submenu_callback(void* context, uint32_t index) { + BFApp* brainfuck = context; + view_dispatcher_send_custom_event(brainfuck->view_dispatcher, index); +} +void brainfuck_scene_start_on_enter(void* context) { + BFApp* brainfuck = context; + + Submenu* submenu = brainfuck->submenu; + submenu_add_item( + submenu, "New", SubmenuIndexNew, brainfuck_scene_start_submenu_callback, brainfuck); + submenu_add_item( + submenu, "Open", SubmenuIndexOpen, brainfuck_scene_start_submenu_callback, brainfuck); + submenu_add_item( + submenu, "About", SubmenuIndexAbout, brainfuck_scene_start_submenu_callback, brainfuck); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(brainfuck->scene_manager, brainfuckSceneStart)); + view_dispatcher_switch_to_view(brainfuck->view_dispatcher, brainfuckViewMenu); +} + +bool brainfuck_scene_start_on_event(void* context, SceneManagerEvent event) { + BFApp* brainfuck = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexNew) { + scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneFileCreate); + consumed = true; + } else if(event.event == SubmenuIndexOpen) { + scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneFileSelect); + consumed = true; + } else if(event.event == SubmenuIndexAbout) { + text_box_set_text( + brainfuck->text_box, + "FlipperBrainfuck\n\nAn F0 brainfuck intepretor\nBy github.com/Nymda"); + scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneExecEnv); + consumed = true; + } + scene_manager_set_scene_state(brainfuck->scene_manager, brainfuckSceneStart, event.event); + } + + return consumed; +} + +void brainfuck_scene_start_on_exit(void* context) { + BFApp* brainfuck = context; + submenu_reset(brainfuck->submenu); +} diff --git a/applications/plugins/brainfuck/views/bf_dev_env.c b/applications/plugins/brainfuck/views/bf_dev_env.c new file mode 100644 index 000000000..c5f194500 --- /dev/null +++ b/applications/plugins/brainfuck/views/bf_dev_env.c @@ -0,0 +1,419 @@ +#include "bf_dev_env.h" +#include + +typedef struct BFDevEnv { + View* view; + DevEnvOkCallback callback; + void* context; + BFApp* appDev; +} BFDevEnv; + +typedef struct { + uint32_t row; + uint32_t col; +} BFDevEnvModel; + +typedef struct { + int up; + int down; + int left; + int right; +} bMapping; + +static bool bf_dev_process_up(BFDevEnv* devEnv); +static bool bf_dev_process_down(BFDevEnv* devEnv); +static bool bf_dev_process_left(BFDevEnv* devEnv); +static bool bf_dev_process_right(BFDevEnv* devEnv); +static bool bf_dev_process_ok(BFDevEnv* devEnv, InputEvent* event); + +BFApp* appDev; +FuriThread* workerThread; + +char bfChars[9] = {'<', '>', '[', ']', '+', '-', '.', ',', 0x00}; + +int selectedButton = 0; +int saveNotifyCountdown = 0; +int execCountdown = 0; + +char dspLine0[25] = {}; +char dspLine1[25] = {}; +char dspLine2[25] = {}; + +static bMapping buttonMappings[12] = { + {8, 8, 7, 1}, //0 + {8, 8, 0, 2}, //1 + {9, 9, 1, 3}, //2 + {9, 9, 2, 4}, //3 + {10, 10, 3, 5}, //4 + {10, 10, 4, 6}, //5 + {11, 11, 5, 7}, //6 + {11, 11, 6, 0}, //7 + + {0, 0, 11, 9}, //8 + {3, 3, 8, 10}, //9 + {5, 5, 9, 11}, //10 + {6, 6, 10, 8} //11 +}; + +#define BT_X 14 +#define BT_Y 14 +static void bf_dev_draw_button(Canvas* canvas, int x, int y, bool selected, const char* lbl) { + UNUSED(lbl); + + if(selected) { + canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3); + canvas_invert_color(canvas); + canvas_set_font(canvas, FontBatteryPercent); + canvas_draw_str_aligned( + canvas, x + (BT_X / 2), y + (BT_Y / 2) - 1, AlignCenter, AlignCenter, lbl); + canvas_invert_color(canvas); + } else { + canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3); + canvas_invert_color(canvas); + canvas_draw_rbox(canvas, x + 2, y - 1, BT_X - 2, BT_Y - 1, 3); + canvas_invert_color(canvas); + canvas_draw_rframe(canvas, x, y, BT_X, BT_Y, 3); + canvas_set_font(canvas, FontBatteryPercent); + canvas_draw_str_aligned( + canvas, x + (BT_X / 2), y + (BT_Y / 2) - 1, AlignCenter, AlignCenter, lbl); + } +} + +void bf_save_changes() { + //remove old file + Storage* storage = furi_record_open(RECORD_STORAGE); + storage_simply_remove(storage, furi_string_get_cstr(appDev->BF_file_path)); + + //save new file + Stream* stream = buffered_file_stream_alloc(storage); + buffered_file_stream_open( + stream, furi_string_get_cstr(appDev->BF_file_path), FSAM_WRITE, FSOM_CREATE_ALWAYS); + stream_write(stream, (const uint8_t*)appDev->dataBuffer, appDev->dataSize); + buffered_file_stream_close(stream); +} + +static void bf_dev_draw_callback(Canvas* canvas, void* _model) { + UNUSED(_model); + + if(saveNotifyCountdown > 0) { + canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "SAVED"); + saveNotifyCountdown--; + return; + } + + bf_dev_draw_button(canvas, 1, 36, (selectedButton == 0), "+"); //T 0 + bf_dev_draw_button(canvas, 17, 36, (selectedButton == 1), "-"); //T 1 + bf_dev_draw_button(canvas, 33, 36, (selectedButton == 2), "<"); //T 2 + bf_dev_draw_button(canvas, 49, 36, (selectedButton == 3), ">"); //T 3 + bf_dev_draw_button(canvas, 65, 36, (selectedButton == 4), "["); //B 0 + bf_dev_draw_button(canvas, 81, 36, (selectedButton == 5), "]"); //B 1 + bf_dev_draw_button(canvas, 97, 36, (selectedButton == 6), "."); //B 2 + bf_dev_draw_button(canvas, 113, 36, (selectedButton == 7), ","); //B 3 + + //backspace, input, run, save + canvas_draw_icon( + canvas, + 1, + 52, + (selectedButton == 8) ? &I_KeyBackspaceSelected_24x11 : &I_KeyBackspace_24x11); + canvas_draw_icon( + canvas, 45, 52, (selectedButton == 9) ? &I_KeyInputSelected_30x11 : &I_KeyInput_30x11); + canvas_draw_icon( + canvas, 77, 52, (selectedButton == 10) ? &I_KeyRunSelected_24x11 : &I_KeyRun_24x11); + canvas_draw_icon( + canvas, 103, 52, (selectedButton == 11) ? &I_KeySaveSelected_24x11 : &I_KeySave_24x11); + + if(saveNotifyCountdown > 0) { + canvas_draw_icon(canvas, 98, 54, &I_ButtonRightSmall_3x5); + saveNotifyCountdown--; + } + + //textbox + //grossly overcomplicated. not fixing it. + canvas_draw_rframe(canvas, 1, 1, 126, 33, 2); + canvas_set_font(canvas, FontBatteryPercent); + + int dbOffset = 0; + if(appDev->dataSize > 72) { + dbOffset = (appDev->dataSize - 72); + } + + memset(dspLine0, 0x00, 25); + memset(dspLine1, 0x00, 25); + memset(dspLine2, 0x00, 25); + + int tpM = 0; + int tp0 = 0; + int tp1 = 0; + int tp2 = 0; + + for(int p = dbOffset; p < appDev->dataSize; p++) { + if(tpM < 24 * 1) { + dspLine0[tp0] = appDev->dataBuffer[p]; + tp0++; + } else if(tpM < 24 * 2) { + dspLine1[tp1] = appDev->dataBuffer[p]; + tp1++; + } else if(tpM < 24 * 3) { + dspLine2[tp2] = appDev->dataBuffer[p]; + tp2++; + } + tpM++; + } + + canvas_draw_str_aligned(canvas, 3, 8, AlignLeft, AlignCenter, dspLine0); + canvas_draw_str_aligned(canvas, 3, 17, AlignLeft, AlignCenter, dspLine1); + canvas_draw_str_aligned(canvas, 3, 26, AlignLeft, AlignCenter, dspLine2); +} + +static bool bf_dev_input_callback(InputEvent* event, void* context) { + furi_assert(context); + BFDevEnv* devEnv = context; + bool consumed = false; + + if(event->type == InputTypeShort) { + if(event->key == InputKeyRight) { + consumed = bf_dev_process_right(devEnv); + } else if(event->key == InputKeyLeft) { + consumed = bf_dev_process_left(devEnv); + } else if(event->key == InputKeyUp) { + consumed = bf_dev_process_up(devEnv); + } else if(event->key == InputKeyDown) { + consumed = bf_dev_process_down(devEnv); + } + } else if(event->key == InputKeyOk) { + consumed = bf_dev_process_ok(devEnv, event); + } + + return consumed; +} + +static bool bf_dev_process_up(BFDevEnv* devEnv) { + UNUSED(devEnv); + selectedButton = buttonMappings[selectedButton].up; + return true; +} + +static bool bf_dev_process_down(BFDevEnv* devEnv) { + UNUSED(devEnv); + selectedButton = buttonMappings[selectedButton].down; + return true; +} + +static bool bf_dev_process_left(BFDevEnv* devEnv) { + UNUSED(devEnv); + selectedButton = buttonMappings[selectedButton].left; + return true; +} + +static bool bf_dev_process_right(BFDevEnv* devEnv) { + UNUSED(devEnv); + selectedButton = buttonMappings[selectedButton].right; + return true; +} + +static bool bf_dev_process_ok(BFDevEnv* devEnv, InputEvent* event) { + UNUSED(devEnv); + UNUSED(event); + + if(event->type != InputTypePress) { + return false; + } + + switch(selectedButton) { + case 0: { + if(appDev->dataSize < BF_INST_BUFFER_SIZE) { + appDev->dataBuffer[appDev->dataSize] = '+'; + appDev->dataSize++; + } + break; + } + + case 1: { + if(appDev->dataSize < BF_INST_BUFFER_SIZE) { + appDev->dataBuffer[appDev->dataSize] = '-'; + appDev->dataSize++; + } + break; + } + + case 2: { + if(appDev->dataSize < BF_INST_BUFFER_SIZE) { + appDev->dataBuffer[appDev->dataSize] = '<'; + appDev->dataSize++; + } + break; + } + + case 3: { + if(appDev->dataSize < BF_INST_BUFFER_SIZE) { + appDev->dataBuffer[appDev->dataSize] = '>'; + appDev->dataSize++; + } + break; + } + + case 4: { + if(appDev->dataSize < BF_INST_BUFFER_SIZE) { + appDev->dataBuffer[appDev->dataSize] = '['; + appDev->dataSize++; + } + break; + } + + case 5: { + if(appDev->dataSize < BF_INST_BUFFER_SIZE) { + appDev->dataBuffer[appDev->dataSize] = ']'; + appDev->dataSize++; + } + break; + } + + case 6: { + if(appDev->dataSize < BF_INST_BUFFER_SIZE) { + appDev->dataBuffer[appDev->dataSize] = '.'; + appDev->dataSize++; + } + break; + } + + case 7: { + if(appDev->dataSize < BF_INST_BUFFER_SIZE) { + appDev->dataBuffer[appDev->dataSize] = ','; + appDev->dataSize++; + } + break; + } + + case 8: { + if(appDev->dataSize > 0) { + appDev->dataSize--; + appDev->dataBuffer[appDev->dataSize] = (uint32_t)0x00; + } + break; + } + + case 9: { + scene_manager_next_scene(appDev->scene_manager, brainfuckSceneSetInput); + break; + } + + case 10: { + if(getStatus() != 0) { + killThread(); + furi_thread_join(workerThread); + } + + bf_save_changes(); + + initWorker(appDev); + text_box_set_focus(appDev->text_box, TextBoxFocusEnd); + text_box_set_text(appDev->text_box, workerGetOutput()); + + workerThread = furi_thread_alloc_ex("Worker", 2048, (void*)beginWorker, NULL); + furi_thread_start(workerThread); + + scene_manager_next_scene(appDev->scene_manager, brainfuckSceneExecEnv); + break; + } + + case 11: { + bf_save_changes(); + saveNotifyCountdown = 3; + break; + } + } + + bool consumed = false; + return consumed; +} + +static void bf_dev_enter_callback(void* context) { + furi_assert(context); + BFDevEnv* devEnv = context; + + with_view_model( + devEnv->view, + BFDevEnvModel * model, + { + model->col = 0; + model->row = 0; + }, + true); + + appDev = devEnv->appDev; + selectedButton = 0; + + //exit the running thread if required + if(getStatus() != 0) { + killThread(); + furi_thread_join(workerThread); + } + + //clear the bf instruction buffer + memset(appDev->dataBuffer, 0x00, BF_INST_BUFFER_SIZE * sizeof(char)); + + //open the file + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* stream = buffered_file_stream_alloc(storage); + buffered_file_stream_open( + stream, furi_string_get_cstr(appDev->BF_file_path), FSAM_READ, FSOM_OPEN_EXISTING); + + //read into the buffer + appDev->dataSize = stream_size(stream); + stream_read(stream, (uint8_t*)appDev->dataBuffer, appDev->dataSize); + buffered_file_stream_close(stream); + + //replaces any invalid characters with an underscore. strips out newlines, comments, etc + for(int i = 0; i < appDev->dataSize; i++) { + if(!strchr(bfChars, appDev->dataBuffer[i])) { + appDev->dataBuffer[i] = '_'; + } + } + + //find the end of the file to begin editing + int tptr = 0; + while(appDev->dataBuffer[tptr] != 0x00) { + tptr++; + } + appDev->dataSize = tptr; +} + +BFDevEnv* bf_dev_env_alloc(BFApp* appDev) { + BFDevEnv* devEnv = malloc(sizeof(BFDevEnv)); + + devEnv->view = view_alloc(); + devEnv->appDev = appDev; + view_allocate_model(devEnv->view, ViewModelTypeLocking, sizeof(BFDevEnvModel)); + + with_view_model( + devEnv->view, + BFDevEnvModel * model, + { + model->col = 0; + model->row = 0; + }, + true); + + view_set_context(devEnv->view, devEnv); + view_set_draw_callback(devEnv->view, bf_dev_draw_callback); + view_set_input_callback(devEnv->view, bf_dev_input_callback); + view_set_enter_callback(devEnv->view, bf_dev_enter_callback); + return devEnv; +} + +void bf_dev_env_free(BFDevEnv* devEnv) { + if(getStatus() != 0) { + killThread(); + furi_thread_join(workerThread); + } + + furi_assert(devEnv); + view_free(devEnv->view); + free(devEnv); +} + +View* bf_dev_env_get_view(BFDevEnv* devEnv) { + furi_assert(devEnv); + return devEnv->view; +} diff --git a/applications/plugins/brainfuck/views/bf_dev_env.h b/applications/plugins/brainfuck/views/bf_dev_env.h new file mode 100644 index 000000000..31059544b --- /dev/null +++ b/applications/plugins/brainfuck/views/bf_dev_env.h @@ -0,0 +1,15 @@ +#pragma once +#include "../brainfuck_i.h" +#include + +typedef void (*DevEnvOkCallback)(InputType type, void* context); + +BFDevEnv* bf_dev_env_alloc(BFApp* application); + +void bf_dev_set_file_path(FuriString* path); + +void bf_dev_env_free(BFDevEnv* devEnv); + +View* bf_dev_env_get_view(BFDevEnv* devEnv); + +void bf_dev_env_set_ok(BFDevEnv* devEnv, DevEnvOkCallback callback, void* context); diff --git a/applications/plugins/brainfuck/worker.c b/applications/plugins/brainfuck/worker.c new file mode 100644 index 000000000..1b05ac3fd --- /dev/null +++ b/applications/plugins/brainfuck/worker.c @@ -0,0 +1,276 @@ +#include "worker.h" + +bool killswitch = false; + +int status = 0; //0: idle, 1: running, 2: failure + +char* inst = 0; +int instCount = 0; +int instPtr = 0; +int runOpCount = 0; + +char* wOutput = 0; +int wOutputPtr = 0; + +char* wInput = 0; +int wInputPtr = 0; + +uint8_t* bfStack = 0; +int stackPtr = 0; +int stackSize = BF_STACK_INITIAL_SIZE; +int stackSizeReal = 0; + +BFApp* wrkrApp = 0; + +void killThread() { + killswitch = true; +} + +bool validateInstPtr() { + if(instPtr > instCount || instPtr < 0) { + return false; + } + return true; +} + +bool validateStackPtr() { + if(stackPtr > stackSize || stackPtr < 0) { + return false; + } + return true; +} + +char* workerGetOutput() { + return wOutput; +} + +int getStackSize() { + return stackSizeReal; +} + +int getOpCount() { + return runOpCount; +} + +int getStatus() { + return status; +} + +void initWorker(BFApp* app) { + wrkrApp = app; + + //rebuild output + if(wOutput) { + free(wOutput); + } + wOutput = (char*)malloc(BF_OUTPUT_SIZE); + wOutputPtr = 0; + + //rebuild stack + if(bfStack) { + free(bfStack); + } + bfStack = (uint8_t*)malloc(BF_STACK_INITIAL_SIZE); + memset(bfStack, 0x00, BF_STACK_INITIAL_SIZE); + stackSize = BF_STACK_INITIAL_SIZE; + stackSizeReal = 0; + stackPtr = 0; + + //set instructions + inst = wrkrApp->dataBuffer; + instCount = wrkrApp->dataSize; + instPtr = 0; + runOpCount = 0; + + //set input + wInput = wrkrApp->inputBuffer; + wInputPtr = 0; + + //set status + status = 0; +} + +void rShift() { + runOpCount++; + stackPtr++; + if(!validateStackPtr()) { + status = 2; + return; + } + + while(stackPtr > stackSize) { + stackSize += BF_STACK_STEP_SIZE; + void* tmp = realloc(bfStack, stackSize); + + if(!tmp) { + status = 2; + return; + } + + memset((tmp + stackSize) - BF_STACK_STEP_SIZE, 0x00, BF_STACK_STEP_SIZE); + bfStack = (uint8_t*)tmp; + }; + if(stackPtr > stackSizeReal) { + stackSizeReal = stackPtr; + } +} + +void lShift() { + runOpCount++; + stackPtr--; + if(!validateStackPtr()) { + status = 2; + return; + } +} + +void inc() { + runOpCount++; + if(!validateStackPtr()) { + status = 2; + return; + } + bfStack[stackPtr]++; +} + +void dec() { + runOpCount++; + if(!validateStackPtr()) { + status = 2; + return; + } + bfStack[stackPtr]--; +} + +void print() { + runOpCount++; + wOutput[wOutputPtr] = bfStack[stackPtr]; + wOutputPtr++; + if(wOutputPtr > (BF_OUTPUT_SIZE - 1)) { + wOutputPtr = 0; + } +} + +void input() { + runOpCount++; + + bfStack[stackPtr] = (uint8_t)wInput[wInputPtr]; + if(wInput[wInputPtr] == 0x00 || wInputPtr >= 64) { + wInputPtr = 0; + } else { + wInputPtr++; + } +} + +void loop() { + runOpCount++; + if(bfStack[stackPtr] == 0) { + int loopCount = 1; + while(loopCount > 0) { + instPtr++; + if(!validateInstPtr()) { + status = 2; + return; + } + if(inst[instPtr] == '[') { + loopCount++; + } else if(inst[instPtr] == ']') { + loopCount--; + } + } + } +} + +void endLoop() { + runOpCount++; + if(bfStack[stackPtr] != 0) { + int loopCount = 1; + while(loopCount > 0) { + instPtr--; + if(!validateInstPtr()) { + status = 2; + return; + } + if(inst[instPtr] == ']') { + loopCount++; + } else if(inst[instPtr] == '[') { + loopCount--; + } + } + } +} + +static const NotificationSequence led_on = { + &message_blue_255, + &message_do_not_reset, + NULL, +}; + +static const NotificationSequence led_off = { + &message_green_0, + NULL, +}; + +void beginWorker() { + status = 1; + while(inst[instPtr] != 0x00) { + if(runOpCount % 500 == 0) { + text_box_set_text(wrkrApp->text_box, workerGetOutput()); + notification_message(wrkrApp->notifications, &led_on); + } + + if(status == 2) { + status = 0; + break; + } + if(killswitch) { + status = 0; + killswitch = false; + break; + } + switch(inst[instPtr]) { + case '>': + rShift(); + break; + case '<': + lShift(); + break; + + case '+': + inc(); + break; + + case '-': + dec(); + break; + + case '.': + print(); + break; + + case ',': + input(); + break; + + case '[': + loop(); + break; + + case ']': + endLoop(); + break; + + default: + break; + } + instPtr++; + if(!validateInstPtr()) { + status = 0; + break; + } + } + + notification_message(wrkrApp->notifications, &led_off); + text_box_set_text(wrkrApp->text_box, workerGetOutput()); + status = 0; +} \ No newline at end of file diff --git a/applications/plugins/brainfuck/worker.h b/applications/plugins/brainfuck/worker.h new file mode 100644 index 000000000..b12e364c3 --- /dev/null +++ b/applications/plugins/brainfuck/worker.h @@ -0,0 +1,9 @@ +#include "brainfuck_i.h" + +void initWorker(BFApp* application); +char* workerGetOutput(); +int getStackSize(); +int getOpCount(); +int getStatus(); +void beginWorker(); +void killThread(); \ No newline at end of file diff --git a/applications/plugins/cli_bridge/application.fam b/applications/plugins/cli_bridge/application.fam index 60cd9648d..f5f294d9b 100644 --- a/applications/plugins/cli_bridge/application.fam +++ b/applications/plugins/cli_bridge/application.fam @@ -3,7 +3,7 @@ App( name="CLI (subghz chat)", apptype=FlipperAppType.EXTERNAL, entry_point="cligui_main", - requires=["gui","cli"], + requires=["gui", "cli"], stack_size=8 * 1024, fap_icon="cligui.png", fap_category="Tools", diff --git a/applications/plugins/clock_app/application.fam b/applications/plugins/clock_app/application.fam index 644fbb65f..a6a2eff3e 100644 --- a/applications/plugins/clock_app/application.fam +++ b/applications/plugins/clock_app/application.fam @@ -7,4 +7,4 @@ App( stack_size=2 * 1024, fap_icon="clock.png", fap_category="Tools", -) \ No newline at end of file +) diff --git a/applications/plugins/counter/application.fam b/applications/plugins/counter/application.fam index bb2e58df1..5d164f20c 100644 --- a/applications/plugins/counter/application.fam +++ b/applications/plugins/counter/application.fam @@ -9,4 +9,4 @@ App( fap_category="Misc", fap_icon="icons/counter_icon.png", fap_icon_assets="icons", -) \ No newline at end of file +) diff --git a/applications/plugins/dap_link/dap_link.c b/applications/plugins/dap_link/dap_link.c index c46c68788..dd684810a 100644 --- a/applications/plugins/dap_link/dap_link.c +++ b/applications/plugins/dap_link/dap_link.c @@ -486,8 +486,7 @@ int32_t dap_link_app(void* p) { if(furi_hal_usb_is_locked()) { DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); DialogMessage* message = dialog_message_alloc(); - dialog_message_set_header( - message, "Connection\nis active!", 3, 2, AlignLeft, AlignTop); + dialog_message_set_header(message, "Connection\nis active!", 3, 2, AlignLeft, AlignTop); dialog_message_set_text( message, "Disconnect from\nPC or phone to\nuse this function.", diff --git a/applications/plugins/dice/dice.c b/applications/plugins/dice/dice.c index 61aa7b4f5..dc748b68f 100644 --- a/applications/plugins/dice/dice.c +++ b/applications/plugins/dice/dice.c @@ -467,7 +467,6 @@ int32_t dice_app(void* p) { return 255; } - ViewPort* view_port = view_port_alloc(); view_port_draw_callback_set(view_port, dice_render_callback, plugin_state); view_port_input_callback_set(view_port, dice_input_callback, plugin_state->event_queue); diff --git a/applications/plugins/dolphinbackup/application.fam b/applications/plugins/dolphinbackup/application.fam index 024c1b197..166f9a22b 100644 --- a/applications/plugins/dolphinbackup/application.fam +++ b/applications/plugins/dolphinbackup/application.fam @@ -9,4 +9,4 @@ App( order=85, fap_icon="bckupIcon.png", fap_category="Tools", -) \ No newline at end of file +) diff --git a/applications/plugins/dolphinbackup/storage_DolphinBackup.c b/applications/plugins/dolphinbackup/storage_DolphinBackup.c index 02baddc0f..7e7bd8f36 100644 --- a/applications/plugins/dolphinbackup/storage_DolphinBackup.c +++ b/applications/plugins/dolphinbackup/storage_DolphinBackup.c @@ -16,7 +16,7 @@ static const char* app_dirsDolphinBackup[] = { "nfc", "infrared", "ibutton", - "badusb", + "badkb", ".bt.settings", ".desktop.settings", ".dolphin.state", diff --git a/applications/plugins/dolphinrestorer/application.fam b/applications/plugins/dolphinrestorer/application.fam index 46699404a..afd263c45 100644 --- a/applications/plugins/dolphinrestorer/application.fam +++ b/applications/plugins/dolphinrestorer/application.fam @@ -4,9 +4,9 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="drestorer_app", cdefines=["APP_DRESTORER"], - requires=["gui","storage"], - stack_size= 2 * 1024, + requires=["gui", "storage"], + stack_size=2 * 1024, order=90, fap_icon="restoreIcon.png", fap_category="Tools", -) \ No newline at end of file +) diff --git a/applications/plugins/flashlight/application.fam b/applications/plugins/flashlight/application.fam index 368e14833..6d70a036f 100644 --- a/applications/plugins/flashlight/application.fam +++ b/applications/plugins/flashlight/application.fam @@ -11,4 +11,4 @@ App( order=20, fap_icon="flash10px.png", fap_category="GPIO", -) \ No newline at end of file +) diff --git a/applications/plugins/flipper_i2ctools/application.fam b/applications/plugins/flipper_i2ctools/application.fam index d8d10dfce..f6522a86e 100644 --- a/applications/plugins/flipper_i2ctools/application.fam +++ b/applications/plugins/flipper_i2ctools/application.fam @@ -10,4 +10,4 @@ App( fap_icon="i2ctools.png", fap_category="GPIO", fap_icon_assets="images", -) \ No newline at end of file +) diff --git a/applications/plugins/game_2048/application.fam b/applications/plugins/game_2048/application.fam index c8940c881..f2456668e 100644 --- a/applications/plugins/game_2048/application.fam +++ b/applications/plugins/game_2048/application.fam @@ -10,6 +10,6 @@ App( ], stack_size=1 * 1024, order=90, - fap_icon="game_2048.png", - fap_category="Games" -) \ No newline at end of file + fap_icon="game_2048.png", + fap_category="Games", +) diff --git a/applications/plugins/geigercounter/application.fam b/applications/plugins/geigercounter/application.fam new file mode 100644 index 000000000..71be5a161 --- /dev/null +++ b/applications/plugins/geigercounter/application.fam @@ -0,0 +1,13 @@ +App( + appid="Geiger_Coutner", + name="[GPIO] Geiger Counter", + apptype=FlipperAppType.EXTERNAL, + entry_point="flipper_geiger_app", + cdefines=["APP_GEIGER"], + requires=[ + "gui", + ], + stack_size=1 * 1024, + fap_icon="geiger.png", + fap_category="GPIO", +) diff --git a/applications/plugins/geigercounter/flipper_geiger.c b/applications/plugins/geigercounter/flipper_geiger.c new file mode 100644 index 000000000..709db9a26 --- /dev/null +++ b/applications/plugins/geigercounter/flipper_geiger.c @@ -0,0 +1,227 @@ +// CC0 1.0 Universal (CC0 1.0) +// Public Domain Dedication +// https://github.com/nmrr + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SCREEN_SIZE_X 128 +#define SCREEN_SIZE_Y 64 + +// FOR J305 GEIGER TUBE +#define CONVERSION_FACTOR 0.0081 + +typedef enum { + EventTypeInput, + ClockEventTypeTick, + EventGPIO, +} EventType; + +typedef struct { + EventType type; + InputEvent input; +} EventApp; + +typedef struct { + uint32_t cps, cpm; + uint32_t line[SCREEN_SIZE_X / 2]; + float coef; + uint8_t data; +} mutexStruct; + +static void draw_callback(Canvas* canvas, void* ctx) { + UNUSED(ctx); + + mutexStruct displayStruct; + mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block((ValueMutex*)ctx); + memcpy(&displayStruct, geigerMutex, sizeof(mutexStruct)); + release_mutex((ValueMutex*)ctx, geigerMutex); + + char buffer[32]; + if(displayStruct.data == 0) + snprintf( + buffer, sizeof(buffer), "%ld cps - %ld cpm", displayStruct.cps, displayStruct.cpm); + else if(displayStruct.data == 1) + snprintf( + buffer, + sizeof(buffer), + "%ld cps - %.2f uSv/h", + displayStruct.cps, + ((double)displayStruct.cpm * (double)CONVERSION_FACTOR)); + else + snprintf( + buffer, + sizeof(buffer), + "%ld cps - %.2f mSv/y", + displayStruct.cps, + (((double)displayStruct.cpm * (double)CONVERSION_FACTOR)) * (double)8.76); + + for(int i = 0; i < SCREEN_SIZE_X; i += 2) { + float Y = SCREEN_SIZE_Y - (displayStruct.line[i / 2] * displayStruct.coef); + + canvas_draw_line(canvas, i, Y, i, SCREEN_SIZE_Y); + canvas_draw_line(canvas, i + 1, Y, i + 1, SCREEN_SIZE_Y); + } + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignBottom, buffer); +} + +static void input_callback(InputEvent* input_event, void* ctx) { + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; + EventApp event = {.type = EventTypeInput, .input = *input_event}; + furi_message_queue_put(event_queue, &event, FuriWaitForever); +} + +static void clock_tick(void* ctx) { + furi_assert(ctx); + + uint32_t randomNumber = furi_hal_random_get(); + randomNumber &= 0xFFF; + if(randomNumber == 0) randomNumber = 1; + + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, randomNumber, 50); + + FuriMessageQueue* queue = ctx; + EventApp event = {.type = ClockEventTypeTick}; + furi_message_queue_put(queue, &event, 0); +} + +static void gpiocallback(void* ctx) { + furi_assert(ctx); + FuriMessageQueue* queue = ctx; + EventApp event = {.type = EventGPIO}; + furi_message_queue_put(queue, &event, 0); +} + +int32_t flipper_geiger_app() { + EventApp event; + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(EventApp)); + + furi_hal_gpio_init(&gpio_ext_pa7, GpioModeInterruptFall, GpioPullUp, GpioSpeedVeryHigh); + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 5, 50); + + mutexStruct mutexVal; + mutexVal.cps = 0; + mutexVal.cpm = 0; + for(int i = 0; i < SCREEN_SIZE_X / 2; i++) mutexVal.line[i] = 0; + mutexVal.coef = 1; + mutexVal.data = 0; + + uint32_t counter = 0; + + ValueMutex state_mutex; + init_mutex(&state_mutex, &mutexVal, sizeof(mutexVal)); + + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, draw_callback, &state_mutex); + view_port_input_callback_set(view_port, input_callback, event_queue); + + furi_hal_gpio_add_int_callback(&gpio_ext_pa7, gpiocallback, event_queue); + + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + FuriTimer* timer = furi_timer_alloc(clock_tick, FuriTimerTypePeriodic, event_queue); + furi_timer_start(timer, 1000); + + // ENABLE 5V pin + furi_hal_power_enable_otg(); + + while(1) { + FuriStatus event_status = furi_message_queue_get(event_queue, &event, FuriWaitForever); + + uint8_t screenRefresh = 0; + + if(event_status == FuriStatusOk) { + if(event.type == EventTypeInput) { + if(event.input.key == InputKeyBack) { + break; + } else if(event.input.key == InputKeyOk && event.input.type == InputTypeShort) { + counter = 0; + mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block(&state_mutex); + + geigerMutex->cps = 0; + geigerMutex->cpm = 0; + for(int i = 0; i < SCREEN_SIZE_X / 2; i++) geigerMutex->line[i] = 0; + + screenRefresh = 1; + release_mutex(&state_mutex, geigerMutex); + } else if((event.input.key == InputKeyLeft && + event.input.type == InputTypeShort)) { + mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block(&state_mutex); + + if(geigerMutex->data != 0) + geigerMutex->data--; + else + geigerMutex->data = 2; + + screenRefresh = 1; + release_mutex(&state_mutex, geigerMutex); + } else if((event.input.key == InputKeyRight && + event.input.type == InputTypeShort)) { + mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block(&state_mutex); + + if(geigerMutex->data != 2) + geigerMutex->data++; + else + geigerMutex->data = 0; + + screenRefresh = 1; + release_mutex(&state_mutex, geigerMutex); + } + } else if(event.type == ClockEventTypeTick) { + mutexStruct* geigerMutex = (mutexStruct*)acquire_mutex_block(&state_mutex); + + for(int i = 0; i < SCREEN_SIZE_X / 2 - 1; i++) + geigerMutex->line[SCREEN_SIZE_X / 2 - 1 - i] = + geigerMutex->line[SCREEN_SIZE_X / 2 - 2 - i]; + + geigerMutex->line[0] = counter; + geigerMutex->cps = counter; + counter = 0; + + geigerMutex->cpm = geigerMutex->line[0]; + uint32_t max = geigerMutex->line[0]; + for(int i = 1; i < SCREEN_SIZE_X / 2; i++) { + if(i < 60) geigerMutex->cpm += geigerMutex->line[i]; + if(geigerMutex->line[i] > max) max = geigerMutex->line[i]; + } + + if(max > 0) + geigerMutex->coef = ((float)(SCREEN_SIZE_Y - 15)) / ((float)max); + else + geigerMutex->coef = 1; + + screenRefresh = 1; + release_mutex(&state_mutex, geigerMutex); + } else if(event.type == EventGPIO) { + counter++; + } + } + + if(screenRefresh == 1) view_port_update(view_port); + } + + furi_hal_power_disable_otg(); + + furi_hal_gpio_disable_int_callback(&gpio_ext_pa7); + furi_hal_gpio_remove_int_callback(&gpio_ext_pa7); + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + + furi_message_queue_free(event_queue); + delete_mutex(&state_mutex); + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + furi_timer_free(timer); + furi_record_close(RECORD_GUI); + + return 0; +} \ No newline at end of file diff --git a/applications/plugins/geigercounter/geiger.png b/applications/plugins/geigercounter/geiger.png new file mode 100644 index 000000000..d41e1915b Binary files /dev/null and b/applications/plugins/geigercounter/geiger.png differ diff --git a/applications/plugins/gpioreader2/application.fam b/applications/plugins/gpioreader2/application.fam index 57792fd0c..bf25c323d 100644 --- a/applications/plugins/gpioreader2/application.fam +++ b/applications/plugins/gpioreader2/application.fam @@ -8,4 +8,4 @@ App( fap_category="GPIO", fap_icon="icon.png", order=1, -) \ No newline at end of file +) diff --git a/applications/plugins/hc_sr04/application.fam b/applications/plugins/hc_sr04/application.fam index da91a0864..bfbb2daa8 100644 --- a/applications/plugins/hc_sr04/application.fam +++ b/applications/plugins/hc_sr04/application.fam @@ -11,4 +11,4 @@ App( order=20, fap_icon="dist_sensor10px.png", fap_category="GPIO", -) \ No newline at end of file +) diff --git a/applications/plugins/hid_app/assets/ButtonF10_5x8.png b/applications/plugins/hid_app/assets/ButtonF10_5x8.png new file mode 100644 index 000000000..d1a7a04f0 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF10_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF11_5x8.png b/applications/plugins/hid_app/assets/ButtonF11_5x8.png new file mode 100644 index 000000000..7e177358e Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF11_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF12_5x8.png b/applications/plugins/hid_app/assets/ButtonF12_5x8.png new file mode 100644 index 000000000..50d2a7dc6 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF12_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF1_5x8.png b/applications/plugins/hid_app/assets/ButtonF1_5x8.png new file mode 100644 index 000000000..7394d2710 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF1_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF2_5x8.png b/applications/plugins/hid_app/assets/ButtonF2_5x8.png new file mode 100644 index 000000000..9d922a385 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF2_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF3_5x8.png b/applications/plugins/hid_app/assets/ButtonF3_5x8.png new file mode 100644 index 000000000..95c2dd4f4 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF3_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF4_5x8.png b/applications/plugins/hid_app/assets/ButtonF4_5x8.png new file mode 100644 index 000000000..602466f4b Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF4_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF5_5x8.png b/applications/plugins/hid_app/assets/ButtonF5_5x8.png new file mode 100644 index 000000000..d73b54052 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF5_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF6_5x8.png b/applications/plugins/hid_app/assets/ButtonF6_5x8.png new file mode 100644 index 000000000..c50748257 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF6_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF7_5x8.png b/applications/plugins/hid_app/assets/ButtonF7_5x8.png new file mode 100644 index 000000000..396c98f51 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF7_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF8_5x8.png b/applications/plugins/hid_app/assets/ButtonF8_5x8.png new file mode 100644 index 000000000..6304d7fb8 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF8_5x8.png differ diff --git a/applications/plugins/hid_app/assets/ButtonF9_5x8.png b/applications/plugins/hid_app/assets/ButtonF9_5x8.png new file mode 100644 index 000000000..148e69580 Binary files /dev/null and b/applications/plugins/hid_app/assets/ButtonF9_5x8.png differ diff --git a/applications/plugins/hid_app/views/hid_keyboard.c b/applications/plugins/hid_app/views/hid_keyboard.c index 8b12e8fd1..82e772b15 100644 --- a/applications/plugins/hid_app/views/hid_keyboard.c +++ b/applications/plugins/hid_app/views/hid_keyboard.c @@ -46,11 +46,25 @@ typedef struct { #define KEY_WIDTH 9 #define KEY_HEIGHT 12 #define KEY_PADDING 1 -#define ROW_COUNT 6 +#define ROW_COUNT 7 #define COLUMN_COUNT 12 // 0 width items are not drawn, but there value is used const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { + { + {.width = 1, .icon = &I_ButtonF1_5x8, .value = HID_KEYBOARD_F1}, + {.width = 1, .icon = &I_ButtonF2_5x8, .value = HID_KEYBOARD_F2}, + {.width = 1, .icon = &I_ButtonF3_5x8, .value = HID_KEYBOARD_F3}, + {.width = 1, .icon = &I_ButtonF4_5x8, .value = HID_KEYBOARD_F4}, + {.width = 1, .icon = &I_ButtonF5_5x8, .value = HID_KEYBOARD_F5}, + {.width = 1, .icon = &I_ButtonF6_5x8, .value = HID_KEYBOARD_F6}, + {.width = 1, .icon = &I_ButtonF7_5x8, .value = HID_KEYBOARD_F7}, + {.width = 1, .icon = &I_ButtonF8_5x8, .value = HID_KEYBOARD_F8}, + {.width = 1, .icon = &I_ButtonF9_5x8, .value = HID_KEYBOARD_F9}, + {.width = 1, .icon = &I_ButtonF10_5x8, .value = HID_KEYBOARD_F10}, + {.width = 1, .icon = &I_ButtonF11_5x8, .value = HID_KEYBOARD_F11}, + {.width = 1, .icon = &I_ButtonF12_5x8, .value = HID_KEYBOARD_F12}, + }, { {.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1}, {.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2}, @@ -224,7 +238,12 @@ static void hid_keyboard_draw_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontKeyboard); // Start shifting the all keys up if on the next row (Scrolling) - uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0; + uint8_t initY = model->y == 0 ? 0 : 1; + + if(model->y > 5) { + initY = model->y - 4; + } + for(uint8_t y = initY; y < ROW_COUNT; y++) { const HidKeyboardKey* keyboardKeyRow = hid_keyboard_keyset[y]; uint8_t x = 0; @@ -365,7 +384,10 @@ HidKeyboard* hid_keyboard_alloc(Hid* bt_hid) { with_view_model( hid_keyboard->view, HidKeyboardModel * model, - { model->transport = bt_hid->transport; }, + { + model->transport = bt_hid->transport; + model->y = 1; + }, true); return hid_keyboard; diff --git a/applications/plugins/htu21d_temp_sensor/application.fam b/applications/plugins/htu21d_temp_sensor/application.fam index 5807d7f51..724f55cd5 100644 --- a/applications/plugins/htu21d_temp_sensor/application.fam +++ b/applications/plugins/htu21d_temp_sensor/application.fam @@ -9,6 +9,6 @@ App( ], stack_size=2 * 1024, order=90, - fap_icon="temperature_sensor.png", + fap_icon="temperature_sensor.png", fap_category="GPIO", ) diff --git a/applications/plugins/ifttt/application.fam b/applications/plugins/ifttt/application.fam index 495627429..75e5beb67 100644 --- a/applications/plugins/ifttt/application.fam +++ b/applications/plugins/ifttt/application.fam @@ -11,4 +11,4 @@ App( order=20, fap_icon="icon.png", fap_category="GPIO", -) \ No newline at end of file +) diff --git a/applications/plugins/morse_code/application.fam b/applications/plugins/morse_code/application.fam index 1cc7bdaa1..73ad2ba81 100644 --- a/applications/plugins/morse_code/application.fam +++ b/applications/plugins/morse_code/application.fam @@ -10,6 +10,5 @@ App( stack_size=1 * 1024, order=20, fap_icon="morse_code_10px.png", - fap_category="Music" - -) \ No newline at end of file + fap_category="Music", +) diff --git a/applications/plugins/mouse_jiggler/application.fam b/applications/plugins/mouse_jiggler/application.fam index 6c529a883..6115315f5 100644 --- a/applications/plugins/mouse_jiggler/application.fam +++ b/applications/plugins/mouse_jiggler/application.fam @@ -9,4 +9,4 @@ App( order=150, fap_icon="mouse_10px.png", fap_category="Misc", -) \ No newline at end of file +) diff --git a/applications/plugins/mousejacker/icons/badusb_10px.png b/applications/plugins/mousejacker/icons/badkb_10px.png similarity index 100% rename from applications/plugins/mousejacker/icons/badusb_10px.png rename to applications/plugins/mousejacker/icons/badkb_10px.png diff --git a/applications/plugins/mousejacker/images/badusb_10px.png b/applications/plugins/mousejacker/images/badkb_10px.png similarity index 100% rename from applications/plugins/mousejacker/images/badusb_10px.png rename to applications/plugins/mousejacker/images/badkb_10px.png diff --git a/applications/plugins/mousejacker/mousejacker.c b/applications/plugins/mousejacker/mousejacker.c index c45b0e502..3bd772889 100644 --- a/applications/plugins/mousejacker/mousejacker.c +++ b/applications/plugins/mousejacker/mousejacker.c @@ -112,7 +112,7 @@ static bool open_ducky_script(Stream* stream, PluginState* plugin_state) { DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options( - &browser_options, MOUSEJACKER_APP_PATH_EXTENSION, &I_badusb_10px); + &browser_options, MOUSEJACKER_APP_PATH_EXTENSION, &I_badkb_10px); browser_options.hide_ext = false; bool ret = dialog_file_browser_show(dialogs, path, path, &browser_options); @@ -396,4 +396,4 @@ int32_t mousejacker_app(void* p) { free(plugin_state); return 0; -} \ No newline at end of file +} diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index 7a57856e1..b3b04d836 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -291,7 +291,7 @@ static bool mj_process_ducky_line( strncmp(line_tmp, "CONTROL-SHIFT", strlen("CONTROL-SHIFT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 4 | 2, dk.hid, plugin_state); + send_hid_packet(handle, addr, addr_size, rate, dk.mod | 1 | 2, dk.hid, plugin_state); return true; } else if( strncmp(line_tmp, "CTRL", strlen("CTRL")) == 0 || diff --git a/applications/plugins/music_player/music_player_worker.c b/applications/plugins/music_player/music_player_worker.c index 60fd33a17..ee350ee80 100644 --- a/applications/plugins/music_player/music_player_worker.c +++ b/applications/plugins/music_player/music_player_worker.c @@ -6,6 +6,7 @@ #include #include +#include #include #define TAG "MusicPlayerWorker" diff --git a/applications/plugins/namechanger/application.fam b/applications/plugins/namechanger/application.fam index 545f0b905..704b643c5 100644 --- a/applications/plugins/namechanger/application.fam +++ b/applications/plugins/namechanger/application.fam @@ -4,10 +4,10 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="namechanger_app", cdefines=["APP_NAMECHANGER"], - requires=["gui","storage"], + requires=["gui", "storage"], stack_size=2 * 1024, order=90, fap_icon="namechanger_10px.png", fap_category="Tools", - fap_icon_assets="icons", -) \ No newline at end of file + fap_icon_assets="icons", +) diff --git a/applications/plugins/nfc_magic/application.fam b/applications/plugins/nfc_magic/application.fam index cc85cd386..427524051 100644 --- a/applications/plugins/nfc_magic/application.fam +++ b/applications/plugins/nfc_magic/application.fam @@ -2,6 +2,7 @@ App( appid="NFC_Magic", name="NFC Magic", apptype=FlipperAppType.EXTERNAL, + targets=["f7"], entry_point="nfc_magic_app", requires=[ "storage", diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c index 69bf9eb50..4b8089693 100644 --- a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c @@ -26,7 +26,7 @@ void nfc_magic_scene_wrong_card_on_enter(void* context) { AlignLeft, AlignTop, FontSecondary, - "Writing is supported\nonly for 4 bytes UID\nMifare CLassic 1k"); + "Writing is supported\nonly for 4 bytes UID\nMifare Classic 1k"); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wrong_card_widget_callback, nfc_magic); diff --git a/applications/plugins/nightstand/ClockIcon.png b/applications/plugins/nightstand/ClockIcon.png new file mode 100644 index 000000000..8a5406e6c Binary files /dev/null and b/applications/plugins/nightstand/ClockIcon.png differ diff --git a/applications/plugins/nightstand/application.fam b/applications/plugins/nightstand/application.fam new file mode 100644 index 000000000..0b8cbf83a --- /dev/null +++ b/applications/plugins/nightstand/application.fam @@ -0,0 +1,12 @@ +App( + appid="Nightstand", + name="Nightstand Clock", + apptype=FlipperAppType.EXTERNAL, + entry_point="clock_app", + requires=["gui"], + icon="A_Clock_14", + stack_size=2 * 1024, + fap_icon="ClockIcon.png", + fap_category="Misc", + order=81, +) diff --git a/applications/plugins/nightstand/clock_app.c b/applications/plugins/nightstand/clock_app.c new file mode 100644 index 000000000..d7a9f7faa --- /dev/null +++ b/applications/plugins/nightstand/clock_app.c @@ -0,0 +1,334 @@ +#include +#include + +#include +#include + +#include +#include + +#include "clock_app.h" + +/* + This is a modified version of the default clock app intended for use overnight + Up / Down control the displays brightness. Down at brightness 0 turns the notification LED on and off. +*/ + +int brightness = 5; +bool led = false; +NotificationApp* notif = 0; + +const NotificationMessage message_red_dim = { + .type = NotificationMessageTypeLedRed, + .data.led.value = 0xFF / 16, +}; + +const NotificationMessage message_red_off = { + .type = NotificationMessageTypeLedRed, + .data.led.value = 0x00, +}; + +static const NotificationSequence led_on = { + &message_red_dim, + &message_do_not_reset, + NULL, +}; + +static const NotificationSequence led_off = { + &message_red_off, + &message_do_not_reset, + NULL, +}; + +static const NotificationSequence led_reset = { + &message_red_0, + NULL, +}; + +void set_backlight_brightness(float brightness) { + notif->settings.display_brightness = brightness; + notification_message(notif, &sequence_display_backlight_on); +} + +void handle_up() { + if(brightness < 100) { + led = false; + notification_message(notif, &led_off); + brightness += 5; + } + set_backlight_brightness((float)(brightness / 100.f)); +} + +void handle_down() { + if(brightness > 0) { + brightness -= 5; + if(brightness == 0) { //trigger only on the first brightness 5 -> 0 transition + led = true; + notification_message(notif, &led_on); + } + } else if(brightness == 0) { //trigger on every down press afterwards + led = !led; + if(led) { + notification_message(notif, &led_on); + } else { + notification_message(notif, &led_off); + } + } + set_backlight_brightness((float)(brightness / 100.f)); +} + +static void clock_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { + furi_assert(event_queue); + PluginEvent event = {.type = EventTypeKey, .input = *input_event}; + furi_message_queue_put(event_queue, &event, FuriWaitForever); +} + +static void clock_render_callback(Canvas* const canvas, void* ctx) { + //canvas_clear(canvas); + //canvas_set_color(canvas, ColorBlack); + + //avoids a bug with the brightness being reverted after the backlight-off period + set_backlight_brightness((float)(brightness / 100.f)); + + ClockState* state = ctx; + if(furi_mutex_acquire(state->mutex, 200) != FuriStatusOk) { + //FURI_LOG_D(TAG, "Can't obtain mutex, requeue render"); + PluginEvent event = {.type = EventTypeTick}; + furi_message_queue_put(state->event_queue, &event, 0); + return; + } + + FuriHalRtcDateTime curr_dt; + furi_hal_rtc_get_datetime(&curr_dt); + uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt); + + char time_string[TIME_LEN]; + char date_string[DATE_LEN]; + char meridian_string[MERIDIAN_LEN]; + char timer_string[20]; + + if(state->time_format == LocaleTimeFormat24h) { + snprintf( + time_string, TIME_LEN, CLOCK_TIME_FORMAT, curr_dt.hour, curr_dt.minute, curr_dt.second); + } else { + bool pm = curr_dt.hour > 12; + bool pm12 = curr_dt.hour >= 12; + snprintf( + time_string, + TIME_LEN, + CLOCK_TIME_FORMAT, + pm ? curr_dt.hour - 12 : curr_dt.hour, + curr_dt.minute, + curr_dt.second); + + snprintf( + meridian_string, + MERIDIAN_LEN, + MERIDIAN_FORMAT, + pm12 ? MERIDIAN_STRING_PM : MERIDIAN_STRING_AM); + } + + if(state->date_format == LocaleDateFormatYMD) { + snprintf( + date_string, DATE_LEN, CLOCK_ISO_DATE_FORMAT, curr_dt.year, curr_dt.month, curr_dt.day); + } else if(state->date_format == LocaleDateFormatMDY) { + snprintf( + date_string, DATE_LEN, CLOCK_RFC_DATE_FORMAT, curr_dt.month, curr_dt.day, curr_dt.year); + } else { + snprintf( + date_string, DATE_LEN, CLOCK_RFC_DATE_FORMAT, curr_dt.day, curr_dt.month, curr_dt.year); + } + + bool timer_running = state->timer_running; + uint32_t timer_start_timestamp = state->timer_start_timestamp; + uint32_t timer_stopped_seconds = state->timer_stopped_seconds; + + furi_mutex_release(state->mutex); + + canvas_set_font(canvas, FontBigNumbers); + + if(timer_start_timestamp != 0) { + int32_t elapsed_secs = timer_running ? (curr_ts - timer_start_timestamp) : + timer_stopped_seconds; + snprintf(timer_string, 20, "%.2ld:%.2ld", elapsed_secs / 60, elapsed_secs % 60); + canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, time_string); // DRAW TIME + canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, timer_string); // DRAW TIMER + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignTop, date_string); // DRAW DATE + elements_button_left(canvas, "Reset"); + } else { + canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, time_string); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 65, 17, AlignCenter, AlignCenter, date_string); + + if(state->time_format == LocaleTimeFormat12h) + canvas_draw_str_aligned(canvas, 64, 47, AlignCenter, AlignCenter, meridian_string); + } + if(timer_running) { + elements_button_center(canvas, "Stop"); + } else if(timer_start_timestamp != 0 && !timer_running) { + elements_button_center(canvas, "Start"); + } +} + +static void clock_state_init(ClockState* const state) { + state->time_format = locale_get_time_format(); + + state->date_format = locale_get_date_format(); + + //FURI_LOG_D(TAG, "Time format: %s", state->settings.time_format == H12 ? "12h" : "24h"); + //FURI_LOG_D(TAG, "Date format: %s", state->settings.date_format == Iso ? "ISO 8601" : "RFC 5322"); + //furi_hal_rtc_get_datetime(&state->datetime); +} + +// Runs every 1000ms by default +static void clock_tick(void* ctx) { + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; + PluginEvent event = {.type = EventTypeTick}; + // It's OK to loose this event if system overloaded + furi_message_queue_put(event_queue, &event, 0); +} + +void timer_start_stop(ClockState* plugin_state) { + // START/STOP TIMER + FuriHalRtcDateTime curr_dt; + furi_hal_rtc_get_datetime(&curr_dt); + uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt); + + if(plugin_state->timer_running) { + // Update stopped seconds + plugin_state->timer_stopped_seconds = curr_ts - plugin_state->timer_start_timestamp; + } else { + if(plugin_state->timer_start_timestamp == 0) { + // Set starting timestamp if this is first time + plugin_state->timer_start_timestamp = curr_ts; + } else { + // Timer was already running, need to slightly readjust so we don't + // count the intervening time + plugin_state->timer_start_timestamp = curr_ts - plugin_state->timer_stopped_seconds; + } + } + plugin_state->timer_running = !plugin_state->timer_running; +} + +void timer_reset_seconds(ClockState* plugin_state) { + if(plugin_state->timer_start_timestamp != 0) { + // Reset seconds + plugin_state->timer_running = false; + plugin_state->timer_start_timestamp = 0; + plugin_state->timer_stopped_seconds = 0; + } +} + +int32_t clock_app(void* p) { + UNUSED(p); + ClockState* plugin_state = malloc(sizeof(ClockState)); + + plugin_state->event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); + if(plugin_state->event_queue == NULL) { + FURI_LOG_E(TAG, "Cannot create event queue"); + free(plugin_state); + return 255; + } + //FURI_LOG_D(TAG, "Event queue created"); + + plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + if(plugin_state->mutex == NULL) { + FURI_LOG_E(TAG, "Cannot create mutex"); + furi_message_queue_free(plugin_state->event_queue); + free(plugin_state); + return 255; + } + //FURI_LOG_D(TAG, "Mutex created"); + + clock_state_init(plugin_state); + + // Set system callbacks + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, clock_render_callback, plugin_state); + view_port_input_callback_set(view_port, clock_input_callback, plugin_state->event_queue); + + FuriTimer* timer = + furi_timer_alloc(clock_tick, FuriTimerTypePeriodic, plugin_state->event_queue); + + if(timer == NULL) { + FURI_LOG_E(TAG, "Cannot create timer"); + furi_mutex_free(plugin_state->mutex); + furi_message_queue_free(plugin_state->event_queue); + free(plugin_state); + return 255; + } + //FURI_LOG_D(TAG, "Timer created"); + + // Open GUI and register view_port + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + furi_timer_start(timer, furi_kernel_get_tick_frequency()); + //FURI_LOG_D(TAG, "Timer started"); + + notif = furi_record_open(RECORD_NOTIFICATION); + float tmpBrightness = notif->settings.display_brightness; + brightness = tmpBrightness * 100; + + notification_message(notif, &sequence_display_backlight_enforce_on); + notification_message(notif, &led_off); + + // Main loop + PluginEvent event; + for(bool processing = true; processing;) { + FuriStatus event_status = furi_message_queue_get(plugin_state->event_queue, &event, 100); + + if(event_status != FuriStatusOk) continue; + + if(furi_mutex_acquire(plugin_state->mutex, FuriWaitForever) != FuriStatusOk) continue; + // press events + if(event.type == EventTypeKey) { + if(event.input.type == InputTypeShort) { + switch(event.input.key) { + case InputKeyLeft: + // Reset seconds + timer_reset_seconds(plugin_state); + break; + case InputKeyOk: + // Toggle timer + timer_start_stop(plugin_state); + break; + case InputKeyBack: + // Exit the plugin + processing = false; + break; + case InputKeyUp: + handle_up(); + break; + case InputKeyDown: + handle_down(); + break; + default: + break; + } + } + } /*else if(event.type == EventTypeTick) { + furi_hal_rtc_get_datetime(&plugin_state->datetime); + }*/ + + view_port_update(view_port); + furi_mutex_release(plugin_state->mutex); + } + + furi_timer_free(timer); + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + furi_record_close(RECORD_GUI); + view_port_free(view_port); + furi_message_queue_free(plugin_state->event_queue); + furi_mutex_free(plugin_state->mutex); + free(plugin_state); + + set_backlight_brightness(tmpBrightness); + notification_message(notif, &sequence_display_backlight_enforce_auto); + notification_message(notif, &led_reset); + + return 0; +} diff --git a/applications/plugins/nightstand/clock_app.h b/applications/plugins/nightstand/clock_app.h new file mode 100644 index 000000000..693bdfac0 --- /dev/null +++ b/applications/plugins/nightstand/clock_app.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#define TAG "Clock" + +#define CLOCK_ISO_DATE_FORMAT "%.4d-%.2d-%.2d" +#define CLOCK_RFC_DATE_FORMAT "%.2d-%.2d-%.4d" +#define CLOCK_TIME_FORMAT "%.2d:%.2d:%.2d" + +#define MERIDIAN_FORMAT "%s" +#define MERIDIAN_STRING_AM "AM" +#define MERIDIAN_STRING_PM "PM" + +#define TIME_LEN 12 +#define DATE_LEN 14 +#define MERIDIAN_LEN 3 + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + EventType type; + InputEvent input; +} PluginEvent; + +typedef struct { + LocaleDateFormat date_format; + LocaleTimeFormat time_format; + FuriHalRtcDateTime datetime; + FuriMutex* mutex; + FuriMessageQueue* event_queue; + uint32_t timer_start_timestamp; + uint32_t timer_stopped_seconds; + bool timer_running; +} ClockState; diff --git a/applications/plugins/orgasmotron/orgasmotron.c b/applications/plugins/orgasmotron/orgasmotron.c index b28f392f5..684fc3d95 100644 --- a/applications/plugins/orgasmotron/orgasmotron.c +++ b/applications/plugins/orgasmotron/orgasmotron.c @@ -40,7 +40,7 @@ int32_t orgasmotron_app(void* p) { PluginState* plugin_state = malloc(sizeof(PluginState)); ValueMutex state_mutex; - if (!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) { + if(!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) { FURI_LOG_E("Orgasmatron", "cannot create mutex\r\n"); free(plugin_state); return 255; @@ -61,10 +61,10 @@ int32_t orgasmotron_app(void* p) { //int mode = 0; bool processing = true; //while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { - while (processing) { + while(processing) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex); - if (event_status == FuriStatusOk) { + if(event_status == FuriStatusOk) { if(event.key == InputKeyBack && event.type == InputTypeShort) { //Exit Application notification_message(notification, &sequence_reset_vibro); @@ -73,53 +73,58 @@ int32_t orgasmotron_app(void* p) { processing = false; //break; } - if(event.key == InputKeyOk && (event.type == InputTypePress || event.type == InputTypeRelease)) { + if(event.key == InputKeyOk && + (event.type == InputTypePress || event.type == InputTypeRelease)) { plugin_state->mode = 0; } - if(event.key == InputKeyLeft && (event.type == InputTypePress || event.type == InputTypeRelease)) { + if(event.key == InputKeyLeft && + (event.type == InputTypePress || event.type == InputTypeRelease)) { plugin_state->mode = 1; } - if(event.key == InputKeyRight && (event.type == InputTypePress || event.type == InputTypeRelease)) { + if(event.key == InputKeyRight && + (event.type == InputTypePress || event.type == InputTypeRelease)) { plugin_state->mode = 3; } - if(event.key == InputKeyUp && (event.type == InputTypePress || event.type == InputTypeRelease)) { + if(event.key == InputKeyUp && + (event.type == InputTypePress || event.type == InputTypeRelease)) { plugin_state->mode = 2; } - if(event.key == InputKeyDown && (event.type == InputTypePress || event.type == InputTypeRelease)) { + if(event.key == InputKeyDown && + (event.type == InputTypePress || event.type == InputTypeRelease)) { plugin_state->mode = 4; } } - - if (plugin_state->mode == 0) { + + if(plugin_state->mode == 0) { //Stop Vibration notification_message(notification, &sequence_reset_vibro); notification_message(notification, &sequence_reset_green); - } else if (plugin_state->mode == 1) { + } else if(plugin_state->mode == 1) { //Full power notification_message(notification, &sequence_set_vibro_on); notification_message(notification, &sequence_set_green_255); - } else if (plugin_state->mode == 2) { + } else if(plugin_state->mode == 2) { //Pulsed Vibration notification_message(notification, &sequence_set_vibro_on); notification_message(notification, &sequence_set_green_255); delay(100); notification_message(notification, &sequence_reset_vibro); - } else if (plugin_state->mode == 3) { + } else if(plugin_state->mode == 3) { //Soft power notification_message(notification, &sequence_set_vibro_on); notification_message(notification, &sequence_set_green_255); delay(50); notification_message(notification, &sequence_reset_vibro); - } else if (plugin_state->mode == 4) { + } else if(plugin_state->mode == 4) { //Special Sequence - for (int i = 0;i < 15;i++) { + for(int i = 0; i < 15; i++) { notification_message(notification, &sequence_set_vibro_on); notification_message(notification, &sequence_set_green_255); delay(50); notification_message(notification, &sequence_reset_vibro); delay(50); } - for (int i = 0;i < 2;i++) { + for(int i = 0; i < 2; i++) { notification_message(notification, &sequence_set_vibro_on); notification_message(notification, &sequence_set_green_255); delay(400); diff --git a/applications/plugins/orgasmotron/orgasmotron.fap b/applications/plugins/orgasmotron/orgasmotron.fap deleted file mode 100644 index 23d7bebb3..000000000 Binary files a/applications/plugins/orgasmotron/orgasmotron.fap and /dev/null differ diff --git a/applications/plugins/paint/application.fam b/applications/plugins/paint/application.fam index 0630abbce..d727ab2d2 100644 --- a/applications/plugins/paint/application.fam +++ b/applications/plugins/paint/application.fam @@ -9,4 +9,4 @@ App( order=175, fap_icon="paintIcon.png", fap_category="Misc", -) \ No newline at end of file +) diff --git a/applications/plugins/passgen/application.fam b/applications/plugins/passgen/application.fam index 78d810a1d..94005e716 100644 --- a/applications/plugins/passgen/application.fam +++ b/applications/plugins/passgen/application.fam @@ -9,4 +9,4 @@ App( fap_category="Tools", fap_icon="icons/passgen_icon.png", fap_icon_assets="icons", -) \ No newline at end of file +) diff --git a/applications/plugins/picopass/application.fam b/applications/plugins/picopass/application.fam index 6cec00d8d..5d331e708 100644 --- a/applications/plugins/picopass/application.fam +++ b/applications/plugins/picopass/application.fam @@ -2,6 +2,7 @@ App( appid="Picopass", name="PicoPass Reader", apptype=FlipperAppType.EXTERNAL, + targets=["f7"], entry_point="picopass_app", requires=[ "storage", diff --git a/applications/plugins/pomodoro/application.fam b/applications/plugins/pomodoro/application.fam new file mode 100644 index 000000000..ceb8cccc9 --- /dev/null +++ b/applications/plugins/pomodoro/application.fam @@ -0,0 +1,12 @@ +App( + appid="Pomodoro", + name="Pomodoro", + apptype=FlipperAppType.EXTERNAL, + entry_point="flipp_pomodoro_app", + requires=["gui", "notification", "dolphin"], + stack_size=1 * 1024, + fap_category="Tools", + fap_icon_assets="images", + fap_icon="flipp_pomodoro_10.png", + fap_icon_assets_symbol="flipp_pomodoro", +) diff --git a/applications/plugins/pomodoro/flipp_pomodoro_10.png b/applications/plugins/pomodoro/flipp_pomodoro_10.png new file mode 100644 index 000000000..977d16a58 Binary files /dev/null and b/applications/plugins/pomodoro/flipp_pomodoro_10.png differ diff --git a/applications/plugins/pomodoro/flipp_pomodoro_app.c b/applications/plugins/pomodoro/flipp_pomodoro_app.c new file mode 100644 index 000000000..ed5b8282b --- /dev/null +++ b/applications/plugins/pomodoro/flipp_pomodoro_app.c @@ -0,0 +1,101 @@ +#include "flipp_pomodoro_app_i.h" + +enum { + CustomEventConsumed = true, + CustomEventNotConsumed = false, +}; + +static bool flipp_pomodoro_app_back_event_callback(void* ctx) { + furi_assert(ctx); + FlippPomodoroApp* app = ctx; + return scene_manager_handle_back_event(app->scene_manager); +}; + +static void flipp_pomodoro_app_tick_event_callback(void* ctx) { + furi_assert(ctx); + FlippPomodoroApp* app = ctx; + + scene_manager_handle_custom_event(app->scene_manager, FlippPomodoroAppCustomEventTimerTick); +}; + +static bool flipp_pomodoro_app_custom_event_callback(void* ctx, uint32_t event) { + furi_assert(ctx); + FlippPomodoroApp* app = ctx; + + switch(event) { + case FlippPomodoroAppCustomEventStageSkip: + flipp_pomodoro__toggle_stage(app->state); + view_dispatcher_send_custom_event( + app->view_dispatcher, FlippPomodoroAppCustomEventStateUpdated); + return CustomEventConsumed; + case FlippPomodoroAppCustomEventStageComplete: + if(flipp_pomodoro__get_stage(app->state) == FlippPomodoroStageFocus) { + // REGISTER a deed on work stage complete to get an acheivement + DOLPHIN_DEED(DolphinDeedPluginGameWin); + }; + + flipp_pomodoro__toggle_stage(app->state); + notification_message( + app->notification_app, + stage_start_notification_sequence_map[flipp_pomodoro__get_stage(app->state)]); + view_dispatcher_send_custom_event( + app->view_dispatcher, FlippPomodoroAppCustomEventStateUpdated); + return CustomEventConsumed; + default: + break; + } + return scene_manager_handle_custom_event(app->scene_manager, event); +}; + +FlippPomodoroApp* flipp_pomodoro_app_alloc() { + FlippPomodoroApp* app = malloc(sizeof(FlippPomodoroApp)); + app->state = flipp_pomodoro__new(); + + app->scene_manager = scene_manager_alloc(&flipp_pomodoro_scene_handlers, app); + app->gui = furi_record_open(RECORD_GUI); + app->notification_app = furi_record_open(RECORD_NOTIFICATION); + + app->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, flipp_pomodoro_app_custom_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, flipp_pomodoro_app_tick_event_callback, 1000); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, flipp_pomodoro_app_back_event_callback); + + app->timer_view = flipp_pomodoro_view_timer_alloc(); + + view_dispatcher_add_view( + app->view_dispatcher, + FlippPomodoroAppViewTimer, + flipp_pomodoro_view_timer_get_view(app->timer_view)); + + scene_manager_next_scene(app->scene_manager, FlippPomodoroSceneTimer); + + return app; +}; + +void flipp_pomodoro_app_free(FlippPomodoroApp* app) { + view_dispatcher_remove_view(app->view_dispatcher, FlippPomodoroAppViewTimer); + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + flipp_pomodoro_view_timer_free(app->timer_view); + flipp_pomodoro__destroy(app->state); + free(app); + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); +}; + +int32_t flipp_pomodoro_app(void* p) { + UNUSED(p); + FlippPomodoroApp* app = flipp_pomodoro_app_alloc(); + + view_dispatcher_run(app->view_dispatcher); + + flipp_pomodoro_app_free(app); + + return 0; +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/flipp_pomodoro_app.h b/applications/plugins/pomodoro/flipp_pomodoro_app.h new file mode 100644 index 000000000..54102e1f3 --- /dev/null +++ b/applications/plugins/pomodoro/flipp_pomodoro_app.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "views/flipp_pomodoro_timer_view.h" + +#include "modules/flipp_pomodoro.h" + +typedef enum { + // Reserve first 100 events for button types and indexes, starting from 0 + FlippPomodoroAppCustomEventStageSkip = 100, + FlippPomodoroAppCustomEventStageComplete, // By Expiration + FlippPomodoroAppCustomEventTimerTick, + FlippPomodoroAppCustomEventStateUpdated, +} FlippPomodoroAppCustomEvent; + +typedef struct { + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notification_app; + FlippPomodoroTimerView* timer_view; + FlippPomodoroState* state; +} FlippPomodoroApp; + +typedef enum { + FlippPomodoroAppViewTimer, +} FlippPomodoroAppView; \ No newline at end of file diff --git a/applications/plugins/pomodoro/flipp_pomodoro_app_i.h b/applications/plugins/pomodoro/flipp_pomodoro_app_i.h new file mode 100644 index 000000000..492ef9c2d --- /dev/null +++ b/applications/plugins/pomodoro/flipp_pomodoro_app_i.h @@ -0,0 +1,31 @@ +#pragma once + +#define FURI_DEBUG 1 + +/** + * Index of dependencies for the main app + */ + +// Platform Imports + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// App resource imports + +#include "helpers/time.h" +#include "helpers/notifications.h" +#include "modules/flipp_pomodoro.h" +#include "flipp_pomodoro_app.h" +#include "scenes/flipp_pomodoro_scene.h" +#include "views/flipp_pomodoro_timer_view.h" + +// Auto-compiled icons +#include "flipp_pomodoro_icons.h" diff --git a/applications/plugins/pomodoro/helpers/debug.h b/applications/plugins/pomodoro/helpers/debug.h new file mode 100644 index 000000000..13b8f2998 --- /dev/null +++ b/applications/plugins/pomodoro/helpers/debug.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +#define TAG "FlippPomodoro" \ No newline at end of file diff --git a/applications/plugins/pomodoro/helpers/notifications.c b/applications/plugins/pomodoro/helpers/notifications.c new file mode 100644 index 000000000..388a3f11d --- /dev/null +++ b/applications/plugins/pomodoro/helpers/notifications.c @@ -0,0 +1,49 @@ +#include + +const NotificationSequence work_start_notification = { + &message_display_backlight_on, + + &message_vibro_on, + + &message_note_b5, + &message_delay_250, + + &message_note_d5, + &message_delay_250, + + &message_sound_off, + &message_vibro_off, + + &message_green_255, + &message_delay_1000, + &message_green_0, + &message_delay_250, + &message_green_255, + &message_delay_1000, + + NULL, +}; + +const NotificationSequence rest_start_notification = { + &message_display_backlight_on, + + &message_vibro_on, + + &message_note_d5, + &message_delay_250, + + &message_note_b5, + &message_delay_250, + + &message_sound_off, + &message_vibro_off, + + &message_red_255, + &message_delay_1000, + &message_red_0, + &message_delay_250, + &message_red_255, + &message_delay_1000, + + NULL, +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/helpers/notifications.h b/applications/plugins/pomodoro/helpers/notifications.h new file mode 100644 index 000000000..c6cd0428f --- /dev/null +++ b/applications/plugins/pomodoro/helpers/notifications.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../modules/flipp_pomodoro.h" +#include + +extern const NotificationSequence work_start_notification; +extern const NotificationSequence rest_start_notification; + +/// @brief Defines a notification sequence that should indicate start of specific pomodoro stage. +const NotificationSequence* stage_start_notification_sequence_map[] = { + [FlippPomodoroStageFocus] = &work_start_notification, + [FlippPomodoroStageRest] = &rest_start_notification, + [FlippPomodoroStageLongBreak] = &rest_start_notification, +}; diff --git a/applications/plugins/pomodoro/helpers/time.c b/applications/plugins/pomodoro/helpers/time.c new file mode 100644 index 000000000..7fb0d13c2 --- /dev/null +++ b/applications/plugins/pomodoro/helpers/time.c @@ -0,0 +1,20 @@ +#include +#include +#include "time.h" + +const int TIME_SECONDS_IN_MINUTE = 60; +const int TIME_MINUTES_IN_HOUR = 60; + +uint32_t time_now() { + return furi_hal_rtc_get_timestamp(); +}; + +TimeDifference time_difference_seconds(uint32_t begin, uint32_t end) { + const uint32_t duration_seconds = end - begin; + + uint32_t minutes = (duration_seconds / TIME_MINUTES_IN_HOUR) % TIME_MINUTES_IN_HOUR; + uint32_t seconds = duration_seconds % TIME_SECONDS_IN_MINUTE; + + return ( + TimeDifference){.total_seconds = duration_seconds, .minutes = minutes, .seconds = seconds}; +}; diff --git a/applications/plugins/pomodoro/helpers/time.h b/applications/plugins/pomodoro/helpers/time.h new file mode 100644 index 000000000..7a7d90bf2 --- /dev/null +++ b/applications/plugins/pomodoro/helpers/time.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +extern const int TIME_SECONDS_IN_MINUTE; +extern const int TIME_MINUTES_IN_HOUR; + +/// @brief Container for a time period +typedef struct { + uint8_t seconds; + uint8_t minutes; + uint32_t total_seconds; +} TimeDifference; + +/// @brief Time by the moment of calling +/// @return A timestamp(seconds percision) +uint32_t time_now(); + +/// @brief Calculates difference between two provided timestamps +/// @param begin - start timestamp of the period +/// @param end - end timestamp of the period to measure +/// @return TimeDifference struct +TimeDifference time_difference_seconds(uint32_t begin, uint32_t end); diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_00.png b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_00.png new file mode 100644 index 000000000..7ead27c4e Binary files /dev/null and b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_00.png differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_01.png b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_01.png new file mode 100644 index 000000000..0e36886f2 Binary files /dev/null and b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_01.png differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_rate b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_rate new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_rate @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_00.png b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_00.png new file mode 100644 index 000000000..072affef3 Binary files /dev/null and b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_00.png differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_01.png b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_01.png new file mode 100644 index 000000000..cf6358658 Binary files /dev/null and b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_01.png differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_rate b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_rate new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_rate @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/applications/plugins/pomodoro/modules/flipp_pomodoro.c b/applications/plugins/pomodoro/modules/flipp_pomodoro.c new file mode 100644 index 000000000..9915025fb --- /dev/null +++ b/applications/plugins/pomodoro/modules/flipp_pomodoro.c @@ -0,0 +1,94 @@ +#include +#include +#include "../helpers/time.h" +#include "flipp_pomodoro.h" + +PomodoroStage stages_sequence[] = { + FlippPomodoroStageFocus, + FlippPomodoroStageRest, + + FlippPomodoroStageFocus, + FlippPomodoroStageRest, + + FlippPomodoroStageFocus, + FlippPomodoroStageRest, + + FlippPomodoroStageFocus, + FlippPomodoroStageLongBreak, +}; + +char* current_stage_label[] = { + [FlippPomodoroStageFocus] = "Continue focus for:", + [FlippPomodoroStageRest] = "Keep rest for:", + [FlippPomodoroStageLongBreak] = "Long Break for:", +}; + +char* next_stage_label[] = { + [FlippPomodoroStageFocus] = "Focus", + [FlippPomodoroStageRest] = "Short Break", + [FlippPomodoroStageLongBreak] = "Long Break", +}; + +PomodoroStage flipp_pomodoro__stage_by_index(int index) { + const int one_loop_size = sizeof(stages_sequence); + return stages_sequence[index % one_loop_size]; +} + +void flipp_pomodoro__toggle_stage(FlippPomodoroState* state) { + furi_assert(state); + state->current_stage_index = state->current_stage_index + 1; + state->started_at_timestamp = time_now(); +}; + +PomodoroStage flipp_pomodoro__get_stage(FlippPomodoroState* state) { + furi_assert(state); + return flipp_pomodoro__stage_by_index(state->current_stage_index); +}; + +char* flipp_pomodoro__current_stage_label(FlippPomodoroState* state) { + furi_assert(state); + return current_stage_label[flipp_pomodoro__get_stage(state)]; +}; + +char* flipp_pomodoro__next_stage_label(FlippPomodoroState* state) { + furi_assert(state); + return next_stage_label[flipp_pomodoro__stage_by_index(state->current_stage_index + 1)]; +}; + +void flipp_pomodoro__destroy(FlippPomodoroState* state) { + furi_assert(state); + free(state); +}; + +uint32_t flipp_pomodoro__current_stage_total_duration(FlippPomodoroState* state) { + const int32_t stage_duration_seconds_map[] = { + [FlippPomodoroStageFocus] = 25 * TIME_SECONDS_IN_MINUTE, + [FlippPomodoroStageRest] = 5 * TIME_SECONDS_IN_MINUTE, + [FlippPomodoroStageLongBreak] = 30 * TIME_SECONDS_IN_MINUTE, + }; + + return stage_duration_seconds_map[flipp_pomodoro__get_stage(state)]; +}; + +uint32_t flipp_pomodoro__stage_expires_timestamp(FlippPomodoroState* state) { + return state->started_at_timestamp + flipp_pomodoro__current_stage_total_duration(state); +}; + +TimeDifference flipp_pomodoro__stage_remaining_duration(FlippPomodoroState* state) { + const uint32_t stage_ends_at = flipp_pomodoro__stage_expires_timestamp(state); + return time_difference_seconds(time_now(), stage_ends_at); +}; + +bool flipp_pomodoro__is_stage_expired(FlippPomodoroState* state) { + const uint32_t expired_by = flipp_pomodoro__stage_expires_timestamp(state); + const uint8_t seamless_change_span_seconds = 1; + return (time_now() - seamless_change_span_seconds) >= expired_by; +}; + +FlippPomodoroState* flipp_pomodoro__new() { + FlippPomodoroState* state = malloc(sizeof(FlippPomodoroState)); + const uint32_t now = time_now(); + state->started_at_timestamp = now; + state->current_stage_index = 0; + return state; +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/modules/flipp_pomodoro.h b/applications/plugins/pomodoro/modules/flipp_pomodoro.h new file mode 100644 index 000000000..251a77469 --- /dev/null +++ b/applications/plugins/pomodoro/modules/flipp_pomodoro.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include "../helpers/time.h" + +/// @brief Options of pomodoro stages +typedef enum { + FlippPomodoroStageFocus, + FlippPomodoroStageRest, + FlippPomodoroStageLongBreak, +} PomodoroStage; + +/// @brief State of the pomodoro timer +typedef struct { + PomodoroStage stage; + uint8_t current_stage_index; + uint32_t started_at_timestamp; +} FlippPomodoroState; + +/// @brief Generates initial state +/// @returns A new pre-populated state for pomodoro timer +FlippPomodoroState* flipp_pomodoro__new(); + +/// @brief Extract current stage of pomodoro +/// @param state - pointer to the state of pomorodo +/// @returns Current stage value +PomodoroStage flipp_pomodoro__get_stage(FlippPomodoroState* state); + +/// @brief Destroys state of timer and it's dependencies +void flipp_pomodoro__destroy(FlippPomodoroState* state); + +/// @brief Get remaining stage time. +/// @param state - pointer to the state of pomorodo +/// @returns Time difference to the end of current stage +TimeDifference flipp_pomodoro__stage_remaining_duration(FlippPomodoroState* state); + +/// @brief Label of currently active stage +/// @param state - pointer to the state of pomorodo +/// @returns A string that explains current stage +char* flipp_pomodoro__current_stage_label(FlippPomodoroState* state); + +/// @brief Label of transition to the next stage +/// @param state - pointer to the state of pomorodo. +/// @returns string with the label of the "skipp" button +char* flipp_pomodoro__next_stage_label(FlippPomodoroState* state); + +/// @brief Check if current stage is expired +/// @param state - pointer to the state of pomorodo. +/// @returns expriations status - true means stage is expired +bool flipp_pomodoro__is_stage_expired(FlippPomodoroState* state); + +/// @brief Rotate stage of the timer +/// @param state - pointer to the state of pomorodo. +void flipp_pomodoro__toggle_stage(FlippPomodoroState* state); diff --git a/applications/plugins/pomodoro/scenes/.keep b/applications/plugins/pomodoro/scenes/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/applications/plugins/pomodoro/scenes/config/flipp_pomodoro_scene_config.h b/applications/plugins/pomodoro/scenes/config/flipp_pomodoro_scene_config.h new file mode 100644 index 000000000..f95daeb30 --- /dev/null +++ b/applications/plugins/pomodoro/scenes/config/flipp_pomodoro_scene_config.h @@ -0,0 +1 @@ +ADD_SCENE(flipp_pomodoro, timer, Timer) \ No newline at end of file diff --git a/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.c b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.c new file mode 100644 index 000000000..5856ac947 --- /dev/null +++ b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.c @@ -0,0 +1,30 @@ +#include "flipp_pomodoro_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const flipp_pomodoro_scene_on_enter_handlers[])(void*) = { +#include "config/flipp_pomodoro_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const flipp_pomodoro_scene_on_event_handlers[])(void* ctx, SceneManagerEvent event) = { +#include "config/flipp_pomodoro_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const flipp_pomodoro_scene_on_exit_handlers[])(void* ctx) = { +#include "config/flipp_pomodoro_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers flipp_pomodoro_scene_handlers = { + .on_enter_handlers = flipp_pomodoro_scene_on_enter_handlers, + .on_event_handlers = flipp_pomodoro_scene_on_event_handlers, + .on_exit_handlers = flipp_pomodoro_scene_on_exit_handlers, + .scene_num = FlippPomodoroSceneNum, +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.h b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.h new file mode 100644 index 000000000..3b8a9052a --- /dev/null +++ b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.h @@ -0,0 +1,27 @@ +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) FlippPomodoroScene##id, +typedef enum { +#include "config/flipp_pomodoro_scene_config.h" + FlippPomodoroSceneNum, +} FlippPomodoroScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers flipp_pomodoro_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "config/flipp_pomodoro_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* ctx, SceneManagerEvent event); +#include "config/flipp_pomodoro_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* ctx); +#include "config/flipp_pomodoro_scene_config.h" +#undef ADD_SCENE diff --git a/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene_timer.c b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene_timer.c new file mode 100644 index 000000000..2190dbdb7 --- /dev/null +++ b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene_timer.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include "../flipp_pomodoro_app.h" +#include "../views/flipp_pomodoro_timer_view.h" + +enum { SceneEventConusmed = true, SceneEventNotConusmed = false }; + +uint8_t ExitSignal = 0; + +void flipp_pomodoro_scene_timer_sync_view_state(void* ctx) { + furi_assert(ctx); + + FlippPomodoroApp* app = ctx; + + flipp_pomodoro_view_timer_set_state( + flipp_pomodoro_view_timer_get_view(app->timer_view), app->state); +}; + +void flipp_pomodoro_scene_timer_on_next_stage(void* ctx) { + furi_assert(ctx); + + FlippPomodoroApp* app = ctx; + + view_dispatcher_send_custom_event(app->view_dispatcher, FlippPomodoroAppCustomEventStageSkip); +}; + +void flipp_pomodoro_scene_timer_on_enter(void* ctx) { + furi_assert(ctx); + + FlippPomodoroApp* app = ctx; + + view_dispatcher_switch_to_view(app->view_dispatcher, FlippPomodoroAppViewTimer); + flipp_pomodoro_scene_timer_sync_view_state(app); + flipp_pomodoro_view_timer_set_on_right_cb( + app->timer_view, flipp_pomodoro_scene_timer_on_next_stage, app); +}; + +void flipp_pomodoro_scene_timer_handle_custom_event( + FlippPomodoroApp* app, + FlippPomodoroAppCustomEvent custom_event) { + if(custom_event == FlippPomodoroAppCustomEventTimerTick && + flipp_pomodoro__is_stage_expired(app->state)) { + view_dispatcher_send_custom_event( + app->view_dispatcher, FlippPomodoroAppCustomEventStageComplete); + } + + if(custom_event == FlippPomodoroAppCustomEventStateUpdated) { + flipp_pomodoro_scene_timer_sync_view_state(app); + } +}; + +bool flipp_pomodoro_scene_timer_on_event(void* ctx, SceneManagerEvent event) { + furi_assert(ctx); + FlippPomodoroApp* app = ctx; + + switch(event.type) { + case SceneManagerEventTypeCustom: + flipp_pomodoro_scene_timer_handle_custom_event(app, event.event); + return SceneEventConusmed; + case SceneManagerEventTypeBack: + return ExitSignal; + default: + break; + }; + return SceneEventNotConusmed; +}; + +void flipp_pomodoro_scene_timer_on_exit(void* ctx) { + UNUSED(ctx); +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/views/.keep b/applications/plugins/pomodoro/views/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.c b/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.c new file mode 100644 index 000000000..e8e0383b7 --- /dev/null +++ b/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.c @@ -0,0 +1,195 @@ +#include "flipp_pomodoro_timer_view.h" +#include +#include +#include +#include +#include "../helpers/debug.h" +#include "../flipp_pomodoro_app.h" +#include "../modules/flipp_pomodoro.h" + +// Auto-compiled icons +#include "flipp_pomodoro_icons.h" + +enum { + ViewInputConsumed = true, + ViewInputNotConusmed = false, +}; + +struct FlippPomodoroTimerView { + View* view; + FlippPomodoroTimerViewInputCb right_cb; + void* right_cb_ctx; +}; + +typedef struct { + IconAnimation* icon; + FlippPomodoroState* state; +} FlippPomodoroTimerViewModel; + +static const Icon* stage_background_image[] = { + [FlippPomodoroStageFocus] = &A_flipp_pomodoro_focus_64, + [FlippPomodoroStageRest] = &A_flipp_pomodoro_rest_64, + [FlippPomodoroStageLongBreak] = &A_flipp_pomodoro_rest_64, +}; + +static void + flipp_pomodoro_view_timer_draw_countdown(Canvas* canvas, TimeDifference remaining_time) { + canvas_set_font(canvas, FontBigNumbers); + const uint8_t right_border_margin = 1; + + const uint8_t countdown_box_height = canvas_height(canvas) * 0.4; + const uint8_t countdown_box_width = canvas_width(canvas) * 0.5; + const uint8_t countdown_box_x = + canvas_width(canvas) - countdown_box_width - right_border_margin; + const uint8_t countdown_box_y = 15; + + elements_bold_rounded_frame( + canvas, countdown_box_x, countdown_box_y, countdown_box_width, countdown_box_height); + + FuriString* timer_string = furi_string_alloc(); + furi_string_printf(timer_string, "%02u:%02u", remaining_time.minutes, remaining_time.seconds); + const char* remaining_stage_time_string = furi_string_get_cstr(timer_string); + canvas_draw_str_aligned( + canvas, + countdown_box_x + (countdown_box_width / 2), + countdown_box_y + (countdown_box_height / 2), + AlignCenter, + AlignCenter, + remaining_stage_time_string); + + furi_string_free(timer_string); +}; + +static void draw_str_with_drop_shadow( + Canvas* canvas, + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + const char* str) { + canvas_set_color(canvas, ColorWhite); + for(int x_off = -2; x_off <= 2; x_off++) { + for(int y_off = -2; y_off <= 2; y_off++) { + canvas_draw_str_aligned(canvas, x + x_off, y + y_off, horizontal, vertical, str); + } + } + canvas_set_color(canvas, ColorBlack); + canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, str); +} + +static void + flipp_pomodoro_view_timer_draw_current_stage_label(Canvas* canvas, FlippPomodoroState* state) { + canvas_set_font(canvas, FontPrimary); + draw_str_with_drop_shadow( + canvas, + canvas_width(canvas), + 0, + AlignRight, + AlignTop, + flipp_pomodoro__current_stage_label(state)); +} + +static void flipp_pomodoro_view_timer_draw_callback(Canvas* canvas, void* _model) { + if(!_model) { + return; + }; + + FlippPomodoroTimerViewModel* model = _model; + + canvas_clear(canvas); + if(model->icon) { + canvas_draw_icon_animation(canvas, 0, 0, model->icon); + } + + flipp_pomodoro_view_timer_draw_countdown( + canvas, flipp_pomodoro__stage_remaining_duration(model->state)); + + flipp_pomodoro_view_timer_draw_current_stage_label(canvas, model->state); + canvas_set_color(canvas, ColorBlack); + + canvas_set_font(canvas, FontSecondary); + elements_button_right(canvas, flipp_pomodoro__next_stage_label(model->state)); +}; + +bool flipp_pomodoro_view_timer_input_callback(InputEvent* event, void* ctx) { + furi_assert(ctx); + furi_assert(event); + FlippPomodoroTimerView* timer = ctx; + + const bool should_trigger_right_event_cb = (event->type == InputTypePress) && + (event->key == InputKeyRight) && + (timer->right_cb != NULL); + + if(should_trigger_right_event_cb) { + furi_assert(timer->right_cb); + furi_assert(timer->right_cb_ctx); + timer->right_cb(timer->right_cb_ctx); + return ViewInputConsumed; + }; + + return ViewInputNotConusmed; +}; + +View* flipp_pomodoro_view_timer_get_view(FlippPomodoroTimerView* timer) { + furi_assert(timer); + return timer->view; +}; + +void flipp_pomodoro_view_timer_assign_animation(View* view) { + with_view_model( + view, + FlippPomodoroTimerViewModel * model, + { + furi_assert(model->state); + if(model->icon) { + icon_animation_free(model->icon); + } + model->icon = icon_animation_alloc( + stage_background_image[flipp_pomodoro__get_stage(model->state)]); + view_tie_icon_animation(view, model->icon); + icon_animation_start(model->icon); + }, + true); +} + +FlippPomodoroTimerView* flipp_pomodoro_view_timer_alloc() { + FlippPomodoroTimerView* timer = malloc(sizeof(FlippPomodoroTimerView)); + timer->view = view_alloc(); + + view_allocate_model(timer->view, ViewModelTypeLockFree, sizeof(FlippPomodoroTimerViewModel)); + view_set_context(flipp_pomodoro_view_timer_get_view(timer), timer); + view_set_draw_callback(timer->view, flipp_pomodoro_view_timer_draw_callback); + view_set_input_callback(timer->view, flipp_pomodoro_view_timer_input_callback); + + return timer; +}; + +void flipp_pomodoro_view_timer_set_on_right_cb( + FlippPomodoroTimerView* timer, + FlippPomodoroTimerViewInputCb right_cb, + void* right_cb_ctx) { + furi_assert(right_cb); + furi_assert(right_cb_ctx); + timer->right_cb = right_cb; + timer->right_cb_ctx = right_cb_ctx; +}; + +void flipp_pomodoro_view_timer_set_state(View* view, FlippPomodoroState* state) { + furi_assert(view); + furi_assert(state); + with_view_model( + view, FlippPomodoroTimerViewModel * model, { model->state = state; }, false); + flipp_pomodoro_view_timer_assign_animation(view); +}; + +void flipp_pomodoro_view_timer_free(FlippPomodoroTimerView* timer) { + furi_assert(timer); + with_view_model( + timer->view, + FlippPomodoroTimerViewModel * model, + { icon_animation_free(model->icon); }, + false); + view_free(timer->view); + + free(timer); +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.h b/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.h new file mode 100644 index 000000000..929a0eba3 --- /dev/null +++ b/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "../modules/flipp_pomodoro.h" + +typedef struct FlippPomodoroTimerView FlippPomodoroTimerView; + +typedef void (*FlippPomodoroTimerViewInputCb)(void* ctx); + +FlippPomodoroTimerView* flipp_pomodoro_view_timer_alloc(); + +View* flipp_pomodoro_view_timer_get_view(FlippPomodoroTimerView* timer); + +void flipp_pomodoro_view_timer_free(FlippPomodoroTimerView* timer); + +void flipp_pomodoro_view_timer_set_state(View* view, FlippPomodoroState* state); + +void flipp_pomodoro_view_timer_set_on_right_cb( + FlippPomodoroTimerView* timer, + FlippPomodoroTimerViewInputCb right_cb, + void* right_cb_ctx); diff --git a/applications/plugins/protoview/app.c b/applications/plugins/protoview/app.c index f16457e55..4765da9e3 100644 --- a/applications/plugins/protoview/app.c +++ b/applications/plugins/protoview/app.c @@ -40,8 +40,8 @@ extern const SubGhzProtocolRegistry protoview_protocol_registry; /* The callback actually just passes the control to the actual active * view callback, after setting up basic stuff like cleaning the screen * and setting color to black. */ -static void render_callback(Canvas *const canvas, void *ctx) { - ProtoViewApp *app = ctx; +static void render_callback(Canvas* const canvas, void* ctx) { + ProtoViewApp* app = ctx; /* Clear screen. */ canvas_set_color(canvas, ColorWhite); @@ -51,14 +51,25 @@ static void render_callback(Canvas *const canvas, void *ctx) { /* Call who is in charge right now. */ switch(app->current_view) { - case ViewRawPulses: render_view_raw_pulses(canvas,app); break; - case ViewInfo: render_view_info(canvas,app); break; + case ViewRawPulses: + render_view_raw_pulses(canvas, app); + break; + case ViewInfo: + render_view_info(canvas, app); + break; case ViewFrequencySettings: case ViewModulationSettings: - render_view_settings(canvas,app); break; - case ViewDirectSampling: render_view_direct_sampling(canvas,app); break; - case ViewBuildMessage: render_view_build_message(canvas,app); break; - default: furi_crash(TAG "Invalid view selected"); break; + render_view_settings(canvas, app); + break; + case ViewDirectSampling: + render_view_direct_sampling(canvas, app); + break; + case ViewBuildMessage: + render_view_build_message(canvas, app); + break; + default: + furi_crash(TAG "Invalid view selected"); + break; } /* Draw the alert box if set. */ @@ -67,10 +78,9 @@ static void render_callback(Canvas *const canvas, void *ctx) { /* Here all we do is putting the events into the queue that will be handled * in the while() loop of the app entry point function. */ -static void input_callback(InputEvent* input_event, void* ctx) -{ - ProtoViewApp *app = ctx; - furi_message_queue_put(app->event_queue,input_event,FuriWaitForever); +static void input_callback(InputEvent* input_event, void* ctx) { + ProtoViewApp* app = ctx; + furi_message_queue_put(app->event_queue, input_event, FuriWaitForever); } /* Called to switch view (when left/right is pressed). Handles @@ -80,15 +90,15 @@ static void input_callback(InputEvent* input_event, void* ctx) * The 'switchto' parameter can be the identifier of a view, or the * special views ViewGoNext and ViewGoPrev in order to move to * the logical next/prev view. */ -static void app_switch_view(ProtoViewApp *app, ProtoViewCurrentView switchto) { +static void app_switch_view(ProtoViewApp* app, ProtoViewCurrentView switchto) { /* Switch to the specified view. */ ProtoViewCurrentView old = app->current_view; - if (switchto == ViewGoNext) { + if(switchto == ViewGoNext) { app->current_view++; - if (app->current_view == ViewLast) app->current_view = 0; - } else if (switchto == ViewGoPrev) { - if (app->current_view == 0) - app->current_view = ViewLast-1; + if(app->current_view == ViewLast) app->current_view = 0; + } else if(switchto == ViewGoPrev) { + if(app->current_view == 0) + app->current_view = ViewLast - 1; else app->current_view--; } else { @@ -103,20 +113,20 @@ static void app_switch_view(ProtoViewApp *app, ProtoViewCurrentView switchto) { /* Reset the view private data each time, before calling the enter/exit * callbacks that may want to setup some state. */ - memset(app->view_privdata,0,PROTOVIEW_VIEW_PRIVDATA_LEN); + memset(app->view_privdata, 0, PROTOVIEW_VIEW_PRIVDATA_LEN); /* Call the enter/exit view callbacks if needed. */ - if (old == ViewDirectSampling) view_exit_direct_sampling(app); - if (new == ViewDirectSampling) view_enter_direct_sampling(app); - if (old == ViewBuildMessage) view_exit_build_message(app); - if (new == ViewBuildMessage) view_enter_build_message(app); - if (old == ViewInfo) view_exit_info(app); + if(old == ViewDirectSampling) view_exit_direct_sampling(app); + if(new == ViewDirectSampling) view_enter_direct_sampling(app); + if(old == ViewBuildMessage) view_exit_build_message(app); + if(new == ViewBuildMessage) view_enter_build_message(app); + if(old == ViewInfo) view_exit_info(app); /* The frequency/modulation settings are actually a single view: * as long as the user stays between the two modes of this view we * don't need to call the exit-view callback. */ - if ((old == ViewFrequencySettings && new != ViewModulationSettings) || - (old == ViewModulationSettings && new != ViewFrequencySettings)) + if((old == ViewFrequencySettings && new != ViewModulationSettings) || + (old == ViewModulationSettings && new != ViewFrequencySettings)) view_exit_settings(app); ui_dismiss_alert(app); @@ -125,7 +135,7 @@ static void app_switch_view(ProtoViewApp *app, ProtoViewCurrentView switchto) { /* Allocate the application state and initialize a number of stuff. * This is called in the entry point to create the application state. */ ProtoViewApp* protoview_app_alloc() { - ProtoViewApp *app = malloc(sizeof(ProtoViewApp)); + ProtoViewApp* app = malloc(sizeof(ProtoViewApp)); // Init shared data structures RawSamples = raw_samples_alloc(); @@ -133,7 +143,7 @@ ProtoViewApp* protoview_app_alloc() { //init setting app->setting = subghz_setting_alloc(); - subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user.txt")); // GUI app->gui = furi_record_open(RECORD_GUI); @@ -148,10 +158,10 @@ ProtoViewApp* protoview_app_alloc() { app->show_text_input = false; app->alert_dismiss_time = 0; app->current_view = ViewRawPulses; - for (int j = 0; j < ViewLast; j++) app->current_subview[j] = 0; + for(int j = 0; j < ViewLast; j++) app->current_subview[j] = 0; app->direct_sampling_enabled = false; app->view_privdata = malloc(PROTOVIEW_VIEW_PRIVDATA_LEN); - memset(app->view_privdata,0,PROTOVIEW_VIEW_PRIVDATA_LEN); + memset(app->view_privdata, 0, PROTOVIEW_VIEW_PRIVDATA_LEN); // Signal found and visualization defaults app->signal_bestlen = 0; @@ -176,17 +186,14 @@ ProtoViewApp* protoview_app_alloc() { app->txrx->environment = subghz_environment_alloc(); subghz_environment_set_protocol_registry( app->txrx->environment, (void*)&protoview_protocol_registry); - app->txrx->receiver = - subghz_receiver_alloc_init(app->txrx->environment); - subghz_receiver_set_filter(app->txrx->receiver, - SubGhzProtocolFlag_Decodable); + app->txrx->receiver = subghz_receiver_alloc_init(app->txrx->environment); + subghz_receiver_set_filter(app->txrx->receiver, SubGhzProtocolFlag_Decodable); subghz_worker_set_overrun_callback( - app->txrx->worker, - (SubGhzWorkerOverrunCallback)subghz_receiver_reset); + app->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); subghz_worker_set_pair_callback( app->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); subghz_worker_set_context(app->txrx->worker, app->txrx->receiver); - + app->frequency = subghz_setting_get_default_frequency(app->setting); app->modulation = 0; /* Defaults to ProtoViewModulations[0]. */ @@ -199,7 +206,7 @@ ProtoViewApp* protoview_app_alloc() { /* Free what the application allocated. It is not clear to me if the * Flipper OS, once the application exits, will be able to reclaim space * even if we forget to free something here. */ -void protoview_app_free(ProtoViewApp *app) { +void protoview_app_free(ProtoViewApp* app) { furi_assert(app); // Put CC1101 on sleep, this also restores charging. @@ -218,7 +225,7 @@ void protoview_app_free(ProtoViewApp *app) { subghz_setting_free(app->setting); // Worker stuff. - if (!app->txrx->debug_timer_sampling) { + if(!app->txrx->debug_timer_sampling) { subghz_receiver_free(app->txrx->receiver); subghz_environment_free(app->txrx->environment); subghz_worker_free(app->txrx->worker); @@ -236,8 +243,8 @@ void protoview_app_free(ProtoViewApp *app) { /* Called periodically. Do signal processing here. Data we process here * will be later displayed by the render callback. The side effect of this * function is to scan for signals and set DetectedSamples. */ -static void timer_callback(void *ctx) { - ProtoViewApp *app = ctx; +static void timer_callback(void* ctx) { + ProtoViewApp* app = ctx; uint32_t delta, lastidx = app->signal_last_scan_idx; /* scan_for_signal(), called by this function, deals with a @@ -245,14 +252,14 @@ static void timer_callback(void *ctx) { * cross-boundaries, it is enough if we scan each time the buffer fills * for 50% more compared to the last scan. Thanks to this check we * can avoid scanning too many times to just find the same data. */ - if (lastidx < RawSamples->idx) { + if(lastidx < RawSamples->idx) { delta = RawSamples->idx - lastidx; } else { delta = RawSamples->total - lastidx + RawSamples->idx; } - if (delta < RawSamples->total/2) return; + if(delta < RawSamples->total / 2) return; app->signal_last_scan_idx = RawSamples->idx; - scan_for_signal(app,RawSamples); + scan_for_signal(app, RawSamples); } /* This is the navigation callback we use in the view dispatcher used @@ -265,7 +272,7 @@ static void timer_callback(void *ctx) { * We just need a dummy callback returning false. We believe the * implementation should be changed and if no callback is set, it should be * the same as returning false. */ -static bool keyboard_view_dispatcher_navigation_callback(void *ctx) { +static bool keyboard_view_dispatcher_navigation_callback(void* ctx) { UNUSED(ctx); return false; } @@ -273,10 +280,10 @@ static bool keyboard_view_dispatcher_navigation_callback(void *ctx) { /* App entry point, as specified in application.fam. */ int32_t protoview_app_entry(void* p) { UNUSED(p); - ProtoViewApp *app = protoview_app_alloc(); + ProtoViewApp* app = protoview_app_alloc(); /* Create a timer. We do data analysis in the callback. */ - FuriTimer *timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, app); + FuriTimer* timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, app); furi_timer_start(timer, furi_kernel_get_tick_frequency() / 8); /* Start listening to signals immediately. */ @@ -291,71 +298,68 @@ int32_t protoview_app_entry(void* p) { InputEvent input; while(app->running) { FuriStatus qstat = furi_message_queue_get(app->event_queue, &input, 100); - if (qstat == FuriStatusOk) { - if (DEBUG_MSG) FURI_LOG_E(TAG, "Main Loop - Input: type %d key %u", - input.type, input.key); + if(qstat == FuriStatusOk) { + if(DEBUG_MSG) + FURI_LOG_E(TAG, "Main Loop - Input: type %d key %u", input.type, input.key); /* Handle navigation here. Then handle view-specific inputs * in the view specific handling function. */ - if (input.type == InputTypeShort && - input.key == InputKeyBack) - { - if (app->current_view != ViewRawPulses) { + if(input.type == InputTypeShort && input.key == InputKeyBack) { + if(app->current_view != ViewRawPulses) { /* If this is not the main app view, go there. */ - app_switch_view(app,ViewRawPulses); + app_switch_view(app, ViewRawPulses); } else { /* If we are in the main app view, warn the user * they needs to long press to really quit. */ - ui_show_alert(app,"Long press to exit",1000); + ui_show_alert(app, "Long press to exit", 1000); } - } else if (input.type == InputTypeLong && - input.key == InputKeyBack) - { + } else if(input.type == InputTypeLong && input.key == InputKeyBack) { app->running = 0; - } else if (input.type == InputTypeShort && - input.key == InputKeyRight && - ui_get_current_subview(app) == 0) - { + } else if( + input.type == InputTypeShort && input.key == InputKeyRight && + ui_get_current_subview(app) == 0) { /* Go to the next view. */ - app_switch_view(app,ViewGoNext); - } else if (input.type == InputTypeShort && - input.key == InputKeyLeft && - ui_get_current_subview(app) == 0) - { + app_switch_view(app, ViewGoNext); + } else if( + input.type == InputTypeShort && input.key == InputKeyLeft && + ui_get_current_subview(app) == 0) { /* Go to the previous view. */ - app_switch_view(app,ViewGoPrev); + app_switch_view(app, ViewGoPrev); } else { /* This is where we pass the control to the currently * active view input processing. */ switch(app->current_view) { case ViewRawPulses: - process_input_raw_pulses(app,input); + process_input_raw_pulses(app, input); break; case ViewInfo: - process_input_info(app,input); + process_input_info(app, input); break; case ViewFrequencySettings: case ViewModulationSettings: - process_input_settings(app,input); + process_input_settings(app, input); break; case ViewDirectSampling: - process_input_direct_sampling(app,input); + process_input_direct_sampling(app, input); break; case ViewBuildMessage: - process_input_build_message(app,input); + process_input_build_message(app, input); + break; + default: + furi_crash(TAG "Invalid view selected"); break; - default: furi_crash(TAG "Invalid view selected"); break; } } } else { /* Useful to understand if the app is still alive when it * does not respond because of bugs. */ - if (DEBUG_MSG) { - static int c = 0; c++; - if (!(c % 20)) FURI_LOG_E(TAG, "Loop timeout"); + if(DEBUG_MSG) { + static int c = 0; + c++; + if(!(c % 20)) FURI_LOG_E(TAG, "Loop timeout"); } } - if (app->show_text_input) { + if(app->show_text_input) { /* Remove our viewport: we need to use a view dispatcher * in order to show the standard Flipper keyboard. */ gui_remove_view_port(app->gui, app->view_port); @@ -368,11 +372,11 @@ int32_t protoview_app_entry(void* p) { * otherwise when the user presses back on the keyboard to * abort, the dispatcher will not stop. */ view_dispatcher_set_navigation_event_callback( - app->view_dispatcher, - keyboard_view_dispatcher_navigation_callback); + app->view_dispatcher, keyboard_view_dispatcher_navigation_callback); app->text_input = text_input_alloc(); - view_dispatcher_set_event_callback_context(app->view_dispatcher,app); - view_dispatcher_add_view(app->view_dispatcher, 0, text_input_get_view(app->text_input)); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_add_view( + app->view_dispatcher, 0, text_input_get_view(app->text_input)); view_dispatcher_switch_to_view(app->view_dispatcher, 0); /* Setup the text input view. The different parameters are set @@ -388,7 +392,8 @@ int32_t protoview_app_entry(void* p) { false); /* Run the dispatcher with the keyboard. */ - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_attach_to_gui( + app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); view_dispatcher_run(app->view_dispatcher); /* Undo all it: remove the view from the dispatcher, free it @@ -406,7 +411,7 @@ int32_t protoview_app_entry(void* p) { } /* App no longer running. Shut down and free. */ - if (app->txrx->txrx_state == TxRxStateRx) { + if(app->txrx->txrx_state == TxRxStateRx) { FURI_LOG_E(TAG, "Putting CC1101 to sleep before exiting."); radio_rx_end(app); radio_sleep(app); @@ -416,4 +421,3 @@ int32_t protoview_app_entry(void* p) { protoview_app_free(app); return 0; } - diff --git a/applications/plugins/protoview/app.h b/applications/plugins/protoview/app.h index 33bd85eb4..85007e345 100644 --- a/applications/plugins/protoview/app.h +++ b/applications/plugins/protoview/app.h @@ -66,11 +66,11 @@ typedef enum { /* ================================== RX/TX ================================= */ typedef struct { - const char *name; // Name to show to the user. - const char *id; // Identifier in the Flipper API/file. - FuriHalSubGhzPreset preset; // The preset ID. - uint8_t *custom; // If not null, a set of registers for - // the CC1101, specifying a custom preset. + const char* name; // Name to show to the user. + const char* id; // Identifier in the Flipper API/file. + FuriHalSubGhzPreset preset; // The preset ID. + uint8_t* custom; // If not null, a set of registers for + // the CC1101, specifying a custom preset. } ProtoViewModulation; extern ProtoViewModulation ProtoViewModulations[]; /* In app_subghz.c */ @@ -79,19 +79,19 @@ extern ProtoViewModulation ProtoViewModulations[]; /* In app_subghz.c */ * It receives data and we get our protocol "feed" callback called * with the level (1 or 0) and duration. */ struct ProtoViewTxRx { - bool freq_mod_changed; /* The user changed frequency and/or modulation + bool freq_mod_changed; /* The user changed frequency and/or modulation from the interface. There is to restart the radio with the right parameters. */ - SubGhzWorker* worker; /* Our background worker. */ + SubGhzWorker* worker; /* Our background worker. */ SubGhzEnvironment* environment; SubGhzReceiver* receiver; TxRxState txrx_state; /* Receiving, idle or sleeping? */ /* Timer sampling mode state. */ - bool debug_timer_sampling; /* Read data from GDO0 in a busy loop. Only + bool debug_timer_sampling; /* Read data from GDO0 in a busy loop. Only for testing. */ uint32_t last_g0_change_time; /* Last high->low (or reverse) switch. */ - bool last_g0_value; /* Current value (high or low): we are + bool last_g0_value; /* Current value (high or low): we are checking the duration in the timer handler. */ }; @@ -103,44 +103,44 @@ typedef struct ProtoViewTxRx ProtoViewTxRx; #define ALERT_MAX_LEN 32 struct ProtoViewApp { /* GUI */ - Gui *gui; - NotificationApp *notification; - ViewPort *view_port; /* We just use a raw viewport and we render + Gui* gui; + NotificationApp* notification; + ViewPort* view_port; /* We just use a raw viewport and we render everything into the low level canvas. */ - ProtoViewCurrentView current_view; /* Active left-right view ID. */ - int current_subview[ViewLast]; /* Active up-down subview ID. */ - FuriMessageQueue *event_queue; /* Keypress events go here. */ + ProtoViewCurrentView current_view; /* Active left-right view ID. */ + int current_subview[ViewLast]; /* Active up-down subview ID. */ + FuriMessageQueue* event_queue; /* Keypress events go here. */ /* Input text state. */ - ViewDispatcher *view_dispatcher; /* Used only when we want to show + ViewDispatcher* view_dispatcher; /* Used only when we want to show the text_input view for a moment. Otherwise it is set to null. */ - TextInput *text_input; + TextInput* text_input; bool show_text_input; - char *text_input_buffer; + char* text_input_buffer; uint32_t text_input_buffer_len; void (*text_input_done_callback)(void*); /* Alert state. */ - uint32_t alert_dismiss_time; /* Millisecond when the alert will be + uint32_t alert_dismiss_time; /* Millisecond when the alert will be no longer shown. Or zero if the alert is currently not set at all. */ char alert_text[ALERT_MAX_LEN]; /* Alert content. */ /* Radio related. */ - ProtoViewTxRx *txrx; /* Radio state. */ - SubGhzSetting *setting; /* A list of valid frequencies. */ + ProtoViewTxRx* txrx; /* Radio state. */ + SubGhzSetting* setting; /* A list of valid frequencies. */ /* Generic app state. */ - int running; /* Once false exists the app. */ + int running; /* Once false exists the app. */ uint32_t signal_bestlen; /* Longest coherent signal observed so far. */ uint32_t signal_last_scan_idx; /* Index of the buffer last time we performed the scan. */ - bool signal_decoded; /* Was the current signal decoded? */ - ProtoViewMsgInfo *msg_info; /* Decoded message info if not NULL. */ + bool signal_decoded; /* Was the current signal decoded? */ + ProtoViewMsgInfo* msg_info; /* Decoded message info if not NULL. */ bool direct_sampling_enabled; /* This special view needs an explicit acknowledge to work. */ - void *view_privdata; /* This is a piece of memory of total size + void* view_privdata; /* This is a piece of memory of total size PROTOVIEW_VIEW_PRIVDATA_LEN that it is initialized to zero when we switch to a a new view. While the view we are using @@ -149,12 +149,12 @@ struct ProtoViewApp { the pointer to a few specific-data structure. */ /* Raw view apps state. */ - uint32_t us_scale; /* microseconds per pixel. */ - uint32_t signal_offset; /* Long press left/right panning in raw view. */ + uint32_t us_scale; /* microseconds per pixel. */ + uint32_t signal_offset; /* Long press left/right panning in raw view. */ /* Configuration view app state. */ - uint32_t frequency; /* Current frequency. */ - uint8_t modulation; /* Current modulation ID, array index in the + uint32_t frequency; /* Current frequency. */ + uint8_t modulation; /* Current modulation ID, array index in the ProtoViewModulations table. */ }; @@ -165,18 +165,18 @@ struct ProtoViewApp { * in the message info view. */ #define PROTOVIEW_MSG_STR_LEN 32 typedef struct ProtoViewMsgInfo { - ProtoViewDecoder *decoder; /* The decoder that decoded the message. */ - ProtoViewFieldSet *fieldset; /* Decoded fields. */ + ProtoViewDecoder* decoder; /* The decoder that decoded the message. */ + ProtoViewFieldSet* fieldset; /* Decoded fields. */ /* Low level information of the detected signal: the following are filled * by the protocol decoding function: */ - uint32_t start_off; /* Pulses start offset in the bitmap. */ - uint32_t pulses_count; /* Number of pulses of the full message. */ + uint32_t start_off; /* Pulses start offset in the bitmap. */ + uint32_t pulses_count; /* Number of pulses of the full message. */ /* The following are passed already filled to the decoder. */ - uint32_t short_pulse_dur; /* Microseconds duration of the short pulse. */ + uint32_t short_pulse_dur; /* Microseconds duration of the short pulse. */ /* The following are filled by ProtoView core after the decoder returned * success. */ - uint8_t *bits; /* Bitmap with the signal. */ - uint32_t bits_bytes; /* Number of full bytes in the bitmap, that + uint8_t* bits; /* Bitmap with the signal. */ + uint32_t bits_bytes; /* Number of full bytes in the bitmap, that is 'pulses_count/8' rounded to the next integer. */ } ProtoViewMsgInfo; @@ -196,28 +196,28 @@ typedef enum { typedef struct { ProtoViewFieldType type; - uint32_t len; // Depends on type: - // Bits for integers (signed,unsigned,binary,hex). - // Number of characters for strings. - // Number of nibbles for bytes (1 for each 4 bits). - // Number of digits after dot for floats. - char *name; // Field name. + uint32_t len; // Depends on type: + // Bits for integers (signed,unsigned,binary,hex). + // Number of characters for strings. + // Number of nibbles for bytes (1 for each 4 bits). + // Number of digits after dot for floats. + char* name; // Field name. union { - char *str; // String type. - int64_t value; // Signed integer type. - uint64_t uvalue; // Unsigned integer type. - uint8_t *bytes; // Raw bytes type. - float fvalue; // Float type. + char* str; // String type. + int64_t value; // Signed integer type. + uint64_t uvalue; // Unsigned integer type. + uint8_t* bytes; // Raw bytes type. + float fvalue; // Float type. }; } ProtoViewField; typedef struct ProtoViewFieldSet { - ProtoViewField **fields; + ProtoViewField** fields; uint32_t numfields; } ProtoViewFieldSet; typedef struct ProtoViewDecoder { - const char *name; /* Protocol name. */ + const char* name; /* Protocol name. */ /* The decode function takes a buffer that is actually a bitmap, with * high and low levels represented as 0 and 1. The number of high/low * pulses represented by the bitmap is passed as the 'numbits' argument, @@ -225,15 +225,15 @@ typedef struct ProtoViewDecoder { * 'bits'. So 'numbytes' is mainly useful to pass as argument to other * functions that perform bit extraction with bound checking, such as * bitmap_get() and so forth. */ - bool (*decode)(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info); + bool (*decode)(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info); /* This method is used by the decoder to return the fields it needs * in order to build a new message. This way the message builder view * can ask the user to fill the right set of fields of the specified * type. */ - void (*get_fields)(ProtoViewFieldSet *fields); + void (*get_fields)(ProtoViewFieldSet* fields); /* This method takes the fields supported by the decoder, and * renders a message in 'samples'. */ - void (*build_message)(RawSamplesBuffer *samples, ProtoViewFieldSet *fields); + void (*build_message)(RawSamplesBuffer* samples, ProtoViewFieldSet* fields); } ProtoViewDecoder; extern RawSamplesBuffer *RawSamples, *DetectedSamples; @@ -244,76 +244,118 @@ uint32_t radio_rx(ProtoViewApp* app); void radio_idle(ProtoViewApp* app); void radio_rx_end(ProtoViewApp* app); void radio_sleep(ProtoViewApp* app); -void raw_sampling_worker_start(ProtoViewApp *app); -void raw_sampling_worker_stop(ProtoViewApp *app); -void radio_tx_signal(ProtoViewApp *app, FuriHalSubGhzAsyncTxCallback data_feeder, void *ctx); +void raw_sampling_worker_start(ProtoViewApp* app); +void raw_sampling_worker_stop(ProtoViewApp* app); +void radio_tx_signal(ProtoViewApp* app, FuriHalSubGhzAsyncTxCallback data_feeder, void* ctx); /* signal.c */ uint32_t duration_delta(uint32_t a, uint32_t b); -void reset_current_signal(ProtoViewApp *app); -void scan_for_signal(ProtoViewApp *app,RawSamplesBuffer *source); -bool bitmap_get(uint8_t *b, uint32_t blen, uint32_t bitpos); -void bitmap_set(uint8_t *b, uint32_t blen, uint32_t bitpos, bool val); -void bitmap_copy(uint8_t *d, uint32_t dlen, uint32_t doff, uint8_t *s, uint32_t slen, uint32_t soff, uint32_t count); -void bitmap_set_pattern(uint8_t *b, uint32_t blen, uint32_t off, const char *pat); -void bitmap_reverse_bytes_bits(uint8_t *p, uint32_t len); -bool bitmap_match_bits(uint8_t *b, uint32_t blen, uint32_t bitpos, const char *bits); -uint32_t bitmap_seek_bits(uint8_t *b, uint32_t blen, uint32_t startpos, uint32_t maxbits, const char *bits); -uint32_t convert_from_line_code(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t offset, const char *zero_pattern, const char *one_pattern); -uint32_t convert_from_diff_manchester(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t off, bool previous); -void init_msg_info(ProtoViewMsgInfo *i, ProtoViewApp *app); -void free_msg_info(ProtoViewMsgInfo *i); +void reset_current_signal(ProtoViewApp* app); +void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source); +bool bitmap_get(uint8_t* b, uint32_t blen, uint32_t bitpos); +void bitmap_set(uint8_t* b, uint32_t blen, uint32_t bitpos, bool val); +void bitmap_copy( + uint8_t* d, + uint32_t dlen, + uint32_t doff, + uint8_t* s, + uint32_t slen, + uint32_t soff, + uint32_t count); +void bitmap_set_pattern(uint8_t* b, uint32_t blen, uint32_t off, const char* pat); +void bitmap_reverse_bytes_bits(uint8_t* p, uint32_t len); +bool bitmap_match_bits(uint8_t* b, uint32_t blen, uint32_t bitpos, const char* bits); +uint32_t bitmap_seek_bits( + uint8_t* b, + uint32_t blen, + uint32_t startpos, + uint32_t maxbits, + const char* bits); +uint32_t convert_from_line_code( + uint8_t* buf, + uint64_t buflen, + uint8_t* bits, + uint32_t len, + uint32_t offset, + const char* zero_pattern, + const char* one_pattern); +uint32_t convert_from_diff_manchester( + uint8_t* buf, + uint64_t buflen, + uint8_t* bits, + uint32_t len, + uint32_t off, + bool previous); +void init_msg_info(ProtoViewMsgInfo* i, ProtoViewApp* app); +void free_msg_info(ProtoViewMsgInfo* i); /* signal_file.c */ -bool save_signal(ProtoViewApp *app, const char *filename); +bool save_signal(ProtoViewApp* app, const char* filename); /* view_*.c */ -void render_view_raw_pulses(Canvas *const canvas, ProtoViewApp *app); -void process_input_raw_pulses(ProtoViewApp *app, InputEvent input); -void render_view_settings(Canvas *const canvas, ProtoViewApp *app); -void process_input_settings(ProtoViewApp *app, InputEvent input); -void render_view_info(Canvas *const canvas, ProtoViewApp *app); -void process_input_info(ProtoViewApp *app, InputEvent input); -void render_view_direct_sampling(Canvas *const canvas, ProtoViewApp *app); -void process_input_direct_sampling(ProtoViewApp *app, InputEvent input); -void render_view_build_message(Canvas *const canvas, ProtoViewApp *app); -void process_input_build_message(ProtoViewApp *app, InputEvent input); -void view_enter_build_message(ProtoViewApp *app); -void view_exit_build_message(ProtoViewApp *app); -void view_enter_direct_sampling(ProtoViewApp *app); -void view_exit_direct_sampling(ProtoViewApp *app); -void view_exit_settings(ProtoViewApp *app); -void view_exit_info(ProtoViewApp *app); -void adjust_raw_view_scale(ProtoViewApp *app, uint32_t short_pulse_dur); +void render_view_raw_pulses(Canvas* const canvas, ProtoViewApp* app); +void process_input_raw_pulses(ProtoViewApp* app, InputEvent input); +void render_view_settings(Canvas* const canvas, ProtoViewApp* app); +void process_input_settings(ProtoViewApp* app, InputEvent input); +void render_view_info(Canvas* const canvas, ProtoViewApp* app); +void process_input_info(ProtoViewApp* app, InputEvent input); +void render_view_direct_sampling(Canvas* const canvas, ProtoViewApp* app); +void process_input_direct_sampling(ProtoViewApp* app, InputEvent input); +void render_view_build_message(Canvas* const canvas, ProtoViewApp* app); +void process_input_build_message(ProtoViewApp* app, InputEvent input); +void view_enter_build_message(ProtoViewApp* app); +void view_exit_build_message(ProtoViewApp* app); +void view_enter_direct_sampling(ProtoViewApp* app); +void view_exit_direct_sampling(ProtoViewApp* app); +void view_exit_settings(ProtoViewApp* app); +void view_exit_info(ProtoViewApp* app); +void adjust_raw_view_scale(ProtoViewApp* app, uint32_t short_pulse_dur); /* ui.c */ -int ui_get_current_subview(ProtoViewApp *app); -void ui_show_available_subviews(Canvas *canvas, ProtoViewApp *app, int last_subview); -bool ui_process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subview); -void ui_show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen, - void (*done_callback)(void*)); -void ui_dismiss_keyboard(ProtoViewApp *app); -void ui_show_alert(ProtoViewApp *app, const char *text, uint32_t ttl); -void ui_dismiss_alert(ProtoViewApp *app); -void ui_draw_alert_if_needed(Canvas *canvas, ProtoViewApp *app); -void canvas_draw_str_with_border(Canvas* canvas, uint8_t x, uint8_t y, const char* str, Color text_color, Color border_color); +int ui_get_current_subview(ProtoViewApp* app); +void ui_show_available_subviews(Canvas* canvas, ProtoViewApp* app, int last_subview); +bool ui_process_subview_updown(ProtoViewApp* app, InputEvent input, int last_subview); +void ui_show_keyboard( + ProtoViewApp* app, + char* buffer, + uint32_t buflen, + void (*done_callback)(void*)); +void ui_dismiss_keyboard(ProtoViewApp* app); +void ui_show_alert(ProtoViewApp* app, const char* text, uint32_t ttl); +void ui_dismiss_alert(ProtoViewApp* app); +void ui_draw_alert_if_needed(Canvas* canvas, ProtoViewApp* app); +void canvas_draw_str_with_border( + Canvas* canvas, + uint8_t x, + uint8_t y, + const char* str, + Color text_color, + Color border_color); /* fields.c */ -void fieldset_free(ProtoViewFieldSet *fs); -ProtoViewFieldSet *fieldset_new(void); -void fieldset_add_int(ProtoViewFieldSet *fs, const char *name, int64_t val, uint8_t bits); -void fieldset_add_uint(ProtoViewFieldSet *fs, const char *name, uint64_t uval, uint8_t bits); -void fieldset_add_hex(ProtoViewFieldSet *fs, const char *name, uint64_t uval, uint8_t bits); -void fieldset_add_bin(ProtoViewFieldSet *fs, const char *name, uint64_t uval, uint8_t bits); -void fieldset_add_str(ProtoViewFieldSet *fs, const char *name, const char *s); -void fieldset_add_bytes(ProtoViewFieldSet *fs, const char *name, const uint8_t *bytes, uint32_t count); -void fieldset_add_float(ProtoViewFieldSet *fs, const char *name, float val, uint32_t digits_after_dot); -const char *field_get_type_name(ProtoViewField *f); -int field_to_string(char *buf, size_t len, ProtoViewField *f); -bool field_set_from_string(ProtoViewField *f, char *buf, size_t len); -bool field_incr_value(ProtoViewField *f, int incr); -void fieldset_copy_matching_fields(ProtoViewFieldSet *dst, ProtoViewFieldSet *src); -void field_set_from_field(ProtoViewField *dst, ProtoViewField *src); +void fieldset_free(ProtoViewFieldSet* fs); +ProtoViewFieldSet* fieldset_new(void); +void fieldset_add_int(ProtoViewFieldSet* fs, const char* name, int64_t val, uint8_t bits); +void fieldset_add_uint(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits); +void fieldset_add_hex(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits); +void fieldset_add_bin(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits); +void fieldset_add_str(ProtoViewFieldSet* fs, const char* name, const char* s); +void fieldset_add_bytes( + ProtoViewFieldSet* fs, + const char* name, + const uint8_t* bytes, + uint32_t count); +void fieldset_add_float( + ProtoViewFieldSet* fs, + const char* name, + float val, + uint32_t digits_after_dot); +const char* field_get_type_name(ProtoViewField* f); +int field_to_string(char* buf, size_t len, ProtoViewField* f); +bool field_set_from_string(ProtoViewField* f, char* buf, size_t len); +bool field_incr_value(ProtoViewField* f, int incr); +void fieldset_copy_matching_fields(ProtoViewFieldSet* dst, ProtoViewFieldSet* src); +void field_set_from_field(ProtoViewField* dst, ProtoViewField* src); /* crc.c */ -uint8_t crc8(const uint8_t *data, size_t len, uint8_t init, uint8_t poly); +uint8_t crc8(const uint8_t* data, size_t len, uint8_t init, uint8_t poly); diff --git a/applications/plugins/protoview/app_subghz.c b/applications/plugins/protoview/app_subghz.c index 55905e8a3..73e0e16ae 100644 --- a/applications/plugins/protoview/app_subghz.c +++ b/applications/plugins/protoview/app_subghz.c @@ -9,18 +9,20 @@ #include #include -void raw_sampling_worker_start(ProtoViewApp *app); -void raw_sampling_worker_stop(ProtoViewApp *app); +void raw_sampling_worker_start(ProtoViewApp* app); +void raw_sampling_worker_stop(ProtoViewApp* app); ProtoViewModulation ProtoViewModulations[] = { - {"OOK 650Khz", "FuriHalSubGhzPresetOok650Async", - FuriHalSubGhzPresetOok650Async, NULL}, - {"OOK 270Khz", "FuriHalSubGhzPresetOok270Async", - FuriHalSubGhzPresetOok270Async, NULL}, - {"2FSK 2.38Khz", "FuriHalSubGhzPreset2FSKDev238Async", - FuriHalSubGhzPreset2FSKDev238Async, NULL}, - {"2FSK 47.6Khz", "FuriHalSubGhzPreset2FSKDev476Async", - FuriHalSubGhzPreset2FSKDev476Async, NULL}, + {"OOK 650Khz", "FuriHalSubGhzPresetOok650Async", FuriHalSubGhzPresetOok650Async, NULL}, + {"OOK 270Khz", "FuriHalSubGhzPresetOok270Async", FuriHalSubGhzPresetOok270Async, NULL}, + {"2FSK 2.38Khz", + "FuriHalSubGhzPreset2FSKDev238Async", + FuriHalSubGhzPreset2FSKDev238Async, + NULL}, + {"2FSK 47.6Khz", + "FuriHalSubGhzPreset2FSKDev476Async", + FuriHalSubGhzPreset2FSKDev476Async, + NULL}, {"TPMS 1 (FSK)", NULL, 0, (uint8_t*)protoview_subghz_tpms1_fsk_async_regs}, {"TPMS 2 (OOK)", NULL, 0, (uint8_t*)protoview_subghz_tpms2_ook_async_regs}, {"TPMS 3 (FSK)", NULL, 0, (uint8_t*)protoview_subghz_tpms3_fsk_async_regs}, @@ -44,12 +46,10 @@ void radio_begin(ProtoViewApp* app) { /* The CC1101 preset can be either one of the standard presets, if * the modulation "custom" field is NULL, or a custom preset we * defined in custom_presets.h. */ - if (ProtoViewModulations[app->modulation].custom == NULL) { - furi_hal_subghz_load_preset( - ProtoViewModulations[app->modulation].preset); + if(ProtoViewModulations[app->modulation].custom == NULL) { + furi_hal_subghz_load_preset(ProtoViewModulations[app->modulation].preset); } else { - furi_hal_subghz_load_custom_preset( - ProtoViewModulations[app->modulation].custom); + furi_hal_subghz_load_custom_preset(ProtoViewModulations[app->modulation].custom); } furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); app->txrx->txrx_state = TxRxStateIDLE; @@ -61,10 +61,10 @@ void radio_begin(ProtoViewApp* app) { uint32_t radio_rx(ProtoViewApp* app) { furi_assert(app); if(!furi_hal_subghz_is_frequency_valid(app->frequency)) { - furi_crash(TAG" Incorrect RX frequency."); + furi_crash(TAG " Incorrect RX frequency."); } - if (app->txrx->txrx_state == TxRxStateRx) return app->frequency; + if(app->txrx->txrx_state == TxRxStateRx) return app->frequency; furi_hal_subghz_idle(); /* Put it into idle state in case it is sleeping. */ uint32_t value = furi_hal_subghz_set_frequency_and_path(app->frequency); @@ -72,10 +72,8 @@ uint32_t radio_rx(ProtoViewApp* app) { furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_flush_rx(); furi_hal_subghz_rx(); - if (!app->txrx->debug_timer_sampling) { - - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, - app->txrx->worker); + if(!app->txrx->debug_timer_sampling) { + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, app->txrx->worker); subghz_worker_start(app->txrx->worker); } else { raw_sampling_worker_start(app); @@ -88,8 +86,8 @@ uint32_t radio_rx(ProtoViewApp* app) { void radio_rx_end(ProtoViewApp* app) { furi_assert(app); - if (app->txrx->txrx_state == TxRxStateRx) { - if (!app->txrx->debug_timer_sampling) { + if(app->txrx->txrx_state == TxRxStateRx) { + if(!app->txrx->debug_timer_sampling) { if(subghz_worker_is_running(app->txrx->worker)) { subghz_worker_stop(app->txrx->worker); furi_hal_subghz_stop_async_rx(); @@ -105,7 +103,7 @@ void radio_rx_end(ProtoViewApp* app) { /* Put radio on sleep. */ void radio_sleep(ProtoViewApp* app) { furi_assert(app); - if (app->txrx->txrx_state == TxRxStateRx) { + if(app->txrx->txrx_state == TxRxStateRx) { /* We can't go from having an active RX worker to sleeping. * Stop the RX subsystems first. */ radio_rx_end(app); @@ -120,10 +118,10 @@ void radio_sleep(ProtoViewApp* app) { /* This function suspends the current RX state, switches to TX mode, * transmits the signal provided by the callback data_feeder, and later * restores the RX state if there was one. */ -void radio_tx_signal(ProtoViewApp *app, FuriHalSubGhzAsyncTxCallback data_feeder, void *ctx) { +void radio_tx_signal(ProtoViewApp* app, FuriHalSubGhzAsyncTxCallback data_feeder, void* ctx) { TxRxState oldstate = app->txrx->txrx_state; - if (oldstate == TxRxStateRx) radio_rx_end(app); + if(oldstate == TxRxStateRx) radio_rx_end(app); radio_begin(app); furi_hal_subghz_idle(); @@ -138,7 +136,7 @@ void radio_tx_signal(ProtoViewApp *app, FuriHalSubGhzAsyncTxCallback data_feeder furi_hal_subghz_idle(); radio_begin(app); - if (oldstate == TxRxStateRx) radio_rx(app); + if(oldstate == TxRxStateRx) radio_rx(app); } /* ============================= Raw sampling mode ============================= @@ -148,15 +146,15 @@ void radio_tx_signal(ProtoViewApp *app, FuriHalSubGhzAsyncTxCallback data_feeder * Flipper system. * ===========================================================================*/ -void protoview_timer_isr(void *ctx) { - ProtoViewApp *app = ctx; +void protoview_timer_isr(void* ctx) { + ProtoViewApp* app = ctx; bool level = furi_hal_gpio_read(&gpio_cc1101_g0); - if (app->txrx->last_g0_value != level) { + if(app->txrx->last_g0_value != level) { uint32_t now = DWT->CYCCNT; uint32_t dur = now - app->txrx->last_g0_change_time; dur /= furi_hal_cortex_instructions_per_microsecond(); - if (dur > 15000) dur = 15000; + if(dur > 15000) dur = 15000; raw_samples_add(RawSamples, app->txrx->last_g0_value, dur); app->txrx->last_g0_value = level; app->txrx->last_g0_change_time = now; @@ -164,13 +162,13 @@ void protoview_timer_isr(void *ctx) { LL_TIM_ClearFlag_UPDATE(TIM2); } -void raw_sampling_worker_start(ProtoViewApp *app) { +void raw_sampling_worker_start(ProtoViewApp* app) { UNUSED(app); LL_TIM_InitTypeDef tim_init = { - .Prescaler = 63, /* CPU frequency is ~64Mhz. */ + .Prescaler = 63, /* CPU frequency is ~64Mhz. */ .CounterMode = LL_TIM_COUNTERMODE_UP, - .Autoreload = 5, /* Sample every 5 us */ + .Autoreload = 5, /* Sample every 5 us */ }; LL_TIM_Init(TIM2, &tim_init); @@ -183,7 +181,7 @@ void raw_sampling_worker_start(ProtoViewApp *app) { FURI_LOG_E(TAG, "Timer enabled"); } -void raw_sampling_worker_stop(ProtoViewApp *app) { +void raw_sampling_worker_stop(ProtoViewApp* app) { UNUSED(app); FURI_CRITICAL_ENTER(); LL_TIM_DisableCounter(TIM2); diff --git a/applications/plugins/protoview/application.fam b/applications/plugins/protoview/application.fam index 6cd31372e..d3614524c 100644 --- a/applications/plugins/protoview/application.fam +++ b/applications/plugins/protoview/application.fam @@ -5,7 +5,7 @@ App( entry_point="protoview_app_entry", cdefines=["APP_PROTOVIEW"], requires=["gui"], - stack_size=8*1024, + stack_size=8 * 1024, order=50, fap_icon="appicon.png", fap_category="Tools", diff --git a/applications/plugins/protoview/crc.c b/applications/plugins/protoview/crc.c index 38a809e10..94d482972 100644 --- a/applications/plugins/protoview/crc.c +++ b/applications/plugins/protoview/crc.c @@ -3,14 +3,13 @@ /* CRC8 with the specified initialization value 'init' and * polynomial 'poly'. */ -uint8_t crc8(const uint8_t *data, size_t len, uint8_t init, uint8_t poly) -{ +uint8_t crc8(const uint8_t* data, size_t len, uint8_t init, uint8_t poly) { uint8_t crc = init; size_t i, j; - for (i = 0; i < len; i++) { + for(i = 0; i < len; i++) { crc ^= data[i]; - for (j = 0; j < 8; j++) { - if ((crc & 0x80) != 0) + for(j = 0; j < 8; j++) { + if((crc & 0x80) != 0) crc = (uint8_t)((crc << 1) ^ poly); else crc <<= 1; diff --git a/applications/plugins/protoview/custom_presets.h b/applications/plugins/protoview/custom_presets.h index cb9a421c6..00aa49945 100644 --- a/applications/plugins/protoview/custom_presets.h +++ b/applications/plugins/protoview/custom_presets.h @@ -76,7 +76,8 @@ static uint8_t protoview_subghz_tpms1_fsk_async_regs[][2] = { // // Modem Configuration {CC1101_MDMCFG0, 0x00}, {CC1101_MDMCFG1, 0x02}, - {CC1101_MDMCFG2, 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized). Other code reading TPMS uses GFSK, but should be the same when in RX mode. + {CC1101_MDMCFG2, + 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized). Other code reading TPMS uses GFSK, but should be the same when in RX mode. {CC1101_MDMCFG3, 0x93}, // Data rate is 20kBaud {CC1101_MDMCFG4, 0x59}, // Rx bandwidth filter is 325 kHz {CC1101_DEVIATN, 0x41}, // Deviation 28.56 kHz @@ -106,8 +107,10 @@ static uint8_t protoview_subghz_tpms1_fsk_async_regs[][2] = { {0, 0}, /* CC1101 2FSK PATABLE. */ - {0xC0, 0}, {0,0}, {0,0}, {0,0} -}; + {0xC0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; /* This is like the default Flipper OOK 640Khz bandwidth preset, but * the bandwidth is changed to 10kBaud to accomodate TPMS frequency. */ @@ -156,8 +159,10 @@ static const uint8_t protoview_subghz_tpms2_ook_async_regs[][2] = { {0, 0}, /* CC1101 OOK PATABLE. */ - {0, 0xC0}, {0,0}, {0,0}, {0,0} -}; + {0, 0xC0}, + {0, 0}, + {0, 0}, + {0, 0}}; /* 40 KBaud, 2FSK, 28 kHz deviation, 270 Khz bandwidth filter. */ static uint8_t protoview_subghz_tpms3_fsk_async_regs[][2] = { @@ -174,7 +179,8 @@ static uint8_t protoview_subghz_tpms3_fsk_async_regs[][2] = { // // Modem Configuration {CC1101_MDMCFG0, 0x00}, {CC1101_MDMCFG1, 0x02}, - {CC1101_MDMCFG2, 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized). Other code reading TPMS uses GFSK, but should be the same when in RX mode. + {CC1101_MDMCFG2, + 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized). Other code reading TPMS uses GFSK, but should be the same when in RX mode. {CC1101_MDMCFG3, 0x93}, // Data rate is 40kBaud {CC1101_MDMCFG4, 0x6A}, // 6 = BW filter 270kHz, A = Data rate exp {CC1101_DEVIATN, 0x41}, // Deviation 28kHz @@ -204,8 +210,10 @@ static uint8_t protoview_subghz_tpms3_fsk_async_regs[][2] = { {0, 0}, /* CC1101 2FSK PATABLE. */ - {0xC0, 0}, {0,0}, {0,0}, {0,0} -}; + {0xC0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; /* FSK 19k dev, 325 Khz filter, 20kBaud. Works well with Toyota. */ static uint8_t protoview_subghz_tpms4_fsk_async_regs[][2] = { @@ -250,6 +258,7 @@ static uint8_t protoview_subghz_tpms4_fsk_async_regs[][2] = { {0, 0}, /* CC1101 2FSK PATABLE. */ - {0xC0, 0}, {0,0}, {0,0}, {0,0} -}; - + {0xC0, 0}, + {0, 0}, + {0, 0}, + {0, 0}}; diff --git a/applications/plugins/protoview/data_feed.c b/applications/plugins/protoview/data_feed.c index a3bed238e..81d1a8020 100644 --- a/applications/plugins/protoview/data_feed.c +++ b/applications/plugins/protoview/data_feed.c @@ -14,7 +14,7 @@ const SubGhzProtocol subghz_protocol_protoview; /* The feed() method puts data in the RawSamples global (protected by * a mutex). */ -extern RawSamplesBuffer *RawSamples; +extern RawSamplesBuffer* RawSamples; /* This is totally dummy: we just define the decoder base for the async * system to work but we don't really use it if not to collect raw @@ -26,8 +26,7 @@ typedef struct SubGhzProtocolDecoderprotoview { void* subghz_protocol_decoder_protoview_alloc(SubGhzEnvironment* environment) { UNUSED(environment); - SubGhzProtocolDecoderprotoview* instance = - malloc(sizeof(SubGhzProtocolDecoderprotoview)); + SubGhzProtocolDecoderprotoview* instance = malloc(sizeof(SubGhzProtocolDecoderprotoview)); instance->base.protocol = &subghz_protocol_protoview; return instance; } @@ -66,8 +65,7 @@ uint8_t subghz_protocol_decoder_protoview_get_hash_data(void* context) { bool subghz_protocol_decoder_protoview_serialize( void* context, FlipperFormat* flipper_format, - SubGhzRadioPreset* preset) -{ + SubGhzRadioPreset* preset) { UNUSED(context); UNUSED(flipper_format); UNUSED(preset); @@ -75,15 +73,13 @@ bool subghz_protocol_decoder_protoview_serialize( } /* Not used. */ -bool subghz_protocol_decoder_protoview_deserialize(void* context, FlipperFormat* flipper_format) -{ +bool subghz_protocol_decoder_protoview_deserialize(void* context, FlipperFormat* flipper_format) { UNUSED(context); UNUSED(flipper_format); return false; } -void subhz_protocol_decoder_protoview_get_string(void* context, FuriString* output) -{ +void subhz_protocol_decoder_protoview_get_string(void* context, FuriString* output) { furi_assert(context); furi_string_cat_printf(output, "Protoview"); } @@ -116,5 +112,4 @@ const SubGhzProtocol* protoview_protocol_registry_items[] = { const SubGhzProtocolRegistry protoview_protocol_registry = { .items = protoview_protocol_registry_items, - .size = COUNT_OF(protoview_protocol_registry_items) -}; + .size = COUNT_OF(protoview_protocol_registry_items)}; diff --git a/applications/plugins/protoview/fields.c b/applications/plugins/protoview/fields.c index bc62cda54..47d573f4f 100644 --- a/applications/plugins/protoview/fields.c +++ b/applications/plugins/protoview/fields.c @@ -7,8 +7,8 @@ /* Create a new field of the specified type. Without populating its * type-specific value. */ -static ProtoViewField *field_new(ProtoViewFieldType type, const char *name) { - ProtoViewField *f = malloc(sizeof(*f)); +static ProtoViewField* field_new(ProtoViewFieldType type, const char* name) { + ProtoViewField* f = malloc(sizeof(*f)); f->type = type; f->name = strdup(name); return f; @@ -16,72 +16,80 @@ static ProtoViewField *field_new(ProtoViewFieldType type, const char *name) { /* Free only the auxiliary data of a field, used to represent the * current type. Name and type are not touched. */ -static void field_free_aux_data(ProtoViewField *f) { +static void field_free_aux_data(ProtoViewField* f) { switch(f->type) { - case FieldTypeStr: free(f->str); break; - case FieldTypeBytes: free(f->bytes); break; - default: break; // Nothing to free for other types. + case FieldTypeStr: + free(f->str); + break; + case FieldTypeBytes: + free(f->bytes); + break; + default: + break; // Nothing to free for other types. } } /* Free a field an associated data. */ -static void field_free(ProtoViewField *f) { +static void field_free(ProtoViewField* f) { field_free_aux_data(f); free(f->name); free(f); } /* Return the type of the field as string. */ -const char *field_get_type_name(ProtoViewField *f) { +const char* field_get_type_name(ProtoViewField* f) { switch(f->type) { - case FieldTypeStr: return "str"; - case FieldTypeSignedInt: return "int"; - case FieldTypeUnsignedInt: return "uint"; - case FieldTypeBinary: return "bin"; - case FieldTypeHex: return "hex"; - case FieldTypeBytes: return "bytes"; - case FieldTypeFloat: return "float"; + case FieldTypeStr: + return "str"; + case FieldTypeSignedInt: + return "int"; + case FieldTypeUnsignedInt: + return "uint"; + case FieldTypeBinary: + return "bin"; + case FieldTypeHex: + return "hex"; + case FieldTypeBytes: + return "bytes"; + case FieldTypeFloat: + return "float"; } return "unknown"; } /* Set a string representation of the specified field in buf. */ -int field_to_string(char *buf, size_t len, ProtoViewField *f) { +int field_to_string(char* buf, size_t len, ProtoViewField* f) { switch(f->type) { case FieldTypeStr: - return snprintf(buf,len,"%s", f->str); + return snprintf(buf, len, "%s", f->str); case FieldTypeSignedInt: - return snprintf(buf,len,"%lld", (long long) f->value); + return snprintf(buf, len, "%lld", (long long)f->value); case FieldTypeUnsignedInt: - return snprintf(buf,len,"%llu", (unsigned long long) f->uvalue); - case FieldTypeBinary: - { - uint64_t test_bit = (1 << (f->len-1)); - uint64_t idx = 0; - while(idx < len-1 && test_bit) { - buf[idx++] = (f->uvalue & test_bit) ? '1' : '0'; - test_bit >>= 1; - } - buf[idx] = 0; - return idx; + return snprintf(buf, len, "%llu", (unsigned long long)f->uvalue); + case FieldTypeBinary: { + uint64_t test_bit = (1 << (f->len - 1)); + uint64_t idx = 0; + while(idx < len - 1 && test_bit) { + buf[idx++] = (f->uvalue & test_bit) ? '1' : '0'; + test_bit >>= 1; } + buf[idx] = 0; + return idx; + } case FieldTypeHex: - return snprintf(buf, len, "%*llX", (int)(f->len+7)/8, f->uvalue); + return snprintf(buf, len, "%*llX", (int)(f->len + 7) / 8, f->uvalue); case FieldTypeFloat: return snprintf(buf, len, "%.*f", (int)f->len, (double)f->fvalue); - case FieldTypeBytes: - { - uint64_t idx = 0; - while(idx < len-1 && idx < f->len) { - const char *charset = "0123456789ABCDEF"; - uint32_t nibble = idx & 1 ? - (f->bytes[idx/2] & 0xf) : - (f->bytes[idx/2] >> 4); - buf[idx++] = charset[nibble]; - } - buf[idx] = 0; - return idx; + case FieldTypeBytes: { + uint64_t idx = 0; + while(idx < len - 1 && idx < f->len) { + const char* charset = "0123456789ABCDEF"; + uint32_t nibble = idx & 1 ? (f->bytes[idx / 2] & 0xf) : (f->bytes[idx / 2] >> 4); + buf[idx++] = charset[nibble]; } + buf[idx] = 0; + return idx; + } } return 0; } @@ -96,7 +104,7 @@ int field_to_string(char *buf, size_t len, ProtoViewField *f) { * The function returns true if the filed was successfully set to the * new value, otherwise if the specified value is invalid for the * field type, false is returned. */ -bool field_set_from_string(ProtoViewField *f, char *buf, size_t len) { +bool field_set_from_string(ProtoViewField* f, char* buf, size_t len) { // Initialize values to zero since the Flipper sscanf() implementation // is fuzzy... may populate only part of the value. long long val = 0; @@ -107,80 +115,78 @@ bool field_set_from_string(ProtoViewField *f, char *buf, size_t len) { case FieldTypeStr: free(f->str); f->len = len; - f->str = malloc(len+1); - memcpy(f->str,buf,len+1); + f->str = malloc(len + 1); + memcpy(f->str, buf, len + 1); break; case FieldTypeSignedInt: - if (!sscanf(buf,"%lld",&val)) return false; + if(!sscanf(buf, "%lld", &val)) return false; f->value = val; break; case FieldTypeUnsignedInt: - if (!sscanf(buf,"%llu",&uval)) return false; + if(!sscanf(buf, "%llu", &uval)) return false; f->uvalue = uval; break; - case FieldTypeBinary: - { - uint64_t bit_to_set = (1 << (len-1)); - uint64_t idx = 0; - uval = 0; - while(buf[idx]) { - if (buf[idx] == '1') uval |= bit_to_set; - else if (buf[idx] != '0') return false; - bit_to_set >>= 1; - idx++; - } - f->uvalue = uval; + case FieldTypeBinary: { + uint64_t bit_to_set = (1 << (len - 1)); + uint64_t idx = 0; + uval = 0; + while(buf[idx]) { + if(buf[idx] == '1') + uval |= bit_to_set; + else if(buf[idx] != '0') + return false; + bit_to_set >>= 1; + idx++; } - break; + f->uvalue = uval; + } break; case FieldTypeHex: - if (!sscanf(buf,"%llx",&uval) && - !sscanf(buf,"%llX",&uval)) return false; + if(!sscanf(buf, "%llx", &uval) && !sscanf(buf, "%llX", &uval)) return false; f->uvalue = uval; break; case FieldTypeFloat: - if (!sscanf(buf,"%f",&fval)) return false; + if(!sscanf(buf, "%f", &fval)) return false; f->fvalue = fval; break; - case FieldTypeBytes: - { - if (len > f->len) return false; - uint64_t idx = 0; - while(buf[idx]) { - uint8_t nibble = 0; - char c = toupper(buf[idx]); - if (c >= '0' && c <= '9') nibble = c-'0'; - else if (c >= 'A' && c <= 'F') nibble = 10+(c-'A'); - else return false; + case FieldTypeBytes: { + if(len > f->len) return false; + uint64_t idx = 0; + while(buf[idx]) { + uint8_t nibble = 0; + char c = toupper(buf[idx]); + if(c >= '0' && c <= '9') + nibble = c - '0'; + else if(c >= 'A' && c <= 'F') + nibble = 10 + (c - 'A'); + else + return false; - if (idx & 1) { - f->bytes[idx/2] = - (f->bytes[idx/2] & 0xF0) | nibble; - } else { - f->bytes[idx/2] = - (f->bytes[idx/2] & 0x0F) | (nibble<<4); - } - idx++; + if(idx & 1) { + f->bytes[idx / 2] = (f->bytes[idx / 2] & 0xF0) | nibble; + } else { + f->bytes[idx / 2] = (f->bytes[idx / 2] & 0x0F) | (nibble << 4); } - buf[idx] = 0; + idx++; } - break; + buf[idx] = 0; + } break; } return true; } /* Set the 'dst' field to contain a copy of the value of the 'src' * field. The field name is not modified. */ -void field_set_from_field(ProtoViewField *dst, ProtoViewField *src) { +void field_set_from_field(ProtoViewField* dst, ProtoViewField* src) { field_free_aux_data(dst); dst->type = src->type; dst->len = src->len; - switch(src->type) { + switch(src->type) { case FieldTypeStr: dst->str = strdup(src->str); break; case FieldTypeBytes: dst->bytes = malloc(src->len); - memcpy(dst->bytes,src->bytes,dst->len); + memcpy(dst->bytes, src->bytes, dst->len); break; case FieldTypeSignedInt: dst->value = src->value; @@ -199,159 +205,159 @@ void field_set_from_field(ProtoViewField *dst, ProtoViewField *src) { /* Increment the specified field value of 'incr'. If the field type * does not support increments false is returned, otherwise the * action is performed. */ -bool field_incr_value(ProtoViewField *f, int incr) { +bool field_incr_value(ProtoViewField* f, int incr) { switch(f->type) { - case FieldTypeStr: return false; - case FieldTypeSignedInt: { - /* Wrap around depending on the number of bits (f->len) + case FieldTypeStr: + return false; + case FieldTypeSignedInt: { + /* Wrap around depending on the number of bits (f->len) * the integer was declared to have. */ - int64_t max = (1ULL << (f->len-1))-1; - int64_t min = -max-1; - int64_t v = (int64_t)f->value + incr; - if (v > max) v = min+(v-max-1); - if (v < min) v = max+(v-min+1); - f->value = v; - break; - } - case FieldTypeBinary: - case FieldTypeHex: - case FieldTypeUnsignedInt: { - /* Wrap around like for the unsigned case, but here + int64_t max = (1ULL << (f->len - 1)) - 1; + int64_t min = -max - 1; + int64_t v = (int64_t)f->value + incr; + if(v > max) v = min + (v - max - 1); + if(v < min) v = max + (v - min + 1); + f->value = v; + break; + } + case FieldTypeBinary: + case FieldTypeHex: + case FieldTypeUnsignedInt: { + /* Wrap around like for the unsigned case, but here * is simpler. */ - uint64_t max = (1ULL << f->len)-1; // Broken for 64 bits. - uint64_t uv = (uint64_t)f->value + incr; - if (uv > max) uv = uv & max; - f->uvalue = uv; - break; - } - case FieldTypeFloat: - f->fvalue += incr; - break; - case FieldTypeBytes: { - // For bytes we only support single unit increments. - if (incr != -1 && incr != 1) return false; - for (int j = f->len-1; j >= 0; j--) { - uint8_t nibble = (j&1) ? (f->bytes[j/2] & 0x0F) : - ((f->bytes[j/2] & 0xF0) >> 4); + uint64_t max = (1ULL << f->len) - 1; // Broken for 64 bits. + uint64_t uv = (uint64_t)f->value + incr; + if(uv > max) uv = uv & max; + f->uvalue = uv; + break; + } + case FieldTypeFloat: + f->fvalue += incr; + break; + case FieldTypeBytes: { + // For bytes we only support single unit increments. + if(incr != -1 && incr != 1) return false; + for(int j = f->len - 1; j >= 0; j--) { + uint8_t nibble = (j & 1) ? (f->bytes[j / 2] & 0x0F) : ((f->bytes[j / 2] & 0xF0) >> 4); - nibble += incr; - nibble &= 0x0F; + nibble += incr; + nibble &= 0x0F; - f->bytes[j/2] = (j&1) ? ((f->bytes[j/2] & 0xF0) | nibble) : - ((f->bytes[j/2] & 0x0F) | (nibble<<4)); + f->bytes[j / 2] = (j & 1) ? ((f->bytes[j / 2] & 0xF0) | nibble) : + ((f->bytes[j / 2] & 0x0F) | (nibble << 4)); - /* Propagate the operation on overflow of this nibble. */ - if ((incr == 1 && nibble == 0) || - (incr == -1 && nibble == 0xf)) - { - continue; - } - break; // Otherwise stop the loop here. + /* Propagate the operation on overflow of this nibble. */ + if((incr == 1 && nibble == 0) || (incr == -1 && nibble == 0xf)) { + continue; } - break; + break; // Otherwise stop the loop here. } + break; + } } return true; } - /* Free a field set and its contained fields. */ -void fieldset_free(ProtoViewFieldSet *fs) { - for (uint32_t j = 0; j < fs->numfields; j++) - field_free(fs->fields[j]); +void fieldset_free(ProtoViewFieldSet* fs) { + for(uint32_t j = 0; j < fs->numfields; j++) field_free(fs->fields[j]); free(fs->fields); free(fs); } /* Allocate and init an empty field set. */ -ProtoViewFieldSet *fieldset_new(void) { - ProtoViewFieldSet *fs = malloc(sizeof(*fs)); +ProtoViewFieldSet* fieldset_new(void) { + ProtoViewFieldSet* fs = malloc(sizeof(*fs)); fs->numfields = 0; fs->fields = NULL; return fs; } /* Append an already allocated field at the end of the specified field set. */ -static void fieldset_add_field(ProtoViewFieldSet *fs, ProtoViewField *field) { +static void fieldset_add_field(ProtoViewFieldSet* fs, ProtoViewField* field) { fs->numfields++; - fs->fields = realloc(fs->fields,sizeof(ProtoViewField*)*fs->numfields); - fs->fields[fs->numfields-1] = field; + fs->fields = realloc(fs->fields, sizeof(ProtoViewField*) * fs->numfields); + fs->fields[fs->numfields - 1] = field; } /* Allocate and append an integer field. */ -void fieldset_add_int(ProtoViewFieldSet *fs, const char *name, int64_t val, uint8_t bits) { - ProtoViewField *f = field_new(FieldTypeSignedInt,name); +void fieldset_add_int(ProtoViewFieldSet* fs, const char* name, int64_t val, uint8_t bits) { + ProtoViewField* f = field_new(FieldTypeSignedInt, name); f->value = val; f->len = bits; - fieldset_add_field(fs,f); + fieldset_add_field(fs, f); } /* Allocate and append an unsigned field. */ -void fieldset_add_uint(ProtoViewFieldSet *fs, const char *name, uint64_t uval, uint8_t bits) { - ProtoViewField *f = field_new(FieldTypeUnsignedInt,name); +void fieldset_add_uint(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits) { + ProtoViewField* f = field_new(FieldTypeUnsignedInt, name); f->uvalue = uval; f->len = bits; - fieldset_add_field(fs,f); + fieldset_add_field(fs, f); } /* Allocate and append a hex field. This is an unsigned number but * with an hex representation. */ -void fieldset_add_hex(ProtoViewFieldSet *fs, const char *name, uint64_t uval, uint8_t bits) { - ProtoViewField *f = field_new(FieldTypeHex,name); +void fieldset_add_hex(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits) { + ProtoViewField* f = field_new(FieldTypeHex, name); f->uvalue = uval; f->len = bits; - fieldset_add_field(fs,f); + fieldset_add_field(fs, f); } /* Allocate and append a bin field. This is an unsigned number but * with a binary representation. */ -void fieldset_add_bin(ProtoViewFieldSet *fs, const char *name, uint64_t uval, uint8_t bits) { - ProtoViewField *f = field_new(FieldTypeBinary,name); +void fieldset_add_bin(ProtoViewFieldSet* fs, const char* name, uint64_t uval, uint8_t bits) { + ProtoViewField* f = field_new(FieldTypeBinary, name); f->uvalue = uval; f->len = bits; - fieldset_add_field(fs,f); + fieldset_add_field(fs, f); } /* Allocate and append a string field. */ -void fieldset_add_str(ProtoViewFieldSet *fs, const char *name, const char *s) { - ProtoViewField *f = field_new(FieldTypeStr,name); +void fieldset_add_str(ProtoViewFieldSet* fs, const char* name, const char* s) { + ProtoViewField* f = field_new(FieldTypeStr, name); f->str = strdup(s); f->len = strlen(s); - fieldset_add_field(fs,f); + fieldset_add_field(fs, f); } /* Allocate and append a bytes field. Note that 'count' is specified in * nibbles (bytes*2). */ -void fieldset_add_bytes(ProtoViewFieldSet *fs, const char *name, const uint8_t *bytes, uint32_t count_nibbles) { - uint32_t numbytes = (count_nibbles+count_nibbles%2)/2; - ProtoViewField *f = field_new(FieldTypeBytes,name); +void fieldset_add_bytes( + ProtoViewFieldSet* fs, + const char* name, + const uint8_t* bytes, + uint32_t count_nibbles) { + uint32_t numbytes = (count_nibbles + count_nibbles % 2) / 2; + ProtoViewField* f = field_new(FieldTypeBytes, name); f->bytes = malloc(numbytes); - memcpy(f->bytes,bytes,numbytes); + memcpy(f->bytes, bytes, numbytes); f->len = count_nibbles; - fieldset_add_field(fs,f); + fieldset_add_field(fs, f); } /* Allocate and append a float field. */ -void fieldset_add_float(ProtoViewFieldSet *fs, const char *name, float val, uint32_t digits_after_dot) { - ProtoViewField *f = field_new(FieldTypeFloat,name); +void fieldset_add_float( + ProtoViewFieldSet* fs, + const char* name, + float val, + uint32_t digits_after_dot) { + ProtoViewField* f = field_new(FieldTypeFloat, name); f->fvalue = val; f->len = digits_after_dot; - fieldset_add_field(fs,f); + fieldset_add_field(fs, f); } /* For each field of the destination filedset 'dst', look for a matching * field name/type in the source fieldset 'src', and if one is found copy * its value into the 'dst' field. */ -void fieldset_copy_matching_fields(ProtoViewFieldSet *dst, - ProtoViewFieldSet *src) -{ - for (uint32_t j = 0; j < dst->numfields; j++) { - for (uint32_t i = 0; i < src->numfields; i++) { - if (dst->fields[j]->type == src->fields[i]->type && - !strcmp(dst->fields[j]->name,src->fields[i]->name)) - { - field_set_from_field(dst->fields[j], - src->fields[i]); +void fieldset_copy_matching_fields(ProtoViewFieldSet* dst, ProtoViewFieldSet* src) { + for(uint32_t j = 0; j < dst->numfields; j++) { + for(uint32_t i = 0; i < src->numfields; i++) { + if(dst->fields[j]->type == src->fields[i]->type && + !strcmp(dst->fields[j]->name, src->fields[i]->name)) { + field_set_from_field(dst->fields[j], src->fields[i]); } } } diff --git a/applications/plugins/protoview/protocols/b4b1.c b/applications/plugins/protoview/protocols/b4b1.c index 7308d1211..52c59d24b 100644 --- a/applications/plugins/protoview/protocols/b4b1.c +++ b/applications/plugins/protoview/protocols/b4b1.c @@ -9,9 +9,9 @@ #include "../app.h" -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { - if (numbits < 30) return false; - const char *sync_patterns[3] = { +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + if(numbits < 30) return false; + const char* sync_patterns[3] = { "10000000000000000000000000000001", /* 30 zero bits. */ "100000000000000000000000000000001", /* 31 zero bits. */ "1000000000000000000000000000000001", /* 32 zero bits. */ @@ -19,70 +19,67 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView uint32_t off; int j; - for (j = 0; j < 3; j++) { - off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_patterns[j]); - if (off != BITMAP_SEEK_NOT_FOUND) break; + for(j = 0; j < 3; j++) { + off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_patterns[j]); + if(off != BITMAP_SEEK_NOT_FOUND) break; } - if (off == BITMAP_SEEK_NOT_FOUND) return false; - if (DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 preamble at: %lu",off); + if(off == BITMAP_SEEK_NOT_FOUND) return false; + if(DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 preamble at: %lu", off); info->start_off = off; // Seek data setction. Why -1? Last bit is data. - off += strlen(sync_patterns[j])-1; + off += strlen(sync_patterns[j]) - 1; uint8_t d[3]; /* 24 bits of data. */ - uint32_t decoded = - convert_from_line_code(d,sizeof(d),bits,numbytes,off,"1000","1110"); + uint32_t decoded = convert_from_line_code(d, sizeof(d), bits, numbytes, off, "1000", "1110"); - if (DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 decoded: %lu",decoded); - if (decoded < 24) return false; + if(DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 decoded: %lu", decoded); + if(decoded < 24) return false; - off += 24*4; // seek to end symbol offset to calculate the length. + off += 24 * 4; // seek to end symbol offset to calculate the length. off++; // In this protocol there is a final pulse as terminator. info->pulses_count = off - info->start_off; - fieldset_add_bytes(info->fieldset,"id",d,5); - fieldset_add_uint(info->fieldset,"button",d[2]&0xf,4); + fieldset_add_bytes(info->fieldset, "id", d, 5); + fieldset_add_uint(info->fieldset, "button", d[2] & 0xf, 4); return true; } /* Give fields and defaults for the signal creator. */ -static void get_fields(ProtoViewFieldSet *fieldset) { - uint8_t default_id[3]= {0xAB, 0xCD, 0xE0}; - fieldset_add_bytes(fieldset,"id",default_id,5); - fieldset_add_uint(fieldset,"button",1,4); +static void get_fields(ProtoViewFieldSet* fieldset) { + uint8_t default_id[3] = {0xAB, 0xCD, 0xE0}; + fieldset_add_bytes(fieldset, "id", default_id, 5); + fieldset_add_uint(fieldset, "button", 1, 4); } /* Create a signal. */ -static void build_message(RawSamplesBuffer *samples, ProtoViewFieldSet *fs) -{ +static void build_message(RawSamplesBuffer* samples, ProtoViewFieldSet* fs) { uint32_t te = 334; // Short pulse duration in microseconds. // Sync: 1 te pulse, 31 te gap. - raw_samples_add(samples,true,te); - raw_samples_add(samples,false,te*31); + raw_samples_add(samples, true, te); + raw_samples_add(samples, false, te * 31); // ID + button state uint8_t data[3]; - memcpy(data,fs->fields[0]->bytes,3); - data[2] = (data[2]&0xF0) | (fs->fields[1]->uvalue & 0xF); - for (uint32_t j = 0; j < 24; j++) { - if (bitmap_get(data,sizeof(data),j)) { - raw_samples_add(samples,true,te*3); - raw_samples_add(samples,false,te); + memcpy(data, fs->fields[0]->bytes, 3); + data[2] = (data[2] & 0xF0) | (fs->fields[1]->uvalue & 0xF); + for(uint32_t j = 0; j < 24; j++) { + if(bitmap_get(data, sizeof(data), j)) { + raw_samples_add(samples, true, te * 3); + raw_samples_add(samples, false, te); } else { - raw_samples_add(samples,true,te); - raw_samples_add(samples,false,te*3); + raw_samples_add(samples, true, te); + raw_samples_add(samples, false, te * 3); } } // Signal terminator. Just a single short pulse. - raw_samples_add(samples,true,te); + raw_samples_add(samples, true, te); } ProtoViewDecoder B4B1Decoder = { .name = "PT/SC remote", .decode = decode, .get_fields = get_fields, - .build_message = build_message -}; + .build_message = build_message}; diff --git a/applications/plugins/protoview/protocols/keeloq.c b/applications/plugins/protoview/protocols/keeloq.c index 0741eac47..298c690d4 100644 --- a/applications/plugins/protoview/protocols/keeloq.c +++ b/applications/plugins/protoview/protocols/keeloq.c @@ -24,16 +24,16 @@ #include "../app.h" -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { - +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { /* In the sync pattern, we require the 12 high/low pulses and at least * half the gap we expect (5 pulses times, one is the final zero in the * 24 symbols high/low sequence, then other 4). */ - const char *sync_pattern = "101010101010101010101010" "0000"; - uint8_t sync_len = 24+4; - if (numbits-sync_len+sync_len < 3*66) return false; - uint32_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern); - if (off == BITMAP_SEEK_NOT_FOUND) return false; + const char* sync_pattern = "101010101010101010101010" + "0000"; + uint8_t sync_len = 24 + 4; + if(numbits - sync_len + sync_len < 3 * 66) return false; + uint32_t off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_pattern); + if(off == BITMAP_SEEK_NOT_FOUND) return false; info->start_off = off; off += sync_len; // Seek start of message. @@ -42,84 +42,77 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView * symbols of gap, to avoid missing the signal for a matter of wrong * timing. */ uint8_t gap_len = 0; - while(gap_len <= 7 && bitmap_get(bits,numbytes,off+gap_len) == 0) - gap_len++; - if (gap_len < 3 || gap_len > 7) return false; + while(gap_len <= 7 && bitmap_get(bits, numbytes, off + gap_len) == 0) gap_len++; + if(gap_len < 3 || gap_len > 7) return false; off += gap_len; FURI_LOG_E(TAG, "Keeloq preamble+sync found"); uint8_t raw[9] = {0}; - uint32_t decoded = - convert_from_line_code(raw,sizeof(raw),bits,numbytes,off, - "110","100"); /* Pulse width modulation. */ + uint32_t decoded = convert_from_line_code( + raw, sizeof(raw), bits, numbytes, off, "110", "100"); /* Pulse width modulation. */ FURI_LOG_E(TAG, "Keeloq decoded bits: %lu", decoded); - if (decoded < 66) return false; /* Require the full 66 bits. */ + if(decoded < 66) return false; /* Require the full 66 bits. */ - info->pulses_count = (off+66*3) - info->start_off; + info->pulses_count = (off + 66 * 3) - info->start_off; - bitmap_reverse_bytes_bits(raw,sizeof(raw)); /* Keeloq is LSB first. */ + bitmap_reverse_bytes_bits(raw, sizeof(raw)); /* Keeloq is LSB first. */ - int buttons = raw[7]>>4; - int lowbat = (raw[8]&0x1) == 0; // Actual bit meaning: good battery level - int alwaysone = (raw[8]&0x2) != 0; + int buttons = raw[7] >> 4; + int lowbat = (raw[8] & 0x1) == 0; // Actual bit meaning: good battery level + int alwaysone = (raw[8] & 0x2) != 0; - fieldset_add_bytes(info->fieldset,"encr",raw,8); - raw[7] = raw[7]<<4; // Make ID bits contiguous - fieldset_add_bytes(info->fieldset,"id",raw+4,7); // 28 bits, 7 nibbles - fieldset_add_bin(info->fieldset,"s[2,1,0,3]",buttons,4); - fieldset_add_bin(info->fieldset,"low battery",lowbat,1); - fieldset_add_bin(info->fieldset,"always one",alwaysone,1); + fieldset_add_bytes(info->fieldset, "encr", raw, 8); + raw[7] = raw[7] << 4; // Make ID bits contiguous + fieldset_add_bytes(info->fieldset, "id", raw + 4, 7); // 28 bits, 7 nibbles + fieldset_add_bin(info->fieldset, "s[2,1,0,3]", buttons, 4); + fieldset_add_bin(info->fieldset, "low battery", lowbat, 1); + fieldset_add_bin(info->fieldset, "always one", alwaysone, 1); return true; } -static void get_fields(ProtoViewFieldSet *fieldset) { +static void get_fields(ProtoViewFieldSet* fieldset) { uint8_t remote_id[4] = {0xab, 0xcd, 0xef, 0xa0}; uint8_t encr[4] = {0xab, 0xab, 0xab, 0xab}; - fieldset_add_bytes(fieldset,"encr",encr,8); - fieldset_add_bytes(fieldset,"id",remote_id,7); - fieldset_add_bin(fieldset,"s[2,1,0,3]",2,4); - fieldset_add_bin(fieldset,"low battery",0,1); - fieldset_add_bin(fieldset,"always one",1,1); + fieldset_add_bytes(fieldset, "encr", encr, 8); + fieldset_add_bytes(fieldset, "id", remote_id, 7); + fieldset_add_bin(fieldset, "s[2,1,0,3]", 2, 4); + fieldset_add_bin(fieldset, "low battery", 0, 1); + fieldset_add_bin(fieldset, "always one", 1, 1); } -static void build_message(RawSamplesBuffer *samples, ProtoViewFieldSet *fieldset) -{ +static void build_message(RawSamplesBuffer* samples, ProtoViewFieldSet* fieldset) { uint32_t te = 380; // Short pulse duration in microseconds. // Sync: 12 pairs of pulse/gap + 9 times gap - for (int j = 0; j < 12; j++) { - raw_samples_add(samples,true,te); - raw_samples_add(samples,false,te); + for(int j = 0; j < 12; j++) { + raw_samples_add(samples, true, te); + raw_samples_add(samples, false, te); } - raw_samples_add(samples,false,te*9); + raw_samples_add(samples, false, te * 9); // Data, 66 bits. uint8_t data[9] = {0}; - memcpy(data,fieldset->fields[0]->bytes,4); // Encrypted part. - memcpy(data+4,fieldset->fields[1]->bytes,4); // ID. - data[7] = data[7]>>4 | fieldset->fields[2]->uvalue << 4; // s[2,1,0,3] + memcpy(data, fieldset->fields[0]->bytes, 4); // Encrypted part. + memcpy(data + 4, fieldset->fields[1]->bytes, 4); // ID. + data[7] = data[7] >> 4 | fieldset->fields[2]->uvalue << 4; // s[2,1,0,3] int low_battery = fieldset->fields[3] != 0; int always_one = fieldset->fields[4] != 0; low_battery = !low_battery; // Bit real meaning is good battery level. data[8] |= low_battery; data[8] |= (always_one << 1); - bitmap_reverse_bytes_bits(data,sizeof(data)); /* Keeloq is LSB first. */ + bitmap_reverse_bytes_bits(data, sizeof(data)); /* Keeloq is LSB first. */ - for (int j = 0; j < 66; j++) { - if (bitmap_get(data,9,j)) { - raw_samples_add(samples,true,te); - raw_samples_add(samples,false,te*2); + for(int j = 0; j < 66; j++) { + if(bitmap_get(data, 9, j)) { + raw_samples_add(samples, true, te); + raw_samples_add(samples, false, te * 2); } else { - raw_samples_add(samples,true,te*2); - raw_samples_add(samples,false,te); + raw_samples_add(samples, true, te * 2); + raw_samples_add(samples, false, te); } } } -ProtoViewDecoder KeeloqDecoder = { - .name = "Keeloq", - .decode = decode, - .get_fields = get_fields, - .build_message = build_message -}; +ProtoViewDecoder KeeloqDecoder = + {.name = "Keeloq", .decode = decode, .get_fields = get_fields, .build_message = build_message}; diff --git a/applications/plugins/protoview/protocols/oregon2.c b/applications/plugins/protoview/protocols/oregon2.c index 1d909a504..f67e85a2d 100644 --- a/applications/plugins/protoview/protocols/oregon2.c +++ b/applications/plugins/protoview/protocols/oregon2.c @@ -6,11 +6,14 @@ #include "../app.h" -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { - if (numbits < 32) return false; - const char *sync_pattern = "01100110" "01100110" "10010110" "10010110"; - uint64_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern); - if (off == BITMAP_SEEK_NOT_FOUND) return false; +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + if(numbits < 32) return false; + const char* sync_pattern = "01100110" + "01100110" + "10010110" + "10010110"; + uint64_t off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_pattern); + if(off == BITMAP_SEEK_NOT_FOUND) return false; FURI_LOG_E(TAG, "Oregon2 preamble+sync found"); info->start_off = off; @@ -18,50 +21,61 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView uint8_t buffer[8], raw[8] = {0}; uint32_t decoded = - convert_from_line_code(buffer,sizeof(buffer),bits,numbytes,off,"1001","0110"); + convert_from_line_code(buffer, sizeof(buffer), bits, numbytes, off, "1001", "0110"); FURI_LOG_E(TAG, "Oregon2 decoded bits: %lu", decoded); - if (decoded < 11*4) return false; /* Minimum len to extract some data. */ - info->pulses_count = (off+11*4*4) - info->start_off; + if(decoded < 11 * 4) return false; /* Minimum len to extract some data. */ + info->pulses_count = (off + 11 * 4 * 4) - info->start_off; char temp[3] = {0}, hum[2] = {0}; uint8_t deviceid[2]; - for (int j = 0; j < 64; j += 4) { + for(int j = 0; j < 64; j += 4) { uint8_t nib[1]; - nib[0] = (bitmap_get(buffer,8,j+0) | - bitmap_get(buffer,8,j+1) << 1 | - bitmap_get(buffer,8,j+2) << 2 | - bitmap_get(buffer,8,j+3) << 3); - if (DEBUG_MSG) FURI_LOG_E(TAG, "Not inverted nibble[%d]: %x", j/4, (unsigned int)nib[0]); - raw[j/8] |= nib[0] << (4-(j%4)); - switch(j/4) { - case 1: deviceid[0] |= nib[0]; break; - case 0: deviceid[0] |= nib[0] << 4; break; - case 3: deviceid[1] |= nib[0]; break; - case 2: deviceid[1] |= nib[0] << 4; break; - case 10: temp[0] = nib[0]; break; + nib[0] = + (bitmap_get(buffer, 8, j + 0) | bitmap_get(buffer, 8, j + 1) << 1 | + bitmap_get(buffer, 8, j + 2) << 2 | bitmap_get(buffer, 8, j + 3) << 3); + if(DEBUG_MSG) FURI_LOG_E(TAG, "Not inverted nibble[%d]: %x", j / 4, (unsigned int)nib[0]); + raw[j / 8] |= nib[0] << (4 - (j % 4)); + switch(j / 4) { + case 1: + deviceid[0] |= nib[0]; + break; + case 0: + deviceid[0] |= nib[0] << 4; + break; + case 3: + deviceid[1] |= nib[0]; + break; + case 2: + deviceid[1] |= nib[0] << 4; + break; + case 10: + temp[0] = nib[0]; + break; /* Fixme: take the temperature sign from nibble 11. */ - case 9: temp[1] = nib[0]; break; - case 8: temp[2] = nib[0]; break; - case 13: hum[0] = nib[0]; break; - case 12: hum[1] = nib[0]; break; + case 9: + temp[1] = nib[0]; + break; + case 8: + temp[2] = nib[0]; + break; + case 13: + hum[0] = nib[0]; + break; + case 12: + hum[1] = nib[0]; + break; } } - float tempval = ((temp[0]-'0')*10) + - (temp[1]-'0') + - ((float)(temp[2]-'0')*0.1); - int humval = (hum[0]-'0')*10 + (hum[1]-'0'); + float tempval = ((temp[0] - '0') * 10) + (temp[1] - '0') + ((float)(temp[2] - '0') * 0.1); + int humval = (hum[0] - '0') * 10 + (hum[1] - '0'); - fieldset_add_bytes(info->fieldset,"Sensor ID",deviceid,4); - fieldset_add_float(info->fieldset,"Temperature",tempval,1); - fieldset_add_uint(info->fieldset,"Humidity",humval,7); + fieldset_add_bytes(info->fieldset, "Sensor ID", deviceid, 4); + fieldset_add_float(info->fieldset, "Temperature", tempval, 1); + fieldset_add_uint(info->fieldset, "Humidity", humval, 7); return true; } -ProtoViewDecoder Oregon2Decoder = { - .name = "Oregon2", - .decode = decode, - .get_fields = NULL, - .build_message = NULL -}; +ProtoViewDecoder Oregon2Decoder = + {.name = "Oregon2", .decode = decode, .get_fields = NULL, .build_message = NULL}; diff --git a/applications/plugins/protoview/protocols/tpms/citroen.c b/applications/plugins/protoview/protocols/tpms/citroen.c index d8a1681e4..ecd8fb983 100644 --- a/applications/plugins/protoview/protocols/tpms/citroen.c +++ b/applications/plugins/protoview/protocols/tpms/citroen.c @@ -7,55 +7,49 @@ #include "../../app.h" -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { - +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { /* We consider a preamble of 17 symbols. They are more, but the decoding * is more likely to happen if we don't pretend to receive from the * very start of the message. */ uint32_t sync_len = 17; - const char *sync_pattern = "10101010101010110"; - if (numbits-sync_len < 8*10) return false; /* Expect 10 bytes. */ + const char* sync_pattern = "10101010101010110"; + if(numbits - sync_len < 8 * 10) return false; /* Expect 10 bytes. */ - uint64_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern); - if (off == BITMAP_SEEK_NOT_FOUND) return false; + uint64_t off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_pattern); + if(off == BITMAP_SEEK_NOT_FOUND) return false; FURI_LOG_E(TAG, "Renault TPMS preamble+sync found"); info->start_off = off; off += sync_len; /* Skip preamble + sync. */ uint8_t raw[10]; - uint32_t decoded = - convert_from_line_code(raw,sizeof(raw),bits,numbytes,off, - "01","10"); /* Manchester. */ + uint32_t decoded = convert_from_line_code( + raw, sizeof(raw), bits, numbytes, off, "01", "10"); /* Manchester. */ FURI_LOG_E(TAG, "Citroen TPMS decoded bits: %lu", decoded); - if (decoded < 8*10) return false; /* Require the full 10 bytes. */ + if(decoded < 8 * 10) return false; /* Require the full 10 bytes. */ /* Check the CRC. It's a simple XOR of bytes 1-9, the first byte * is not included. The meaning of the first byte is unknown and * we don't display it. */ uint8_t crc = 0; - for (int j = 1; j < 10; j++) crc ^= raw[j]; - if (crc != 0) return false; /* Require sane checksum. */ + for(int j = 1; j < 10; j++) crc ^= raw[j]; + if(crc != 0) return false; /* Require sane checksum. */ - info->pulses_count = (off+8*10*2) - info->start_off; + info->pulses_count = (off + 8 * 10 * 2) - info->start_off; int repeat = raw[5] & 0xf; - float kpa = (float)raw[6]*1.364; - int temp = raw[7]-50; + float kpa = (float)raw[6] * 1.364; + int temp = raw[7] - 50; int battery = raw[8]; /* This may be the battery. It's not clear. */ - fieldset_add_bytes(info->fieldset,"Tire ID",raw+1,4*2); - fieldset_add_float(info->fieldset,"Pressure kpa",kpa,2); - fieldset_add_int(info->fieldset,"Temperature C",temp,8); - fieldset_add_uint(info->fieldset,"Repeat",repeat,4); - fieldset_add_uint(info->fieldset,"Battery",battery,8); + fieldset_add_bytes(info->fieldset, "Tire ID", raw + 1, 4 * 2); + fieldset_add_float(info->fieldset, "Pressure kpa", kpa, 2); + fieldset_add_int(info->fieldset, "Temperature C", temp, 8); + fieldset_add_uint(info->fieldset, "Repeat", repeat, 4); + fieldset_add_uint(info->fieldset, "Battery", battery, 8); return true; } -ProtoViewDecoder CitroenTPMSDecoder = { - .name = "Citroen TPMS", - .decode = decode, - .get_fields = NULL, - .build_message = NULL -}; +ProtoViewDecoder CitroenTPMSDecoder = + {.name = "Citroen TPMS", .decode = decode, .get_fields = NULL, .build_message = NULL}; diff --git a/applications/plugins/protoview/protocols/tpms/ford.c b/applications/plugins/protoview/protocols/tpms/ford.c index abdb692ee..3816e72f9 100644 --- a/applications/plugins/protoview/protocols/tpms/ford.c +++ b/applications/plugins/protoview/protocols/tpms/ford.c @@ -10,54 +10,49 @@ #include "../../app.h" -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + const char* sync_pattern = "010101010101" + "0110"; + uint8_t sync_len = 12 + 4; /* We just use 12 preamble symbols + sync. */ + if(numbits - sync_len < 8 * 8) return false; - const char *sync_pattern = "010101010101" "0110"; - uint8_t sync_len = 12+4; /* We just use 12 preamble symbols + sync. */ - if (numbits-sync_len < 8*8) return false; - - uint64_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern); - if (off == BITMAP_SEEK_NOT_FOUND) return false; + uint64_t off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_pattern); + if(off == BITMAP_SEEK_NOT_FOUND) return false; FURI_LOG_E(TAG, "Fort TPMS preamble+sync found"); info->start_off = off; off += sync_len; /* Skip preamble and sync. */ uint8_t raw[8]; - uint32_t decoded = - convert_from_line_code(raw,sizeof(raw),bits,numbytes,off, - "01","10"); /* Manchester. */ + uint32_t decoded = convert_from_line_code( + raw, sizeof(raw), bits, numbytes, off, "01", "10"); /* Manchester. */ FURI_LOG_E(TAG, "Ford TPMS decoded bits: %lu", decoded); - if (decoded < 8*8) return false; /* Require the full 8 bytes. */ + if(decoded < 8 * 8) return false; /* Require the full 8 bytes. */ /* CRC is just the sum of the first 7 bytes MOD 256. */ uint8_t crc = 0; - for (int j = 0; j < 7; j++) crc += raw[j]; - if (crc != raw[7]) return false; /* Require sane CRC. */ + for(int j = 0; j < 7; j++) crc += raw[j]; + if(crc != raw[7]) return false; /* Require sane CRC. */ - info->pulses_count = (off+8*8*2) - info->start_off; + info->pulses_count = (off + 8 * 8 * 2) - info->start_off; - float psi = 0.25 * (((raw[6]&0x20)<<3)|raw[4]); + float psi = 0.25 * (((raw[6] & 0x20) << 3) | raw[4]); /* Temperature apperas to be valid only if the most significant * bit of the value is not set. Otherwise its meaning is unknown. * Likely useful to alternatively send temperature or other info. */ - int temp = raw[5] & 0x80 ? 0 : raw[5]-56; + int temp = raw[5] & 0x80 ? 0 : raw[5] - 56; int flags = raw[5] & 0x7f; int car_moving = (raw[6] & 0x44) == 0x44; - fieldset_add_bytes(info->fieldset,"Tire ID",raw,4*2); - fieldset_add_float(info->fieldset,"Pressure psi",psi,2); - fieldset_add_int(info->fieldset,"Temperature C",temp,8); - fieldset_add_hex(info->fieldset,"Flags",flags,7); - fieldset_add_uint(info->fieldset,"Moving",car_moving,1); + fieldset_add_bytes(info->fieldset, "Tire ID", raw, 4 * 2); + fieldset_add_float(info->fieldset, "Pressure psi", psi, 2); + fieldset_add_int(info->fieldset, "Temperature C", temp, 8); + fieldset_add_hex(info->fieldset, "Flags", flags, 7); + fieldset_add_uint(info->fieldset, "Moving", car_moving, 1); return true; } -ProtoViewDecoder FordTPMSDecoder = { - .name = "Ford TPMS", - .decode = decode, - .get_fields = NULL, - .build_message = NULL -}; +ProtoViewDecoder FordTPMSDecoder = + {.name = "Ford TPMS", .decode = decode, .get_fields = NULL, .build_message = NULL}; diff --git a/applications/plugins/protoview/protocols/tpms/renault.c b/applications/plugins/protoview/protocols/tpms/renault.c index 09de77d17..3d8fc43d5 100644 --- a/applications/plugins/protoview/protocols/tpms/renault.c +++ b/applications/plugins/protoview/protocols/tpms/renault.c @@ -6,85 +6,82 @@ #include "../../app.h" #define USE_TEST_VECTOR 0 -static const char *test_vector = +static const char* test_vector = "...01010101010101010110" // Preamble + sync /* The following is Marshal encoded, so each two characters are * actaully one bit. 01 = 0, 10 = 1. */ "010110010110" // Flags. "10011001101010011001" // Pressure, multiply by 0.75 to obtain kpa. - // 244 kpa here. - "1010010110011010" // Temperature, subtract 30 to obtain celsius. 22C here. + // 244 kpa here. + "1010010110011010" // Temperature, subtract 30 to obtain celsius. 22C here. "1001010101101001" "0101100110010101" - "1001010101100110" // Tire ID. 0x7AD779 here. + "1001010101100110" // Tire ID. 0x7AD779 here. "0101010101010101" - "0101010101010101" // Two FF bytes (usually). Unknown. + "0101010101010101" // Two FF bytes (usually). Unknown. "0110010101010101"; // CRC8 with (poly 7, initialization 0). -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { - - if (USE_TEST_VECTOR) { /* Test vector to check that decoding works. */ - bitmap_set_pattern(bits,numbytes,0,test_vector); +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + if(USE_TEST_VECTOR) { /* Test vector to check that decoding works. */ + bitmap_set_pattern(bits, numbytes, 0, test_vector); numbits = strlen(test_vector); } - if (numbits-12 < 9*8) return false; + if(numbits - 12 < 9 * 8) return false; - const char *sync_pattern = "01010101010101010110"; - uint64_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern); - if (off == BITMAP_SEEK_NOT_FOUND) return false; + const char* sync_pattern = "01010101010101010110"; + uint64_t off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_pattern); + if(off == BITMAP_SEEK_NOT_FOUND) return false; FURI_LOG_E(TAG, "Renault TPMS preamble+sync found"); info->start_off = off; off += 20; /* Skip preamble. */ uint8_t raw[9]; - uint32_t decoded = - convert_from_line_code(raw,sizeof(raw),bits,numbytes,off, - "01","10"); /* Manchester. */ + uint32_t decoded = convert_from_line_code( + raw, sizeof(raw), bits, numbytes, off, "01", "10"); /* Manchester. */ FURI_LOG_E(TAG, "Renault TPMS decoded bits: %lu", decoded); - if (decoded < 8*9) return false; /* Require the full 9 bytes. */ - if (crc8(raw,8,0,7) != raw[8]) return false; /* Require sane CRC. */ + if(decoded < 8 * 9) return false; /* Require the full 9 bytes. */ + if(crc8(raw, 8, 0, 7) != raw[8]) return false; /* Require sane CRC. */ - info->pulses_count = (off+8*9*2) - info->start_off; + info->pulses_count = (off + 8 * 9 * 2) - info->start_off; - uint8_t flags = raw[0]>>2; - float kpa = 0.75 * ((uint32_t)((raw[0]&3)<<8) | raw[1]); - int temp = raw[2]-30; + uint8_t flags = raw[0] >> 2; + float kpa = 0.75 * ((uint32_t)((raw[0] & 3) << 8) | raw[1]); + int temp = raw[2] - 30; - fieldset_add_bytes(info->fieldset,"Tire ID",raw+3,3*2); - fieldset_add_float(info->fieldset,"Pressure kpa",kpa,2); - fieldset_add_int(info->fieldset,"Temperature C",temp,8); - fieldset_add_hex(info->fieldset,"Flags",flags,6); - fieldset_add_bytes(info->fieldset,"Unknown1",raw+6,2); - fieldset_add_bytes(info->fieldset,"Unknown2",raw+7,2); + fieldset_add_bytes(info->fieldset, "Tire ID", raw + 3, 3 * 2); + fieldset_add_float(info->fieldset, "Pressure kpa", kpa, 2); + fieldset_add_int(info->fieldset, "Temperature C", temp, 8); + fieldset_add_hex(info->fieldset, "Flags", flags, 6); + fieldset_add_bytes(info->fieldset, "Unknown1", raw + 6, 2); + fieldset_add_bytes(info->fieldset, "Unknown2", raw + 7, 2); return true; } /* Give fields and defaults for the signal creator. */ -static void get_fields(ProtoViewFieldSet *fieldset) { - uint8_t default_id[3]= {0xAB, 0xCD, 0xEF}; - fieldset_add_bytes(fieldset,"Tire ID",default_id,3*2); - fieldset_add_float(fieldset,"Pressure kpa",123,2); - fieldset_add_int(fieldset,"Temperature C",20,8); +static void get_fields(ProtoViewFieldSet* fieldset) { + uint8_t default_id[3] = {0xAB, 0xCD, 0xEF}; + fieldset_add_bytes(fieldset, "Tire ID", default_id, 3 * 2); + fieldset_add_float(fieldset, "Pressure kpa", 123, 2); + fieldset_add_int(fieldset, "Temperature C", 20, 8); // We don't know what flags are, but 1B is a common value. - fieldset_add_hex(fieldset,"Flags",0x1b,6); - fieldset_add_bytes(fieldset,"Unknown1",(uint8_t*)"\xff",2); - fieldset_add_bytes(fieldset,"Unknown2",(uint8_t*)"\xff",2); + fieldset_add_hex(fieldset, "Flags", 0x1b, 6); + fieldset_add_bytes(fieldset, "Unknown1", (uint8_t*)"\xff", 2); + fieldset_add_bytes(fieldset, "Unknown2", (uint8_t*)"\xff", 2); } /* Create a Renault TPMS signal, according to the fields provided. */ -static void build_message(RawSamplesBuffer *samples, ProtoViewFieldSet *fieldset) -{ +static void build_message(RawSamplesBuffer* samples, ProtoViewFieldSet* fieldset) { uint32_t te = 50; // Short pulse duration in microseconds. // Preamble + sync - const char *psync = "01010101010101010101010101010110"; - const char *p = psync; + const char* psync = "01010101010101010101010101010110"; + const char* p = psync; while(*p) { - raw_samples_add_or_update(samples,*p == '1',te); + raw_samples_add_or_update(samples, *p == '1', te); p++; } @@ -93,21 +90,21 @@ static void build_message(RawSamplesBuffer *samples, ProtoViewFieldSet *fieldset unsigned int raw_pressure = fieldset->fields[1]->fvalue * 4 / 3; data[0] = fieldset->fields[3]->uvalue << 2; // Flags data[0] |= (raw_pressure >> 8) & 3; // Pressure kpa high 2 bits - data[1] = raw_pressure & 0xff; // Pressure kpa low 8 bits + data[1] = raw_pressure & 0xff; // Pressure kpa low 8 bits data[2] = fieldset->fields[2]->value + 30; // Temperature C - memcpy(data+3,fieldset->fields[0]->bytes,6); // ID, 24 bits. - data[6] = fieldset->fields[4]->bytes[0]; // Unknown 1 - data[7] = fieldset->fields[5]->bytes[0]; // Unknown 2 - data[8] = crc8(data,8,0,7); + memcpy(data + 3, fieldset->fields[0]->bytes, 6); // ID, 24 bits. + data[6] = fieldset->fields[4]->bytes[0]; // Unknown 1 + data[7] = fieldset->fields[5]->bytes[0]; // Unknown 2 + data[8] = crc8(data, 8, 0, 7); // Generate Manchester code for each bit - for (uint32_t j = 0; j < 9*8; j++) { - if (bitmap_get(data,sizeof(data),j)) { - raw_samples_add_or_update(samples,true,te); - raw_samples_add_or_update(samples,false,te); + for(uint32_t j = 0; j < 9 * 8; j++) { + if(bitmap_get(data, sizeof(data), j)) { + raw_samples_add_or_update(samples, true, te); + raw_samples_add_or_update(samples, false, te); } else { - raw_samples_add_or_update(samples,false,te); - raw_samples_add_or_update(samples,true,te); + raw_samples_add_or_update(samples, false, te); + raw_samples_add_or_update(samples, true, te); } } } @@ -116,5 +113,4 @@ ProtoViewDecoder RenaultTPMSDecoder = { .name = "Renault TPMS", .decode = decode, .get_fields = get_fields, - .build_message = build_message -}; + .build_message = build_message}; diff --git a/applications/plugins/protoview/protocols/tpms/schrader.c b/applications/plugins/protoview/protocols/tpms/schrader.c index ae25e39bb..7dc85a2cb 100644 --- a/applications/plugins/protoview/protocols/tpms/schrader.c +++ b/applications/plugins/protoview/protocols/tpms/schrader.c @@ -11,20 +11,21 @@ #include "../../app.h" #define USE_TEST_VECTOR 0 -static const char *test_vector = "000000111101010101011010010110010110101001010110100110011001100101010101011010100110100110011010101010101010101010101010101010101010101010101010"; +static const char* test_vector = + "000000111101010101011010010110010110101001010110100110011001100101010101011010100110100110011010101010101010101010101010101010101010101010101010"; -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { - - if (USE_TEST_VECTOR) { /* Test vector to check that decoding works. */ - bitmap_set_pattern(bits,numbytes,0,test_vector); +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + if(USE_TEST_VECTOR) { /* Test vector to check that decoding works. */ + bitmap_set_pattern(bits, numbytes, 0, test_vector); numbits = strlen(test_vector); } - if (numbits < 64) return false; /* Preamble + data. */ + if(numbits < 64) return false; /* Preamble + data. */ - const char *sync_pattern = "1111010101" "01011010"; - uint64_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern); - if (off == BITMAP_SEEK_NOT_FOUND) return false; + const char* sync_pattern = "1111010101" + "01011010"; + uint64_t off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_pattern); + if(off == BITMAP_SEEK_NOT_FOUND) return false; FURI_LOG_E(TAG, "Schrader TPMS gap+preamble found"); info->start_off = off; @@ -34,38 +35,33 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView uint8_t raw[8]; uint8_t id[4]; - uint32_t decoded = - convert_from_line_code(raw,sizeof(raw),bits,numbytes,off, - "01","10"); /* Manchester code. */ + uint32_t decoded = convert_from_line_code( + raw, sizeof(raw), bits, numbytes, off, "01", "10"); /* Manchester code. */ FURI_LOG_E(TAG, "Schrader TPMS decoded bits: %lu", decoded); - if (decoded < 64) return false; /* Require the full 8 bytes. */ + if(decoded < 64) return false; /* Require the full 8 bytes. */ raw[0] |= 0xf0; // Fix the preamble nibble for checksum computation. - uint8_t cksum = crc8(raw,sizeof(raw)-1,0xf0,0x7); - if (cksum != raw[7]) { + uint8_t cksum = crc8(raw, sizeof(raw) - 1, 0xf0, 0x7); + if(cksum != raw[7]) { FURI_LOG_E(TAG, "Schrader TPMS checksum mismatch"); return false; } - info->pulses_count = (off+8*8*2) - info->start_off; + info->pulses_count = (off + 8 * 8 * 2) - info->start_off; - float kpa = (float)raw[5]*2.5; - int temp = raw[6]-50; - id[0] = raw[1]&7; + float kpa = (float)raw[5] * 2.5; + int temp = raw[6] - 50; + id[0] = raw[1] & 7; id[1] = raw[2]; id[2] = raw[3]; id[3] = raw[4]; - fieldset_add_bytes(info->fieldset,"Tire ID",id,4*2); - fieldset_add_float(info->fieldset,"Pressure kpa",kpa,2); - fieldset_add_int(info->fieldset,"Temperature C",temp,8); + fieldset_add_bytes(info->fieldset, "Tire ID", id, 4 * 2); + fieldset_add_float(info->fieldset, "Pressure kpa", kpa, 2); + fieldset_add_int(info->fieldset, "Temperature C", temp, 8); return true; } -ProtoViewDecoder SchraderTPMSDecoder = { - .name = "Schrader TPMS", - .decode = decode, - .get_fields = NULL, - .build_message = NULL -}; +ProtoViewDecoder SchraderTPMSDecoder = + {.name = "Schrader TPMS", .decode = decode, .get_fields = NULL, .build_message = NULL}; diff --git a/applications/plugins/protoview/protocols/tpms/schrader_eg53ma4.c b/applications/plugins/protoview/protocols/tpms/schrader_eg53ma4.c index 0105010bd..45accf1a1 100644 --- a/applications/plugins/protoview/protocols/tpms/schrader_eg53ma4.c +++ b/applications/plugins/protoview/protocols/tpms/schrader_eg53ma4.c @@ -15,50 +15,45 @@ #include "../../app.h" -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + const char* sync_pattern = "010101010101" + "01100101"; + uint8_t sync_len = 12 + 8; /* We just use 12 preamble symbols + sync. */ + if(numbits - sync_len + 8 < 8 * 10) return false; - const char *sync_pattern = "010101010101" "01100101"; - uint8_t sync_len = 12+8; /* We just use 12 preamble symbols + sync. */ - if (numbits-sync_len+8 < 8*10) return false; - - uint64_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern); - if (off == BITMAP_SEEK_NOT_FOUND) return false; + uint64_t off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync_pattern); + if(off == BITMAP_SEEK_NOT_FOUND) return false; FURI_LOG_E(TAG, "Schrader EG53MA4 TPMS preamble+sync found"); info->start_off = off; - off += sync_len-8; /* Skip preamble, not sync that is part of the data. */ + off += sync_len - 8; /* Skip preamble, not sync that is part of the data. */ uint8_t raw[10]; - uint32_t decoded = - convert_from_line_code(raw,sizeof(raw),bits,numbytes,off, - "01","10"); /* Manchester code. */ + uint32_t decoded = convert_from_line_code( + raw, sizeof(raw), bits, numbytes, off, "01", "10"); /* Manchester code. */ FURI_LOG_E(TAG, "Schrader EG53MA4 TPMS decoded bits: %lu", decoded); - if (decoded < 10*8) return false; /* Require the full 10 bytes. */ + if(decoded < 10 * 8) return false; /* Require the full 10 bytes. */ /* CRC is just all bytes added mod 256. */ uint8_t crc = 0; - for (int j = 0; j < 9; j++) crc += raw[j]; - if (crc != raw[9]) return false; /* Require sane CRC. */ + for(int j = 0; j < 9; j++) crc += raw[j]; + if(crc != raw[9]) return false; /* Require sane CRC. */ - info->pulses_count = (off+10*8*2) - info->start_off; + info->pulses_count = (off + 10 * 8 * 2) - info->start_off; /* To convert the raw pressure to kPa, RTL433 uses 2.5, but is likely * wrong. Searching on Google for users experimenting with the value * reported, the value appears to be 2.75. */ - float kpa = (float)raw[7]*2.75; + float kpa = (float)raw[7] * 2.75; int temp_f = raw[8]; - int temp_c = (temp_f-32)*5/9; /* Convert Fahrenheit to Celsius. */ + int temp_c = (temp_f - 32) * 5 / 9; /* Convert Fahrenheit to Celsius. */ - fieldset_add_bytes(info->fieldset,"Tire ID",raw+4,3*2); - fieldset_add_float(info->fieldset,"Pressure kpa",kpa,2); - fieldset_add_int(info->fieldset,"Temperature C",temp_c,8); + fieldset_add_bytes(info->fieldset, "Tire ID", raw + 4, 3 * 2); + fieldset_add_float(info->fieldset, "Pressure kpa", kpa, 2); + fieldset_add_int(info->fieldset, "Temperature C", temp_c, 8); return true; } -ProtoViewDecoder SchraderEG53MA4TPMSDecoder = { - .name = "Schrader EG53MA4 TPMS", - .decode = decode, - .get_fields = NULL, - .build_message = NULL -}; +ProtoViewDecoder SchraderEG53MA4TPMSDecoder = + {.name = "Schrader EG53MA4 TPMS", .decode = decode, .get_fields = NULL, .build_message = NULL}; diff --git a/applications/plugins/protoview/protocols/tpms/toyota.c b/applications/plugins/protoview/protocols/tpms/toyota.c index b9dd1d959..b80af7647 100644 --- a/applications/plugins/protoview/protocols/tpms/toyota.c +++ b/applications/plugins/protoview/protocols/tpms/toyota.c @@ -24,40 +24,33 @@ #include "../../app.h" -static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info) { - - if (numbits-6 < 64*2) return false; /* Ask for 64 bit of data (each bit +static bool decode(uint8_t* bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo* info) { + if(numbits - 6 < 64 * 2) + return false; /* Ask for 64 bit of data (each bit is two symbols in the bitmap). */ - char *sync[] = { - "00111100", - "001111100", - "00111101", - "001111101", - NULL - }; + char* sync[] = {"00111100", "001111100", "00111101", "001111101", NULL}; int j; uint32_t off = 0; - for (j = 0; sync[j]; j++) { - off = bitmap_seek_bits(bits,numbytes,0,numbits,sync[j]); - if (off != BITMAP_SEEK_NOT_FOUND) { + for(j = 0; sync[j]; j++) { + off = bitmap_seek_bits(bits, numbytes, 0, numbits, sync[j]); + if(off != BITMAP_SEEK_NOT_FOUND) { info->start_off = off; - off += strlen(sync[j])-2; + off += strlen(sync[j]) - 2; break; - } + } } - if (off == BITMAP_SEEK_NOT_FOUND) return false; + if(off == BITMAP_SEEK_NOT_FOUND) return false; FURI_LOG_E(TAG, "Toyota TPMS sync[%s] found", sync[j]); uint8_t raw[9]; - uint32_t decoded = - convert_from_diff_manchester(raw,sizeof(raw),bits,numbytes,off,true); + uint32_t decoded = convert_from_diff_manchester(raw, sizeof(raw), bits, numbytes, off, true); FURI_LOG_E(TAG, "Toyota TPMS decoded bits: %lu", decoded); - if (decoded < 8*9) return false; /* Require the full 8 bytes. */ - if (crc8(raw,8,0x80,7) != raw[8]) return false; /* Require sane CRC. */ + if(decoded < 8 * 9) return false; /* Require the full 8 bytes. */ + if(crc8(raw, 8, 0x80, 7) != raw[8]) return false; /* Require sane CRC. */ /* We detected a valid signal. However now info->start_off is actually * pointing to the sync part, not the preamble of alternating 0 and 1. @@ -65,25 +58,21 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView * for the decoder itself to fix the signal if neeeded, so that its * logical representation will be more accurate and better to save * and retransmit. */ - if (info->start_off >= 12) { + if(info->start_off >= 12) { info->start_off -= 12; - bitmap_set_pattern(bits,numbytes,info->start_off,"010101010101"); + bitmap_set_pattern(bits, numbytes, info->start_off, "010101010101"); } - info->pulses_count = (off+8*9*2) - info->start_off; + info->pulses_count = (off + 8 * 9 * 2) - info->start_off; - float psi = (float)((raw[4]&0x7f)<<1 | raw[5]>>7) * 0.25 - 7; - int temp = ((raw[5]&0x7f)<<1 | raw[6]>>7) - 40; + float psi = (float)((raw[4] & 0x7f) << 1 | raw[5] >> 7) * 0.25 - 7; + int temp = ((raw[5] & 0x7f) << 1 | raw[6] >> 7) - 40; - fieldset_add_bytes(info->fieldset,"Tire ID",raw,4*2); - fieldset_add_float(info->fieldset,"Pressure psi",psi,2); - fieldset_add_int(info->fieldset,"Temperature C",temp,8); + fieldset_add_bytes(info->fieldset, "Tire ID", raw, 4 * 2); + fieldset_add_float(info->fieldset, "Pressure psi", psi, 2); + fieldset_add_int(info->fieldset, "Temperature C", temp, 8); return true; } -ProtoViewDecoder ToyotaTPMSDecoder = { - .name = "Toyota TPMS", - .decode = decode, - .get_fields = NULL, - .build_message = NULL -}; +ProtoViewDecoder ToyotaTPMSDecoder = + {.name = "Toyota TPMS", .decode = decode, .get_fields = NULL, .build_message = NULL}; diff --git a/applications/plugins/protoview/raw_samples.c b/applications/plugins/protoview/raw_samples.c index f83cca361..54773f43f 100644 --- a/applications/plugins/protoview/raw_samples.c +++ b/applications/plugins/protoview/raw_samples.c @@ -8,15 +8,15 @@ #include "raw_samples.h" /* Allocate and initialize a samples buffer. */ -RawSamplesBuffer *raw_samples_alloc(void) { - RawSamplesBuffer *buf = malloc(sizeof(*buf)); +RawSamplesBuffer* raw_samples_alloc(void) { + RawSamplesBuffer* buf = malloc(sizeof(*buf)); buf->mutex = furi_mutex_alloc(FuriMutexTypeNormal); raw_samples_reset(buf); return buf; } /* Free a sample buffer. Should be called when the mutex is released. */ -void raw_samples_free(RawSamplesBuffer *s) { +void raw_samples_free(RawSamplesBuffer* s) { furi_mutex_free(s->mutex); free(s); } @@ -24,27 +24,27 @@ void raw_samples_free(RawSamplesBuffer *s) { /* This just set all the samples to zero and also resets the internal * index. There is no need to call it after raw_samples_alloc(), but only * when one wants to reset the whole buffer of samples. */ -void raw_samples_reset(RawSamplesBuffer *s) { - furi_mutex_acquire(s->mutex,FuriWaitForever); +void raw_samples_reset(RawSamplesBuffer* s) { + furi_mutex_acquire(s->mutex, FuriWaitForever); s->total = RAW_SAMPLES_NUM; s->idx = 0; s->short_pulse_dur = 0; - memset(s->samples,0,sizeof(s->samples)); + memset(s->samples, 0, sizeof(s->samples)); furi_mutex_release(s->mutex); } /* Set the raw sample internal index so that what is currently at * offset 'offset', will appear to be at 0 index. */ -void raw_samples_center(RawSamplesBuffer *s, uint32_t offset) { - s->idx = (s->idx+offset) % RAW_SAMPLES_NUM; +void raw_samples_center(RawSamplesBuffer* s, uint32_t offset) { + s->idx = (s->idx + offset) % RAW_SAMPLES_NUM; } /* Add the specified sample in the circular buffer. */ -void raw_samples_add(RawSamplesBuffer *s, bool level, uint32_t dur) { - furi_mutex_acquire(s->mutex,FuriWaitForever); +void raw_samples_add(RawSamplesBuffer* s, bool level, uint32_t dur) { + furi_mutex_acquire(s->mutex, FuriWaitForever); s->samples[s->idx].level = level; s->samples[s->idx].dur = dur; - s->idx = (s->idx+1) % RAW_SAMPLES_NUM; + s->idx = (s->idx + 1) % RAW_SAMPLES_NUM; furi_mutex_release(s->mutex); } @@ -56,28 +56,25 @@ void raw_samples_add(RawSamplesBuffer *s, bool level, uint32_t dur) { * * This function is a bit slower so the internal data sampling should * be performed with raw_samples_add(). */ -void raw_samples_add_or_update(RawSamplesBuffer *s, bool level, uint32_t dur) { - furi_mutex_acquire(s->mutex,FuriWaitForever); - uint32_t previdx = (s->idx-1) % RAW_SAMPLES_NUM; - if (s->samples[previdx].level == level && - s->samples[previdx].dur != 0) - { +void raw_samples_add_or_update(RawSamplesBuffer* s, bool level, uint32_t dur) { + furi_mutex_acquire(s->mutex, FuriWaitForever); + uint32_t previdx = (s->idx - 1) % RAW_SAMPLES_NUM; + if(s->samples[previdx].level == level && s->samples[previdx].dur != 0) { /* Update the last sample: it has the same level. */ s->samples[previdx].dur += dur; } else { /* Add a new sample. */ s->samples[s->idx].level = level; s->samples[s->idx].dur = dur; - s->idx = (s->idx+1) % RAW_SAMPLES_NUM; + s->idx = (s->idx + 1) % RAW_SAMPLES_NUM; } furi_mutex_release(s->mutex); } /* Get the sample from the buffer. It is possible to use out of range indexes * as 'idx' because the modulo operation will rewind back from the start. */ -void raw_samples_get(RawSamplesBuffer *s, uint32_t idx, bool *level, uint32_t *dur) -{ - furi_mutex_acquire(s->mutex,FuriWaitForever); +void raw_samples_get(RawSamplesBuffer* s, uint32_t idx, bool* level, uint32_t* dur) { + furi_mutex_acquire(s->mutex, FuriWaitForever); idx = (s->idx + idx) % RAW_SAMPLES_NUM; *level = s->samples[idx].level; *dur = s->samples[idx].dur; @@ -85,12 +82,12 @@ void raw_samples_get(RawSamplesBuffer *s, uint32_t idx, bool *level, uint32_t *d } /* Copy one buffer to the other, including current index. */ -void raw_samples_copy(RawSamplesBuffer *dst, RawSamplesBuffer *src) { - furi_mutex_acquire(src->mutex,FuriWaitForever); - furi_mutex_acquire(dst->mutex,FuriWaitForever); +void raw_samples_copy(RawSamplesBuffer* dst, RawSamplesBuffer* src) { + furi_mutex_acquire(src->mutex, FuriWaitForever); + furi_mutex_acquire(dst->mutex, FuriWaitForever); dst->idx = src->idx; dst->short_pulse_dur = src->short_pulse_dur; - memcpy(dst->samples,src->samples,sizeof(dst->samples)); + memcpy(dst->samples, src->samples, sizeof(dst->samples)); furi_mutex_release(src->mutex); furi_mutex_release(dst->mutex); } diff --git a/applications/plugins/protoview/raw_samples.h b/applications/plugins/protoview/raw_samples.h index 0b0422025..3493f07fd 100644 --- a/applications/plugins/protoview/raw_samples.h +++ b/applications/plugins/protoview/raw_samples.h @@ -4,16 +4,17 @@ /* Our circular buffer of raw samples, used in order to display * the signal. */ -#define RAW_SAMPLES_NUM 2048 /* Use a power of two: we take the modulo +#define RAW_SAMPLES_NUM \ + 2048 /* Use a power of two: we take the modulo of the index quite often to normalize inside the range, and division is slow. */ typedef struct RawSamplesBuffer { - FuriMutex *mutex; + FuriMutex* mutex; struct { - uint16_t level:1; - uint16_t dur:15; + uint16_t level : 1; + uint16_t dur : 15; } samples[RAW_SAMPLES_NUM]; - uint32_t idx; /* Current idx (next to write). */ + uint32_t idx; /* Current idx (next to write). */ uint32_t total; /* Total samples: same as RAW_SAMPLES_NUM, we provide this field for a cleaner interface with the user, but we always use RAW_SAMPLES_NUM when taking the modulo so @@ -22,11 +23,11 @@ typedef struct RawSamplesBuffer { uint32_t short_pulse_dur; /* Duration of the shortest pulse. */ } RawSamplesBuffer; -RawSamplesBuffer *raw_samples_alloc(void); -void raw_samples_reset(RawSamplesBuffer *s); -void raw_samples_center(RawSamplesBuffer *s, uint32_t offset); -void raw_samples_add(RawSamplesBuffer *s, bool level, uint32_t dur); -void raw_samples_add_or_update(RawSamplesBuffer *s, bool level, uint32_t dur); -void raw_samples_get(RawSamplesBuffer *s, uint32_t idx, bool *level, uint32_t *dur); -void raw_samples_copy(RawSamplesBuffer *dst, RawSamplesBuffer *src); -void raw_samples_free(RawSamplesBuffer *s); +RawSamplesBuffer* raw_samples_alloc(void); +void raw_samples_reset(RawSamplesBuffer* s); +void raw_samples_center(RawSamplesBuffer* s, uint32_t offset); +void raw_samples_add(RawSamplesBuffer* s, bool level, uint32_t dur); +void raw_samples_add_or_update(RawSamplesBuffer* s, bool level, uint32_t dur); +void raw_samples_get(RawSamplesBuffer* s, uint32_t idx, bool* level, uint32_t* dur); +void raw_samples_copy(RawSamplesBuffer* dst, RawSamplesBuffer* src); +void raw_samples_free(RawSamplesBuffer* s); diff --git a/applications/plugins/protoview/signal.c b/applications/plugins/protoview/signal.c index f4c5ebedf..a1c4b2b8f 100644 --- a/applications/plugins/protoview/signal.c +++ b/applications/plugins/protoview/signal.c @@ -3,7 +3,7 @@ #include "app.h" -bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info); +bool decode_signal(RawSamplesBuffer* s, uint64_t len, ProtoViewMsgInfo* info); /* ============================================================================= * Raw signal detection @@ -16,7 +16,7 @@ uint32_t duration_delta(uint32_t a, uint32_t b) { } /* Reset the current signal, so that a new one can be detected. */ -void reset_current_signal(ProtoViewApp *app) { +void reset_current_signal(ProtoViewApp* app) { app->signal_bestlen = 0; app->signal_offset = 0; app->signal_decoded = false; @@ -39,47 +39,47 @@ void reset_current_signal(ProtoViewApp *app) { * For instance Oregon2 sensors, in the case of protocol 2.1 will send * pulses of ~400us (RF on) VS ~580us (RF off). */ #define SEARCH_CLASSES 3 -uint32_t search_coherent_signal(RawSamplesBuffer *s, uint32_t idx) { +uint32_t search_coherent_signal(RawSamplesBuffer* s, uint32_t idx) { struct { - uint32_t dur[2]; /* dur[0] = low, dur[1] = high */ - uint32_t count[2]; /* Associated observed frequency. */ + uint32_t dur[2]; /* dur[0] = low, dur[1] = high */ + uint32_t count[2]; /* Associated observed frequency. */ } classes[SEARCH_CLASSES]; - memset(classes,0,sizeof(classes)); + memset(classes, 0, sizeof(classes)); uint32_t minlen = 30, maxlen = 4000; /* Depends on data rate, here we allow for high and low. */ uint32_t len = 0; /* Observed len of coherent samples. */ s->short_pulse_dur = 0; - for (uint32_t j = idx; j < idx+500; j++) { + for(uint32_t j = idx; j < idx + 500; j++) { bool level; uint32_t dur; raw_samples_get(s, j, &level, &dur); - if (dur < minlen || dur > maxlen) break; /* return. */ + if(dur < minlen || dur > maxlen) break; /* return. */ /* Let's see if it matches a class we already have or if we * can populate a new (yet empty) class. */ uint32_t k; - for (k = 0; k < SEARCH_CLASSES; k++) { - if (classes[k].count[level] == 0) { + for(k = 0; k < SEARCH_CLASSES; k++) { + if(classes[k].count[level] == 0) { classes[k].dur[level] = dur; classes[k].count[level] = 1; break; /* Sample accepted. */ } else { uint32_t classavg = classes[k].dur[level]; uint32_t count = classes[k].count[level]; - uint32_t delta = duration_delta(dur,classavg); + uint32_t delta = duration_delta(dur, classavg); /* Is the difference in duration between this signal and * the class we are inspecting less than a given percentage? * If so, accept this signal. */ - if (delta < classavg/5) { /* 100%/5 = 20%. */ + if(delta < classavg / 5) { /* 100%/5 = 20%. */ /* It is useful to compute the average of the class * we are observing. We know how many samples we got so * far, so we can recompute the average easily. * By always having a better estimate of the pulse len * we can avoid missing next samples in case the first * observed samples are too off. */ - classavg = ((classavg * count) + dur) / (count+1); + classavg = ((classavg * count) + dur) / (count + 1); classes[k].dur[level] = classavg; classes[k].count[level]++; break; /* Sample accepted. */ @@ -87,7 +87,7 @@ uint32_t search_coherent_signal(RawSamplesBuffer *s, uint32_t idx) { } } - if (k == SEARCH_CLASSES) break; /* No match, return. */ + if(k == SEARCH_CLASSES) break; /* No match, return. */ /* If we are here, we accepted this sample. Try with the next * one. */ @@ -97,14 +97,12 @@ uint32_t search_coherent_signal(RawSamplesBuffer *s, uint32_t idx) { /* Update the buffer setting the shortest pulse we found * among the three classes. This will be used when scaling * for visualization. */ - uint32_t short_dur[2] = {0,0}; - for (int j = 0; j < SEARCH_CLASSES; j++) { - for (int level = 0; level < 2; level++) { - if (classes[j].dur[level] == 0) continue; - if (classes[j].count[level] < 3) continue; - if (short_dur[level] == 0 || - short_dur[level] > classes[j].dur[level]) - { + uint32_t short_dur[2] = {0, 0}; + for(int j = 0; j < SEARCH_CLASSES; j++) { + for(int level = 0; level < 2; level++) { + if(classes[j].dur[level] == 0) continue; + if(classes[j].count[level] < 3) continue; + if(short_dur[level] == 0 || short_dur[level] > classes[j].dur[level]) { short_dur[level] = classes[j].dur[level]; } } @@ -113,33 +111,28 @@ uint32_t search_coherent_signal(RawSamplesBuffer *s, uint32_t idx) { /* Use the average between high and low short pulses duration. * Often they are a bit different, and using the average is more robust * when we do decoding sampling at short_pulse_dur intervals. */ - if (short_dur[0] == 0) short_dur[0] = short_dur[1]; - if (short_dur[1] == 0) short_dur[1] = short_dur[0]; - s->short_pulse_dur = (short_dur[0]+short_dur[1])/2; + if(short_dur[0] == 0) short_dur[0] = short_dur[1]; + if(short_dur[1] == 0) short_dur[1] = short_dur[0]; + s->short_pulse_dur = (short_dur[0] + short_dur[1]) / 2; return len; } /* Called when we detect a message. Just blinks when the message was * not decoded. Vibrates, too, when the message was correctly decoded. */ -void notify_signal_detected(ProtoViewApp *app, bool decoded) { +void notify_signal_detected(ProtoViewApp* app, bool decoded) { static const NotificationSequence decoded_seq = { &message_vibro_on, &message_green_255, &message_delay_50, &message_green_0, &message_vibro_off, - NULL - }; + NULL}; static const NotificationSequence unknown_seq = { - &message_red_255, - &message_delay_50, - &message_red_0, - NULL - }; + &message_red_255, &message_delay_50, &message_red_0, NULL}; - if (decoded) + if(decoded) notification_message(app->notification, &decoded_seq); else notification_message(app->notification, &unknown_seq); @@ -149,57 +142,59 @@ void notify_signal_detected(ProtoViewApp *app, bool decoded) { * in order to find a coherent signal. If a signal that does not appear to * be just noise is found, it is set in DetectedSamples global signal * buffer, that is what is rendered on the screen. */ -void scan_for_signal(ProtoViewApp *app, RawSamplesBuffer *source) { +void scan_for_signal(ProtoViewApp* app, RawSamplesBuffer* source) { /* We need to work on a copy: the source buffer may be populated * by the background thread receiving data. */ - RawSamplesBuffer *copy = raw_samples_alloc(); - raw_samples_copy(copy,source); + RawSamplesBuffer* copy = raw_samples_alloc(); + raw_samples_copy(copy, source); /* Try to seek on data that looks to have a regular high low high low * pattern. */ - uint32_t minlen = 18; /* Min run of coherent samples. With less + uint32_t minlen = 18; /* Min run of coherent samples. With less than a few samples it's very easy to mistake noise for signal. */ uint32_t i = 0; - while (i < copy->total-1) { - uint32_t thislen = search_coherent_signal(copy,i); + while(i < copy->total - 1) { + uint32_t thislen = search_coherent_signal(copy, i); /* For messages that are long enough, attempt decoding. */ - if (thislen > minlen) { + if(thislen > minlen) { /* Allocate the message information that some decoder may * fill, in case it is able to decode a message. */ - ProtoViewMsgInfo *info = malloc(sizeof(ProtoViewMsgInfo)); - init_msg_info(info,app); + ProtoViewMsgInfo* info = malloc(sizeof(ProtoViewMsgInfo)); + init_msg_info(info, app); info->short_pulse_dur = copy->short_pulse_dur; uint32_t saved_idx = copy->idx; /* Save index, see later. */ /* decode_signal() expects the detected signal to start * from index zero .*/ - raw_samples_center(copy,i); - bool decoded = decode_signal(copy,thislen,info); + raw_samples_center(copy, i); + bool decoded = decode_signal(copy, thislen, info); copy->idx = saved_idx; /* Restore the index as we are scanning the signal in the loop. */ /* Accept this signal as the new signal if either it's longer * than the previous undecoded one, or the previous one was * unknown and this is decoded. */ - if ((thislen > app->signal_bestlen && app->signal_decoded == false) - || (app->signal_decoded == false && decoded)) - { + if((thislen > app->signal_bestlen && app->signal_decoded == false) || + (app->signal_decoded == false && decoded)) { free_msg_info(app->msg_info); app->msg_info = info; app->signal_bestlen = thislen; app->signal_decoded = decoded; - raw_samples_copy(DetectedSamples,copy); - raw_samples_center(DetectedSamples,i); - FURI_LOG_E(TAG, "===> Displayed sample updated (%d samples %lu us)", - (int)thislen, DetectedSamples->short_pulse_dur); + raw_samples_copy(DetectedSamples, copy); + raw_samples_center(DetectedSamples, i); + FURI_LOG_E( + TAG, + "===> Displayed sample updated (%d samples %lu us)", + (int)thislen, + DetectedSamples->short_pulse_dur); - adjust_raw_view_scale(app,DetectedSamples->short_pulse_dur); - notify_signal_detected(app,decoded); + adjust_raw_view_scale(app, DetectedSamples->short_pulse_dur); + notify_signal_detected(app, decoded); } else { /* If the structure was not filled, discard it. Otherwise * now the owner is app->msg_info. */ @@ -227,38 +222,42 @@ void scan_for_signal(ProtoViewApp *app, RawSamplesBuffer *source) { /* Set the 'bitpos' bit to value 'val', in the specified bitmap * 'b' of len 'blen'. * Out of range bits will silently be discarded. */ -void bitmap_set(uint8_t *b, uint32_t blen, uint32_t bitpos, bool val) { - uint32_t byte = bitpos/8; - uint32_t bit = 7-(bitpos&7); - if (byte >= blen) return; - if (val) - b[byte] |= 1<= blen) return; + if(val) + b[byte] |= 1 << bit; else - b[byte] &= ~(1<= blen) return 0; - return (b[byte] & (1<= blen) return 0; + return (b[byte] & (1 << bit)) != 0; } /* Copy 'count' bits from the bitmap 's' of 'slen' total bytes, to the * bitmap 'd' of 'dlen' total bytes. The bits are copied starting from * offset 'soff' of the source bitmap to the offset 'doff' of the * destination bitmap. */ -void bitmap_copy(uint8_t *d, uint32_t dlen, uint32_t doff, - uint8_t *s, uint32_t slen, uint32_t soff, - uint32_t count) -{ +void bitmap_copy( + uint8_t* d, + uint32_t dlen, + uint32_t doff, + uint8_t* s, + uint32_t slen, + uint32_t soff, + uint32_t count) { /* If we are byte-aligned in both source and destination, use a fast * path for the number of bytes we can consume this way. */ - if ((doff & 7) == 0 && (soff & 7) == 0) { - uint32_t didx = doff/8; - uint32_t sidx = soff/8; + if((doff & 7) == 0 && (soff & 7) == 0) { + uint32_t didx = doff / 8; + uint32_t sidx = soff / 8; while(count > 8 && didx < dlen && sidx < slen) { d[didx++] = s[sidx++]; count -= 8; @@ -271,9 +270,9 @@ void bitmap_copy(uint8_t *d, uint32_t dlen, uint32_t doff, /* Copy the bits needed to reach an offset where we can copy * two half bytes of src to a full byte of destination. */ - while(count > 8 && (doff&7) != 0) { - bool bit = bitmap_get(s,slen,soff++); - bitmap_set(d,dlen,doff++,bit); + while(count > 8 && (doff & 7) != 0) { + bool bit = bitmap_get(s, slen, soff++); + bitmap_set(d, dlen, doff++, bit); count--; } @@ -316,13 +315,12 @@ void bitmap_copy(uint8_t *d, uint32_t dlen, uint32_t doff, * src[2] << 5, that is "WORLDS!!" >> 5 = ".....WOR" * That is "HELLOWOR" */ - if (count > 8) { + if(count > 8) { uint8_t skew = soff % 8; /* Don't worry, compiler will optimize. */ - uint32_t didx = doff/8; - uint32_t sidx = soff/8; + uint32_t didx = doff / 8; + uint32_t sidx = soff / 8; while(count > 8 && didx < dlen && sidx < slen) { - d[didx] = ((s[sidx] << skew) | - (s[sidx+1] >> (8-skew))); + d[didx] = ((s[sidx] << skew) | (s[sidx + 1] >> (8 - skew))); sidx++; didx++; soff += 8; @@ -334,8 +332,8 @@ void bitmap_copy(uint8_t *d, uint32_t dlen, uint32_t doff, /* Here count is guaranteed to be < 8. * Copy the final bits bit by bit. */ while(count) { - bool bit = bitmap_get(s,slen,soff++); - bitmap_set(d,dlen,doff++,bit); + bool bit = bitmap_get(s, slen, soff++); + bitmap_set(d, dlen, doff++, bit); count--; } } @@ -343,15 +341,15 @@ void bitmap_copy(uint8_t *d, uint32_t dlen, uint32_t doff, /* We decode bits assuming the first bit we receive is the MSB * (see bitmap_set/get functions). Certain devices send data * encoded in the reverse way. */ -void bitmap_reverse_bytes_bits(uint8_t *p, uint32_t len) { - for (uint32_t j = 0; j < len; j++) { +void bitmap_reverse_bytes_bits(uint8_t* p, uint32_t len) { + for(uint32_t j = 0; j < len; j++) { uint32_t b = p[j]; /* Step 1: swap the two nibbles: 12345678 -> 56781234 */ - b = (b&0xf0)>>4 | (b&0x0f)<<4; + b = (b & 0xf0) >> 4 | (b & 0x0f) << 4; /* Step 2: swap adjacent pairs : 56781234 -> 78563412 */ - b = (b&0xcc)>>2 | (b&0x33)<<2; + b = (b & 0xcc) >> 2 | (b & 0x33) << 2; /* Step 3: swap adjacent bits : 78563412 -> 87654321 */ - b = (b&0xaa)>>1 | (b&0x55)<<1; + b = (b & 0xaa) >> 1 | (b & 0x55) << 1; p[j] = b; } } @@ -359,10 +357,10 @@ void bitmap_reverse_bytes_bits(uint8_t *p, uint32_t len) { /* Return true if the specified sequence of bits, provided as a string in the * form "11010110..." is found in the 'b' bitmap of 'blen' bits at 'bitpos' * position. */ -bool bitmap_match_bits(uint8_t *b, uint32_t blen, uint32_t bitpos, const char *bits) { - for (size_t j = 0; bits[j]; j++) { +bool bitmap_match_bits(uint8_t* b, uint32_t blen, uint32_t bitpos, const char* bits) { + for(size_t j = 0; bits[j]; j++) { bool expected = (bits[j] == '1') ? true : false; - if (bitmap_get(b,blen,bitpos+j) != expected) return false; + if(bitmap_get(b, blen, bitpos + j) != expected) return false; } return true; } @@ -375,12 +373,17 @@ bool bitmap_match_bits(uint8_t *b, uint32_t blen, uint32_t bitpos, const char *b * Note: there are better algorithms, such as Boyer-Moore. Here we hope that * for the kind of patterns we search we'll have a lot of early stops so * we use a vanilla approach. */ -uint32_t bitmap_seek_bits(uint8_t *b, uint32_t blen, uint32_t startpos, uint32_t maxbits, const char *bits) { - uint32_t endpos = startpos+blen*8; - uint32_t end2 = startpos+maxbits; - if (end2 < endpos) endpos = end2; - for (uint32_t j = startpos; j < endpos; j++) - if (bitmap_match_bits(b,blen,j,bits)) return j; +uint32_t bitmap_seek_bits( + uint8_t* b, + uint32_t blen, + uint32_t startpos, + uint32_t maxbits, + const char* bits) { + uint32_t endpos = startpos + blen * 8; + uint32_t end2 = startpos + maxbits; + if(end2 < endpos) endpos = end2; + for(uint32_t j = startpos; j < endpos; j++) + if(bitmap_match_bits(b, blen, j, bits)) return j; return BITMAP_SEEK_NOT_FOUND; } @@ -391,10 +394,10 @@ uint32_t bitmap_seek_bits(uint8_t *b, uint32_t blen, uint32_t startpos, uint32_t * This function is useful in order to set the test vectors in the protocol * decoders, to see if the decoding works regardless of the fact we are able * to actually receive a given signal. */ -void bitmap_set_pattern(uint8_t *b, uint32_t blen, uint32_t off, const char *pat) { +void bitmap_set_pattern(uint8_t* b, uint32_t blen, uint32_t off, const char* pat) { uint32_t i = 0; while(pat[i]) { - bitmap_set(b,blen,i+off,pat[i] == '1'); + bitmap_set(b, blen, i + off, pat[i] == '1'); i++; } } @@ -426,31 +429,36 @@ void bitmap_set_pattern(uint8_t *b, uint32_t blen, uint32_t off, const char *pat * bits set into the buffer 'b'. The 'rate' argument, in microseconds, is * the detected short-pulse duration. We expect the line code to be * meaningful when interpreted at multiples of 'rate'. */ -uint32_t convert_signal_to_bits(uint8_t *b, uint32_t blen, RawSamplesBuffer *s, uint32_t idx, uint32_t count, uint32_t rate) { - if (rate == 0) return 0; /* We can't perform the conversion. */ +uint32_t convert_signal_to_bits( + uint8_t* b, + uint32_t blen, + RawSamplesBuffer* s, + uint32_t idx, + uint32_t count, + uint32_t rate) { + if(rate == 0) return 0; /* We can't perform the conversion. */ uint32_t bitpos = 0; - for (uint32_t j = 0; j < count; j++) { + for(uint32_t j = 0; j < count; j++) { uint32_t dur; bool level; - raw_samples_get(s, j+idx, &level, &dur); + raw_samples_get(s, j + idx, &level, &dur); uint32_t numbits = dur / rate; /* full bits that surely fit. */ - uint32_t rest = dur % rate; /* How much we are left with. */ - if (rest > rate/2) numbits++; /* There is another one. */ + uint32_t rest = dur % rate; /* How much we are left with. */ + if(rest > rate / 2) numbits++; /* There is another one. */ /* Limit how much a single sample can spawn. There are likely no * protocols doing such long pulses when the rate is low. */ - if (numbits > 1024) numbits = 1024; + if(numbits > 1024) numbits = 1024; - if (0) /* Super verbose, so not under the DEBUG_MSG define. */ - FURI_LOG_E(TAG, "%lu converted into %lu (%d) bits", - dur,numbits,(int)level); + if(0) /* Super verbose, so not under the DEBUG_MSG define. */ + FURI_LOG_E(TAG, "%lu converted into %lu (%d) bits", dur, numbits, (int)level); /* If the signal is too short, let's claim it an interference * and ignore it completely. */ - if (numbits == 0) continue; + if(numbits == 0) continue; - while(numbits--) bitmap_set(b,blen,bitpos++,level); + while(numbits--) bitmap_set(b, blen, bitpos++, level); } return bitpos; } @@ -467,23 +475,29 @@ uint32_t convert_signal_to_bits(uint8_t *b, uint32_t blen, RawSamplesBuffer *s, * specified in bytes by the caller, via the 'len' parameters). * * The decoding starts at the specified offset (in bits) 'off'. */ -uint32_t convert_from_line_code(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t off, const char *zero_pattern, const char *one_pattern) -{ +uint32_t convert_from_line_code( + uint8_t* buf, + uint64_t buflen, + uint8_t* bits, + uint32_t len, + uint32_t off, + const char* zero_pattern, + const char* one_pattern) { uint32_t decoded = 0; /* Number of bits extracted. */ len *= 8; /* Convert bytes to bits. */ while(off < len) { bool bitval; - if (bitmap_match_bits(bits,len,off,zero_pattern)) { + if(bitmap_match_bits(bits, len, off, zero_pattern)) { bitval = false; off += strlen(zero_pattern); - } else if (bitmap_match_bits(bits,len,off,one_pattern)) { + } else if(bitmap_match_bits(bits, len, off, one_pattern)) { bitval = true; off += strlen(one_pattern); } else { break; } - bitmap_set(buf,buflen,decoded++,bitval); - if (decoded/8 == buflen) break; /* No space left on target buffer. */ + bitmap_set(buf, buflen, decoded++, bitval); + if(decoded / 8 == buflen) break; /* No space left on target buffer. */ } return decoded; } @@ -494,17 +508,22 @@ uint32_t convert_from_line_code(uint8_t *buf, uint64_t buflen, uint8_t *bits, ui * in differential codings the next bits depend on the previous one. * * Parameters and return values are like convert_from_line_code(). */ -uint32_t convert_from_diff_manchester(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t off, bool previous) -{ +uint32_t convert_from_diff_manchester( + uint8_t* buf, + uint64_t buflen, + uint8_t* bits, + uint32_t len, + uint32_t off, + bool previous) { uint32_t decoded = 0; len *= 8; /* Conver to bits. */ - for (uint32_t j = off; j < len; j += 2) { - bool b0 = bitmap_get(bits,len,j); - bool b1 = bitmap_get(bits,len,j+1); - if (b0 == previous) break; /* Each new bit must switch value. */ - bitmap_set(buf,buflen,decoded++,b0 == b1); + for(uint32_t j = off; j < len; j += 2) { + bool b0 = bitmap_get(bits, len, j); + bool b1 = bitmap_get(bits, len, j + 1); + if(b0 == previous) break; /* Each new bit must switch value. */ + bitmap_set(buf, buflen, decoded++, b0 == b1); previous = b1; - if (decoded/8 == buflen) break; /* No space left on target buffer. */ + if(decoded / 8 == buflen) break; /* No space left on target buffer. */ } return decoded; } @@ -522,22 +541,21 @@ extern ProtoViewDecoder CitroenTPMSDecoder; extern ProtoViewDecoder FordTPMSDecoder; extern ProtoViewDecoder KeeloqDecoder; -ProtoViewDecoder *Decoders[] = { - &Oregon2Decoder, /* Oregon sensors v2.1 protocol. */ - &B4B1Decoder, /* PT, SC, ... 24 bits remotes. */ - &RenaultTPMSDecoder, /* Renault TPMS. */ - &ToyotaTPMSDecoder, /* Toyota TPMS. */ - &SchraderTPMSDecoder, /* Schrader TPMS. */ - &SchraderEG53MA4TPMSDecoder, /* Schrader EG53MA4 TPMS. */ - &CitroenTPMSDecoder, /* Citroen TPMS. */ - &FordTPMSDecoder, /* Ford TPMS. */ - &KeeloqDecoder, /* Keeloq remote. */ - NULL -}; +ProtoViewDecoder* Decoders[] = { + &Oregon2Decoder, /* Oregon sensors v2.1 protocol. */ + &B4B1Decoder, /* PT, SC, ... 24 bits remotes. */ + &RenaultTPMSDecoder, /* Renault TPMS. */ + &ToyotaTPMSDecoder, /* Toyota TPMS. */ + &SchraderTPMSDecoder, /* Schrader TPMS. */ + &SchraderEG53MA4TPMSDecoder, /* Schrader EG53MA4 TPMS. */ + &CitroenTPMSDecoder, /* Citroen TPMS. */ + &FordTPMSDecoder, /* Ford TPMS. */ + &KeeloqDecoder, /* Keeloq remote. */ + NULL}; /* Free the message info and allocated data. */ -void free_msg_info(ProtoViewMsgInfo *i) { - if (i == NULL) return; +void free_msg_info(ProtoViewMsgInfo* i) { + if(i == NULL) return; fieldset_free(i->fieldset); free(i->bits); free(i); @@ -545,9 +563,9 @@ void free_msg_info(ProtoViewMsgInfo *i) { /* Reset the message info structure before passing it to the decoding * functions. */ -void init_msg_info(ProtoViewMsgInfo *i, ProtoViewApp *app) { +void init_msg_info(ProtoViewMsgInfo* i, ProtoViewApp* app) { UNUSED(app); - memset(i,0,sizeof(ProtoViewMsgInfo)); + memset(i, 0, sizeof(ProtoViewMsgInfo)); i->bits = NULL; i->fieldset = fieldset_new(); } @@ -556,23 +574,29 @@ void init_msg_info(ProtoViewMsgInfo *i, ProtoViewApp *app) { * to a bitstream, and the calls the protocol specific functions for * decoding. If the signal was decoded correctly by some protocol, true * is returned. Otherwise false is returned. */ -bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info) { - uint32_t bitmap_bits_size = 4096*8; - uint32_t bitmap_size = bitmap_bits_size/8; +bool decode_signal(RawSamplesBuffer* s, uint64_t len, ProtoViewMsgInfo* info) { + uint32_t bitmap_bits_size = 4096 * 8; + uint32_t bitmap_size = bitmap_bits_size / 8; /* We call the decoders with an offset a few samples before the actual * signal detected and for a len of a few bits after its end. */ uint32_t before_samples = 32; uint32_t after_samples = 100; - uint8_t *bitmap = malloc(bitmap_size); - uint32_t bits = convert_signal_to_bits(bitmap,bitmap_size,s,-before_samples,len+before_samples+after_samples,s->short_pulse_dur); + uint8_t* bitmap = malloc(bitmap_size); + uint32_t bits = convert_signal_to_bits( + bitmap, + bitmap_size, + s, + -before_samples, + len + before_samples + after_samples, + s->short_pulse_dur); - if (DEBUG_MSG) { /* Useful for debugging purposes. Don't remove. */ - char *str = malloc(1024); + if(DEBUG_MSG) { /* Useful for debugging purposes. Don't remove. */ + char* str = malloc(1024); uint32_t j; - for (j = 0; j < bits && j < 1023; j++) { - str[j] = bitmap_get(bitmap,bitmap_size,j) ? '1' : '0'; + for(j = 0; j < bits && j < 1023; j++) { + str[j] = bitmap_get(bitmap, bitmap_size, j) ? '1' : '0'; } str[j] = 0; FURI_LOG_E(TAG, "%lu bits sampled: %s", bits, str); @@ -585,18 +609,17 @@ bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info) { bool decoded = false; while(Decoders[j]) { uint32_t start_time = furi_get_tick(); - decoded = Decoders[j]->decode(bitmap,bitmap_size,bits,info); + decoded = Decoders[j]->decode(bitmap, bitmap_size, bits, info); uint32_t delta = furi_get_tick() - start_time; - FURI_LOG_E(TAG, "Decoder %s took %lu ms", - Decoders[j]->name, (unsigned long)delta); - if (decoded) { + FURI_LOG_E(TAG, "Decoder %s took %lu ms", Decoders[j]->name, (unsigned long)delta); + if(decoded) { info->decoder = Decoders[j]; break; } j++; } - if (!decoded) { + if(!decoded) { FURI_LOG_E(TAG, "No decoding possible"); } else { FURI_LOG_E(TAG, "+++ Decoded %s", info->decoder->name); @@ -604,12 +627,17 @@ bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info) { * with the decoded signal. The decoder may not implement offset/len * filling of the structure. In such case we have no info and * pulses_count will be set to zero. */ - if (info->pulses_count) { - info->bits_bytes = (info->pulses_count+7)/8; // Round to full byte. + if(info->pulses_count) { + info->bits_bytes = (info->pulses_count + 7) / 8; // Round to full byte. info->bits = malloc(info->bits_bytes); - bitmap_copy(info->bits,info->bits_bytes,0, - bitmap,bitmap_size,info->start_off, - info->pulses_count); + bitmap_copy( + info->bits, + info->bits_bytes, + 0, + bitmap, + bitmap_size, + info->start_off, + info->pulses_count); } } free(bitmap); diff --git a/applications/plugins/protoview/signal_file.c b/applications/plugins/protoview/signal_file.c index 31c8726fb..c60a6a181 100644 --- a/applications/plugins/protoview/signal_file.c +++ b/applications/plugins/protoview/signal_file.c @@ -13,57 +13,56 @@ * but it's logical representation stored in the app->msg_info bitmap, where * each 1 or 0 means a puls or gap for the specified short pulse duration time * (te). */ -bool save_signal(ProtoViewApp *app, const char *filename) { +bool save_signal(ProtoViewApp* app, const char* filename) { /* We have a message at all? */ - if (app->msg_info == NULL || app->msg_info->pulses_count == 0) return false; - - Storage *storage = furi_record_open(RECORD_STORAGE); - FlipperFormat *file = flipper_format_file_alloc(storage); - Stream *stream = flipper_format_get_raw_stream(file); - FuriString *file_content = NULL; + if(app->msg_info == NULL || app->msg_info->pulses_count == 0) return false; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = flipper_format_file_alloc(storage); + Stream* stream = flipper_format_get_raw_stream(file); + FuriString* file_content = NULL; bool success = true; - if (flipper_format_file_open_always(file, filename)) { + if(flipper_format_file_open_always(file, filename)) { /* Write the file header. */ - FuriString *file_content = furi_string_alloc(); - const char *preset_id = ProtoViewModulations[app->modulation].id; + FuriString* file_content = furi_string_alloc(); + const char* preset_id = ProtoViewModulations[app->modulation].id; - furi_string_printf(file_content, - "Filetype: Flipper SubGhz RAW File\n" - "Version: 1\n" - "Frequency: %ld\n" - "Preset: %s\n", - app->frequency, - preset_id ? preset_id : "FuriHalSubGhzPresetCustom"); + furi_string_printf( + file_content, + "Filetype: Flipper SubGhz RAW File\n" + "Version: 1\n" + "Frequency: %ld\n" + "Preset: %s\n", + app->frequency, + preset_id ? preset_id : "FuriHalSubGhzPresetCustom"); /* For custom modulations, we need to emit a set of registers. */ - if (preset_id == NULL) { - FuriString *custom = furi_string_alloc(); - uint8_t *regs = ProtoViewModulations[app->modulation].custom; - furi_string_printf(custom, + if(preset_id == NULL) { + FuriString* custom = furi_string_alloc(); + uint8_t* regs = ProtoViewModulations[app->modulation].custom; + furi_string_printf( + custom, "Custom_preset_module: CC1101\n" - "Custom_preset_data: "); - for (int j = 0; regs[j]; j += 2) { - furi_string_cat_printf(custom, "%02X %02X ", - (int)regs[j], (int)regs[j+1]); + "Custom_preset_data: "); + for(int j = 0; regs[j]; j += 2) { + furi_string_cat_printf(custom, "%02X %02X ", (int)regs[j], (int)regs[j + 1]); } size_t len = furi_string_size(file_content); - furi_string_set_char(custom,len-1,'\n'); - furi_string_cat(file_content,custom); + furi_string_set_char(custom, len - 1, '\n'); + furi_string_cat(file_content, custom); furi_string_free(custom); } /* We always save raw files. */ - furi_string_cat_printf(file_content, - "Protocol: RAW\n" - "RAW_Data: -10000\n"); // Start with 10 ms of gap + furi_string_cat_printf( + file_content, + "Protocol: RAW\n" + "RAW_Data: -10000\n"); // Start with 10 ms of gap /* Write header. */ size_t len = furi_string_size(file_content); - if (stream_write(stream, - (uint8_t*) furi_string_get_cstr(file_content), len) - != len) - { + if(stream_write(stream, (uint8_t*)furi_string_get_cstr(file_content), len) != len) { FURI_LOG_W(TAG, "Short write to file"); success = false; goto write_err; @@ -76,15 +75,13 @@ bool save_signal(ProtoViewApp *app, const char *filename) { uint32_t this_line_samples = 0; uint32_t max_line_samples = 100; uint32_t idx = 0; // Iindex in the signal bitmap. - ProtoViewMsgInfo *i = app->msg_info; + ProtoViewMsgInfo* i = app->msg_info; while(idx < i->pulses_count) { - bool level = bitmap_get(i->bits,i->bits_bytes,idx); + bool level = bitmap_get(i->bits, i->bits_bytes, idx); uint32_t te_times = 1; idx++; /* Count the duration of the current pulse/gap. */ - while(idx < i->pulses_count && - bitmap_get(i->bits,i->bits_bytes,idx) == level) - { + while(idx < i->pulses_count && bitmap_get(i->bits, i->bits_bytes, idx) == level) { te_times++; idx++; } @@ -92,32 +89,29 @@ bool save_signal(ProtoViewApp *app, const char *filename) { // next gap or pulse. int32_t dur = (int32_t)i->short_pulse_dur * te_times; - if (level == 0) dur = -dur; /* Negative is gap in raw files. */ + if(level == 0) dur = -dur; /* Negative is gap in raw files. */ /* Emit the sample. If this is the first sample of the line, * also emit the RAW_Data: field. */ - if (this_line_samples == 0) - furi_string_cat_printf(file_content,"RAW_Data: "); - furi_string_cat_printf(file_content,"%d ",(int)dur); + if(this_line_samples == 0) furi_string_cat_printf(file_content, "RAW_Data: "); + furi_string_cat_printf(file_content, "%d ", (int)dur); this_line_samples++; /* Store the current set of samples on disk, when we reach a * given number or the end of the signal. */ bool end_reached = (idx == i->pulses_count); - if (this_line_samples == max_line_samples || end_reached) { + if(this_line_samples == max_line_samples || end_reached) { /* If that's the end, terminate the signal with a long * gap. */ - if (end_reached) furi_string_cat_printf(file_content,"-10000 "); + if(end_reached) furi_string_cat_printf(file_content, "-10000 "); /* We always have a trailing space in the last sample. Make it * a newline. */ size_t len = furi_string_size(file_content); - furi_string_set_char(file_content,len-1,'\n'); + furi_string_set_char(file_content, len - 1, '\n'); - if (stream_write(stream, - (uint8_t*) furi_string_get_cstr(file_content), - len) != len) - { + if(stream_write(stream, (uint8_t*)furi_string_get_cstr(file_content), len) != + len) { FURI_LOG_W(TAG, "Short write to file"); success = false; goto write_err; @@ -136,6 +130,6 @@ bool save_signal(ProtoViewApp *app, const char *filename) { write_err: furi_record_close(RECORD_STORAGE); flipper_format_free(file); - if (file_content != NULL) furi_string_free(file_content); + if(file_content != NULL) furi_string_free(file_content); return success; } diff --git a/applications/plugins/protoview/ui.c b/applications/plugins/protoview/ui.c index 8badab5bf..b0251f09f 100644 --- a/applications/plugins/protoview/ui.c +++ b/applications/plugins/protoview/ui.c @@ -10,36 +10,31 @@ /* Return the ID of the currently selected subview, of the current * view. */ -int ui_get_current_subview(ProtoViewApp *app) { +int ui_get_current_subview(ProtoViewApp* app) { return app->current_subview[app->current_view]; } /* Called by view rendering callback that has subviews, to show small triangles * facing down/up if there are other subviews the user can access with up * and down. */ -void ui_show_available_subviews(Canvas *canvas, ProtoViewApp *app, - int last_subview) -{ +void ui_show_available_subviews(Canvas* canvas, ProtoViewApp* app, int last_subview) { int subview = ui_get_current_subview(app); - if (subview != 0) - canvas_draw_triangle(canvas,120,5,8,5,CanvasDirectionBottomToTop); - if (subview != last_subview-1) - canvas_draw_triangle(canvas,120,59,8,5,CanvasDirectionTopToBottom); + if(subview != 0) canvas_draw_triangle(canvas, 120, 5, 8, 5, CanvasDirectionBottomToTop); + if(subview != last_subview - 1) + canvas_draw_triangle(canvas, 120, 59, 8, 5, CanvasDirectionTopToBottom); } /* Handle up/down keys when we are in a subview. If the function catched * such keypress, it returns true, so that the actual view input callback * knows it can just return ASAP without doing anything. */ -bool ui_process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subview) { +bool ui_process_subview_updown(ProtoViewApp* app, InputEvent input, int last_subview) { int subview = ui_get_current_subview(app); - if (input.type == InputTypePress) { - if (input.key == InputKeyUp) { - if (subview != 0) - app->current_subview[app->current_view]--; + if(input.type == InputTypePress) { + if(input.key == InputKeyUp) { + if(subview != 0) app->current_subview[app->current_view]--; return true; - } else if (input.key == InputKeyDown) { - if (subview != last_subview-1) - app->current_subview[app->current_view]++; + } else if(input.key == InputKeyDown) { + if(subview != last_subview - 1) app->current_subview[app->current_view]++; return true; } } @@ -62,16 +57,18 @@ bool ui_process_subview_updown(ProtoViewApp *app, InputEvent input, int last_sub * * Note: if the buffer is not a null-termined zero string, what it contains will * be used as initial input for the user. */ -void ui_show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen, - void (*done_callback)(void*)) -{ +void ui_show_keyboard( + ProtoViewApp* app, + char* buffer, + uint32_t buflen, + void (*done_callback)(void*)) { app->show_text_input = true; app->text_input_buffer = buffer; app->text_input_buffer_len = buflen; app->text_input_done_callback = done_callback; } -void ui_dismiss_keyboard(ProtoViewApp *app) { +void ui_dismiss_keyboard(ProtoViewApp* app) { view_dispatcher_stop(app->view_dispatcher); } @@ -79,24 +76,24 @@ void ui_dismiss_keyboard(ProtoViewApp *app) { /* Set an alert message to be shown over any currently active view, for * the specified amount of time of 'ttl' milliseconds. */ -void ui_show_alert(ProtoViewApp *app, const char *text, uint32_t ttl) { +void ui_show_alert(ProtoViewApp* app, const char* text, uint32_t ttl) { app->alert_dismiss_time = furi_get_tick() + furi_ms_to_ticks(ttl); - snprintf(app->alert_text,ALERT_MAX_LEN,"%s",text); + snprintf(app->alert_text, ALERT_MAX_LEN, "%s", text); } /* Cancel the alert before its time has elapsed. */ -void ui_dismiss_alert(ProtoViewApp *app) { +void ui_dismiss_alert(ProtoViewApp* app) { app->alert_dismiss_time = 0; } /* Show the alert if an alert is set. This is called after the currently * active view displayed its stuff, so we overwrite the screen with the * alert message. */ -void ui_draw_alert_if_needed(Canvas *canvas, ProtoViewApp *app) { - if (app->alert_dismiss_time == 0) { +void ui_draw_alert_if_needed(Canvas* canvas, ProtoViewApp* app) { + if(app->alert_dismiss_time == 0) { /* No active alert. */ return; - } else if (app->alert_dismiss_time < furi_get_tick()) { + } else if(app->alert_dismiss_time < furi_get_tick()) { /* Alert just expired. */ ui_dismiss_alert(app); return; @@ -106,41 +103,43 @@ void ui_draw_alert_if_needed(Canvas *canvas, ProtoViewApp *app) { canvas_set_font(canvas, FontPrimary); uint8_t w = canvas_string_width(canvas, app->alert_text); uint8_t h = 8; // Font height. - uint8_t text_x = 64-(w/2); - uint8_t text_y = 32+4; + uint8_t text_x = 64 - (w / 2); + uint8_t text_y = 32 + 4; uint8_t padding = 3; - canvas_set_color(canvas,ColorBlack); - canvas_draw_box(canvas,text_x-padding,text_y-padding-h,w+padding*2,h+padding*2); - canvas_set_color(canvas,ColorWhite); - canvas_draw_box(canvas,text_x-padding+1,text_y-padding-h+1,w+padding*2-2,h+padding*2-2); - canvas_set_color(canvas,ColorBlack); - canvas_draw_str(canvas,text_x,text_y,app->alert_text); + canvas_set_color(canvas, ColorBlack); + canvas_draw_box( + canvas, text_x - padding, text_y - padding - h, w + padding * 2, h + padding * 2); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box( + canvas, + text_x - padding + 1, + text_y - padding - h + 1, + w + padding * 2 - 2, + h + padding * 2 - 2); + canvas_set_color(canvas, ColorBlack); + canvas_draw_str(canvas, text_x, text_y, app->alert_text); } /* =========================== Canvas extensions ============================ */ -void canvas_draw_str_with_border(Canvas* canvas, uint8_t x, uint8_t y, const char* str, Color text_color, Color border_color) -{ +void canvas_draw_str_with_border( + Canvas* canvas, + uint8_t x, + uint8_t y, + const char* str, + Color text_color, + Color border_color) { struct { - uint8_t x; uint8_t y; - } dir[8] = { - {-1,-1}, - {0,-1}, - {1,-1}, - {1,0}, - {1,1}, - {0,1}, - {-1,1}, - {-1,0} - }; + uint8_t x; + uint8_t y; + } dir[8] = {{-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}}; /* Rotate in all the directions writing the same string to create a * border, then write the actual string in the other color in the * middle. */ canvas_set_color(canvas, border_color); - for (int j = 0; j < 8; j++) - canvas_draw_str(canvas,x+dir[j].x,y+dir[j].y,str); + for(int j = 0; j < 8; j++) canvas_draw_str(canvas, x + dir[j].x, y + dir[j].y, str); canvas_set_color(canvas, text_color); - canvas_draw_str(canvas,x,y,str); + canvas_draw_str(canvas, x, y, str); canvas_set_color(canvas, ColorBlack); } diff --git a/applications/plugins/protoview/view_build.c b/applications/plugins/protoview/view_build.c index fd276b61d..955855902 100644 --- a/applications/plugins/protoview/view_build.c +++ b/applications/plugins/protoview/view_build.c @@ -3,39 +3,38 @@ #include "app.h" -extern ProtoViewDecoder *Decoders[]; // Defined in signal.c. +extern ProtoViewDecoder* Decoders[]; // Defined in signal.c. /* Our view private data. */ #define USER_VALUE_LEN 64 typedef struct { - ProtoViewDecoder *decoder; /* Decoder we are using to create a + ProtoViewDecoder* decoder; /* Decoder we are using to create a message. */ - uint32_t cur_decoder; /* Decoder index when we are yet selecting + uint32_t cur_decoder; /* Decoder index when we are yet selecting a decoder. Used when decoder is NULL. */ - ProtoViewFieldSet *fieldset; /* The fields to populate. */ - uint32_t cur_field; /* Field we are editing right now. This + ProtoViewFieldSet* fieldset; /* The fields to populate. */ + uint32_t cur_field; /* Field we are editing right now. This is the index inside the 'fieldset' fields. */ - char *user_value; /* Keyboard input to replace the current + char* user_value; /* Keyboard input to replace the current field value goes here. */ } BuildViewPrivData; /* Not all the decoders support message bulding, so we can't just * increment / decrement the cur_decoder index here. */ -static void select_next_decoder(ProtoViewApp *app) { - BuildViewPrivData *privdata = app->view_privdata; - do { +static void select_next_decoder(ProtoViewApp* app) { + BuildViewPrivData* privdata = app->view_privdata; + do { privdata->cur_decoder++; - if (Decoders[privdata->cur_decoder] == NULL) - privdata->cur_decoder = 0; + if(Decoders[privdata->cur_decoder] == NULL) privdata->cur_decoder = 0; } while(Decoders[privdata->cur_decoder]->get_fields == NULL); } /* Like select_next_decoder() but goes backward. */ -static void select_prev_decoder(ProtoViewApp *app) { - BuildViewPrivData *privdata = app->view_privdata; +static void select_prev_decoder(ProtoViewApp* app) { + BuildViewPrivData* privdata = app->view_privdata; do { - if (privdata->cur_decoder == 0) { + if(privdata->cur_decoder == 0) { /* Go one after the last one to wrap around. */ while(Decoders[privdata->cur_decoder]) privdata->cur_decoder++; } @@ -45,69 +44,73 @@ static void select_prev_decoder(ProtoViewApp *app) { /* Render the view to select the decoder, among the ones that * support message building. */ -static void render_view_select_decoder(Canvas *const canvas, ProtoViewApp *app) { - BuildViewPrivData *privdata = app->view_privdata; +static void render_view_select_decoder(Canvas* const canvas, ProtoViewApp* app) { + BuildViewPrivData* privdata = app->view_privdata; canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 0, 9, "Signal creator"); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 0, 19, "up/down: select, ok: choose"); canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas,64,38,AlignCenter,AlignCenter, - Decoders[privdata->cur_decoder]->name); + canvas_draw_str_aligned( + canvas, 64, 38, AlignCenter, AlignCenter, Decoders[privdata->cur_decoder]->name); } /* Render the view that allows the user to populate the fields needed * for the selected decoder to build a message. */ -static void render_view_set_fields(Canvas *const canvas, ProtoViewApp *app) { - BuildViewPrivData *privdata = app->view_privdata; +static void render_view_set_fields(Canvas* const canvas, ProtoViewApp* app) { + BuildViewPrivData* privdata = app->view_privdata; char buf[32]; - snprintf(buf,sizeof(buf), "%s field %d/%d", - privdata->decoder->name, (int)privdata->cur_field+1, + snprintf( + buf, + sizeof(buf), + "%s field %d/%d", + privdata->decoder->name, + (int)privdata->cur_field + 1, (int)privdata->fieldset->numfields); - canvas_set_color(canvas,ColorBlack); - canvas_draw_box(canvas,0,0,128,21); - canvas_set_color(canvas,ColorWhite); + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 0, 0, 128, 21); + canvas_set_color(canvas, ColorWhite); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 1, 9, buf); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 1, 19, "up/down: next field, ok: edit"); /* Write the field name, type, current content. */ - canvas_set_color(canvas,ColorBlack); - ProtoViewField *field = privdata->fieldset->fields[privdata->cur_field]; - snprintf(buf,sizeof(buf), "%s %s:%d", field->name, - field_get_type_name(field), (int)field->len); + canvas_set_color(canvas, ColorBlack); + ProtoViewField* field = privdata->fieldset->fields[privdata->cur_field]; + snprintf( + buf, sizeof(buf), "%s %s:%d", field->name, field_get_type_name(field), (int)field->len); buf[0] = toupper(buf[0]); canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas,64,30,AlignCenter,AlignCenter,buf); + canvas_draw_str_aligned(canvas, 64, 30, AlignCenter, AlignCenter, buf); canvas_set_font(canvas, FontSecondary); /* Render the current value between "" */ - unsigned int written = (unsigned int) field_to_string(buf+1,sizeof(buf)-1,field); + unsigned int written = (unsigned int)field_to_string(buf + 1, sizeof(buf) - 1, field); buf[0] = '"'; - if (written+3 < sizeof(buf)) memcpy(buf+written+1,"\"\x00",2); - canvas_draw_str_aligned(canvas,63,45,AlignCenter,AlignCenter,buf); + if(written + 3 < sizeof(buf)) memcpy(buf + written + 1, "\"\x00", 2); + canvas_draw_str_aligned(canvas, 63, 45, AlignCenter, AlignCenter, buf); /* Footer instructions. */ canvas_draw_str(canvas, 0, 62, "Long ok: create, < > incr/decr"); } /* Render the build message view. */ -void render_view_build_message(Canvas *const canvas, ProtoViewApp *app) { - BuildViewPrivData *privdata = app->view_privdata; +void render_view_build_message(Canvas* const canvas, ProtoViewApp* app) { + BuildViewPrivData* privdata = app->view_privdata; - if (privdata->decoder) - render_view_set_fields(canvas,app); + if(privdata->decoder) + render_view_set_fields(canvas, app); else - render_view_select_decoder(canvas,app); + render_view_select_decoder(canvas, app); } /* Handle input for the decoder selection. */ -static void process_input_select_decoder(ProtoViewApp *app, InputEvent input) { - BuildViewPrivData *privdata = app->view_privdata; - if (input.type == InputTypeShort) { - if (input.key == InputKeyOk) { +static void process_input_select_decoder(ProtoViewApp* app, InputEvent input) { + BuildViewPrivData* privdata = app->view_privdata; + if(input.type == InputTypeShort) { + if(input.key == InputKeyOk) { privdata->decoder = Decoders[privdata->cur_decoder]; privdata->fieldset = fieldset_new(); privdata->decoder->get_fields(privdata->fieldset); @@ -116,11 +119,8 @@ static void process_input_select_decoder(ProtoViewApp *app, InputEvent input) { * same decoder the user selected, let's populate the * defaults with the current values. So the user will * actaully edit the current message. */ - if (app->signal_decoded && - app->msg_info->decoder == privdata->decoder) - { - fieldset_copy_matching_fields(privdata->fieldset, - app->msg_info->fieldset); + if(app->signal_decoded && app->msg_info->decoder == privdata->decoder) { + fieldset_copy_matching_fields(privdata->fieldset, app->msg_info->fieldset); } /* Now we use the subview system in order to protect the @@ -128,10 +128,10 @@ static void process_input_select_decoder(ProtoViewApp *app, InputEvent input) { Since we are technically into a subview now, we'll have control of < and >. */ InputEvent ii = {.type = InputTypePress, .key = InputKeyDown}; - ui_process_subview_updown(app,ii,2); - } else if (input.key == InputKeyDown) { + ui_process_subview_updown(app, ii, 2); + } else if(input.key == InputKeyDown) { select_next_decoder(app); - } else if (input.key == InputKeyUp) { + } else if(input.key == InputKeyUp) { select_prev_decoder(app); } } @@ -140,12 +140,13 @@ static void process_input_select_decoder(ProtoViewApp *app, InputEvent input) { /* Called after the user typed the new field value in the keyboard. * Let's save it and remove the keyboard view. */ static void text_input_done_callback(void* context) { - ProtoViewApp *app = context; - BuildViewPrivData *privdata = app->view_privdata; + ProtoViewApp* app = context; + BuildViewPrivData* privdata = app->view_privdata; - if (field_set_from_string(privdata->fieldset->fields[privdata->cur_field], - privdata->user_value, strlen(privdata->user_value)) == false) - { + if(field_set_from_string( + privdata->fieldset->fields[privdata->cur_field], + privdata->user_value, + strlen(privdata->user_value)) == false) { ui_show_alert(app, "Invalid value", 1500); } @@ -160,94 +161,88 @@ static void text_input_done_callback(void* context) { * decrement the current field in a much simpler way. * * The current filed is changed by 'incr' amount. */ -static bool increment_current_field(ProtoViewApp *app, int incr) { - BuildViewPrivData *privdata = app->view_privdata; - ProtoViewFieldSet *fs = privdata->fieldset; - ProtoViewField *f = fs->fields[privdata->cur_field]; - return field_incr_value(f,incr); +static bool increment_current_field(ProtoViewApp* app, int incr) { + BuildViewPrivData* privdata = app->view_privdata; + ProtoViewFieldSet* fs = privdata->fieldset; + ProtoViewField* f = fs->fields[privdata->cur_field]; + return field_incr_value(f, incr); } /* Handle input for fields editing mode. */ -static void process_input_set_fields(ProtoViewApp *app, InputEvent input) { - BuildViewPrivData *privdata = app->view_privdata; - ProtoViewFieldSet *fs = privdata->fieldset; +static void process_input_set_fields(ProtoViewApp* app, InputEvent input) { + BuildViewPrivData* privdata = app->view_privdata; + ProtoViewFieldSet* fs = privdata->fieldset; - if (input.type == InputTypeShort && input.key == InputKeyOk) { + if(input.type == InputTypeShort && input.key == InputKeyOk) { /* Show the keyboard to let the user type the new * value. */ - if (privdata->user_value == NULL) - privdata->user_value = malloc(USER_VALUE_LEN); - field_to_string(privdata->user_value, USER_VALUE_LEN, - fs->fields[privdata->cur_field]); - ui_show_keyboard(app, privdata->user_value, USER_VALUE_LEN, - text_input_done_callback); - } else if (input.type == InputTypeShort && input.key == InputKeyDown) { - privdata->cur_field = (privdata->cur_field+1) % fs->numfields; - } else if (input.type == InputTypeShort && input.key == InputKeyUp) { - if (privdata->cur_field == 0) - privdata->cur_field = fs->numfields-1; + if(privdata->user_value == NULL) privdata->user_value = malloc(USER_VALUE_LEN); + field_to_string(privdata->user_value, USER_VALUE_LEN, fs->fields[privdata->cur_field]); + ui_show_keyboard(app, privdata->user_value, USER_VALUE_LEN, text_input_done_callback); + } else if(input.type == InputTypeShort && input.key == InputKeyDown) { + privdata->cur_field = (privdata->cur_field + 1) % fs->numfields; + } else if(input.type == InputTypeShort && input.key == InputKeyUp) { + if(privdata->cur_field == 0) + privdata->cur_field = fs->numfields - 1; else privdata->cur_field--; - } else if (input.type == InputTypeShort && input.key == InputKeyRight) { - increment_current_field(app,1); - } else if (input.type == InputTypeShort && input.key == InputKeyLeft) { - increment_current_field(app,-1); - } else if (input.type == InputTypeRepeat && input.key == InputKeyRight) { + } else if(input.type == InputTypeShort && input.key == InputKeyRight) { + increment_current_field(app, 1); + } else if(input.type == InputTypeShort && input.key == InputKeyLeft) { + increment_current_field(app, -1); + } else if(input.type == InputTypeRepeat && input.key == InputKeyRight) { // The reason why we don't use a large increment directly // is that certain field types only support +1 -1 increments. int times = 10; - while(times--) increment_current_field(app,1); - } else if (input.type == InputTypeRepeat && input.key == InputKeyLeft) { + while(times--) increment_current_field(app, 1); + } else if(input.type == InputTypeRepeat && input.key == InputKeyLeft) { int times = 10; - while(times--) increment_current_field(app,-1); - } else if (input.type == InputTypeLong && input.key == InputKeyOk) { + while(times--) increment_current_field(app, -1); + } else if(input.type == InputTypeLong && input.key == InputKeyOk) { // Build the message in a fresh raw buffer. - if (privdata->decoder->build_message) { - RawSamplesBuffer *rs = raw_samples_alloc(); - privdata->decoder->build_message(rs,privdata->fieldset); + if(privdata->decoder->build_message) { + RawSamplesBuffer* rs = raw_samples_alloc(); + privdata->decoder->build_message(rs, privdata->fieldset); app->signal_decoded = false; // So that the new signal will be - // accepted as the current signal. - scan_for_signal(app,rs); + // accepted as the current signal. + scan_for_signal(app, rs); raw_samples_free(rs); - ui_show_alert(app,"Done: press back key",3000); + ui_show_alert(app, "Done: press back key", 3000); } } } /* Handle input for the build message view. */ -void process_input_build_message(ProtoViewApp *app, InputEvent input) { - BuildViewPrivData *privdata = app->view_privdata; - if (privdata->decoder) - process_input_set_fields(app,input); +void process_input_build_message(ProtoViewApp* app, InputEvent input) { + BuildViewPrivData* privdata = app->view_privdata; + if(privdata->decoder) + process_input_set_fields(app, input); else - process_input_select_decoder(app,input); + process_input_select_decoder(app, input); } /* Enter view callback. */ -void view_enter_build_message(ProtoViewApp *app) { - BuildViewPrivData *privdata = app->view_privdata; +void view_enter_build_message(ProtoViewApp* app) { + BuildViewPrivData* privdata = app->view_privdata; // When we enter the view, the current decoder is just set to zero. // Seek the next valid if needed. - if (Decoders[privdata->cur_decoder]->get_fields == NULL) { + if(Decoders[privdata->cur_decoder]->get_fields == NULL) { select_next_decoder(app); } // However if there is currently a decoded message, and the // decoder of such message supports message building, let's // select it. - if (app->signal_decoded && - app->msg_info->decoder->get_fields && - app->msg_info->decoder->build_message) - { - while(Decoders[privdata->cur_decoder] != app->msg_info->decoder) - select_next_decoder(app); + if(app->signal_decoded && app->msg_info->decoder->get_fields && + app->msg_info->decoder->build_message) { + while(Decoders[privdata->cur_decoder] != app->msg_info->decoder) select_next_decoder(app); } } /* Called on exit for cleanup. */ -void view_exit_build_message(ProtoViewApp *app) { - BuildViewPrivData *privdata = app->view_privdata; - if (privdata->fieldset) fieldset_free(privdata->fieldset); - if (privdata->user_value) free(privdata->user_value); +void view_exit_build_message(ProtoViewApp* app) { + BuildViewPrivData* privdata = app->view_privdata; + if(privdata->fieldset) fieldset_free(privdata->fieldset); + if(privdata->user_value) free(privdata->user_value); } diff --git a/applications/plugins/protoview/view_direct_sampling.c b/applications/plugins/protoview/view_direct_sampling.c index 251a289b8..1ab90f096 100644 --- a/applications/plugins/protoview/view_direct_sampling.c +++ b/applications/plugins/protoview/view_direct_sampling.c @@ -7,47 +7,46 @@ /* Read directly from the G0 CC1101 pin, and draw a black or white * dot depending on the level. */ -void render_view_direct_sampling(Canvas *const canvas, ProtoViewApp *app) { - if (!app->direct_sampling_enabled) { +void render_view_direct_sampling(Canvas* const canvas, ProtoViewApp* app) { + if(!app->direct_sampling_enabled) { canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas,2,9,"Direct sampling is a special"); - canvas_draw_str(canvas,2,18,"mode that displays the signal"); - canvas_draw_str(canvas,2,27,"captured in real time. Like in"); - canvas_draw_str(canvas,2,36,"a old CRT TV. It's very slow."); - canvas_draw_str(canvas,2,45,"Can crash your Flipper."); + canvas_draw_str(canvas, 2, 9, "Direct sampling is a special"); + canvas_draw_str(canvas, 2, 18, "mode that displays the signal"); + canvas_draw_str(canvas, 2, 27, "captured in real time. Like in"); + canvas_draw_str(canvas, 2, 36, "a old CRT TV. It's very slow."); + canvas_draw_str(canvas, 2, 45, "Can crash your Flipper."); canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas,14,60,"To enable press OK"); + canvas_draw_str(canvas, 14, 60, "To enable press OK"); return; } - for (int y = 0; y < 64; y++) { - for (int x = 0; x < 128; x++) { + for(int y = 0; y < 64; y++) { + for(int x = 0; x < 128; x++) { bool level = furi_hal_gpio_read(&gpio_cc1101_g0); - if (level) canvas_draw_dot(canvas,x,y); + if(level) canvas_draw_dot(canvas, x, y); /* Busy loop: this is a terrible approach as it blocks * everything else, but for now it's the best we can do * to obtain direct data with some spacing. */ - uint32_t x = 250; while(x--); + uint32_t x = 250; + while(x--) + ; } } canvas_set_font(canvas, FontSecondary); - canvas_draw_str_with_border(canvas,36,60,"Direct sampling", - ColorWhite,ColorBlack); + canvas_draw_str_with_border(canvas, 36, 60, "Direct sampling", ColorWhite, ColorBlack); } /* Handle input */ -void process_input_direct_sampling(ProtoViewApp *app, InputEvent input) { - if (input.type == InputTypePress && input.key == InputKeyOk) { +void process_input_direct_sampling(ProtoViewApp* app, InputEvent input) { + if(input.type == InputTypePress && input.key == InputKeyOk) { app->direct_sampling_enabled = !app->direct_sampling_enabled; } } /* Enter view. Stop the subghz thread to prevent access as we read * the CC1101 data directly. */ -void view_enter_direct_sampling(ProtoViewApp *app) { - if (app->txrx->txrx_state == TxRxStateRx && - !app->txrx->debug_timer_sampling) - { +void view_enter_direct_sampling(ProtoViewApp* app) { + if(app->txrx->txrx_state == TxRxStateRx && !app->txrx->debug_timer_sampling) { subghz_worker_stop(app->txrx->worker); } else { raw_sampling_worker_stop(app); @@ -55,10 +54,8 @@ void view_enter_direct_sampling(ProtoViewApp *app) { } /* Exit view. Restore the subghz thread. */ -void view_exit_direct_sampling(ProtoViewApp *app) { - if (app->txrx->txrx_state == TxRxStateRx && - !app->txrx->debug_timer_sampling) - { +void view_exit_direct_sampling(ProtoViewApp* app) { + if(app->txrx->txrx_state == TxRxStateRx && !app->txrx->debug_timer_sampling) { subghz_worker_start(app->txrx->worker); } else { raw_sampling_worker_start(app); diff --git a/applications/plugins/protoview/view_info.c b/applications/plugins/protoview/view_info.c index 6aa69739c..75fc58411 100644 --- a/applications/plugins/protoview/view_info.c +++ b/applications/plugins/protoview/view_info.c @@ -20,31 +20,29 @@ typedef struct { * so that the user can see what they are saving. With left/right * you can move to next rows. Here we store where we are. */ uint32_t signal_display_start_row; - char *filename; + char* filename; uint8_t cur_info_page; // Info page to display. Useful when there are - // too many fields populated by the decoder that - // a single page is not enough. + // too many fields populated by the decoder that + // a single page is not enough. } InfoViewPrivData; /* Draw the text label and value of the specified info field at x,y. */ -static void render_info_field(Canvas *const canvas, - ProtoViewField *f, uint8_t x, uint8_t y) -{ +static void render_info_field(Canvas* const canvas, ProtoViewField* f, uint8_t x, uint8_t y) { char buf[64]; char strval[32]; - field_to_string(strval,sizeof(strval),f); - snprintf(buf,sizeof(buf),"%s: %s", f->name, strval); + field_to_string(strval, sizeof(strval), f); + snprintf(buf, sizeof(buf), "%s: %s", f->name, strval); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, x, y, buf); } /* Render the view with the detected message information. */ #define INFO_LINES_PER_PAGE 5 -static void render_subview_main(Canvas *const canvas, ProtoViewApp *app) { - InfoViewPrivData *privdata = app->view_privdata; - uint8_t pages = (app->msg_info->fieldset->numfields - +(INFO_LINES_PER_PAGE-1)) / INFO_LINES_PER_PAGE; +static void render_subview_main(Canvas* const canvas, ProtoViewApp* app) { + InfoViewPrivData* privdata = app->view_privdata; + uint8_t pages = + (app->msg_info->fieldset->numfields + (INFO_LINES_PER_PAGE - 1)) / INFO_LINES_PER_PAGE; privdata->cur_info_page %= pages; uint8_t current_page = privdata->cur_info_page; char buf[32]; @@ -53,9 +51,9 @@ static void render_subview_main(Canvas *const canvas, ProtoViewApp *app) { canvas_set_font(canvas, FontPrimary); uint8_t y = 8, lineheight = 10; - if (pages > 1) { - snprintf(buf,sizeof(buf),"%s %u/%u", app->msg_info->decoder->name, - current_page+1, pages); + if(pages > 1) { + snprintf( + buf, sizeof(buf), "%s %u/%u", app->msg_info->decoder->name, current_page + 1, pages); canvas_draw_str(canvas, 0, y, buf); } else { canvas_draw_str(canvas, 0, y, app->msg_info->decoder->name); @@ -64,26 +62,30 @@ static void render_subview_main(Canvas *const canvas, ProtoViewApp *app) { /* Draw the info fields. */ uint8_t max_lines = INFO_LINES_PER_PAGE; - uint32_t j = current_page*max_lines; - while (j < app->msg_info->fieldset->numfields) { - render_info_field(canvas,app->msg_info->fieldset->fields[j++],0,y); + uint32_t j = current_page * max_lines; + while(j < app->msg_info->fieldset->numfields) { + render_info_field(canvas, app->msg_info->fieldset->fields[j++], 0, y); y += lineheight; - if (--max_lines == 0) break; + if(--max_lines == 0) break; } /* Draw a vertical "save" label. Temporary solution, to switch to * something better ASAP. */ y = 37; lineheight = 7; - canvas_draw_str(canvas, 119, y, "s"); y += lineheight; - canvas_draw_str(canvas, 119, y, "a"); y += lineheight; - canvas_draw_str(canvas, 119, y, "v"); y += lineheight; - canvas_draw_str(canvas, 119, y, "e"); y += lineheight; + canvas_draw_str(canvas, 119, y, "s"); + y += lineheight; + canvas_draw_str(canvas, 119, y, "a"); + y += lineheight; + canvas_draw_str(canvas, 119, y, "v"); + y += lineheight; + canvas_draw_str(canvas, 119, y, "e"); + y += lineheight; } /* Render view with save option. */ -static void render_subview_save(Canvas *const canvas, ProtoViewApp *app) { - InfoViewPrivData *privdata = app->view_privdata; +static void render_subview_save(Canvas* const canvas, ProtoViewApp* app) { + InfoViewPrivData* privdata = app->view_privdata; /* Display our signal in digital form: here we don't show the * signal with the exact timing of the received samples, but as it @@ -92,21 +94,20 @@ static void render_subview_save(Canvas *const canvas, ProtoViewApp *app) { uint8_t rowheight = 11; uint8_t bitwidth = 4; uint8_t bitheight = 5; - uint32_t idx = privdata->signal_display_start_row * (128/4); + uint32_t idx = privdata->signal_display_start_row * (128 / 4); bool prevbit = false; - for (uint8_t y = bitheight+12; y <= rows*rowheight; y += rowheight) { - for (uint8_t x = 0; x < 128; x += 4) { - bool bit = bitmap_get(app->msg_info->bits, - app->msg_info->bits_bytes,idx); - uint8_t prevy = y + prevbit*(bitheight*-1) - 1; - uint8_t thisy = y + bit*(bitheight*-1) - 1; - canvas_draw_line(canvas,x,prevy,x,thisy); - canvas_draw_line(canvas,x,thisy,x+bitwidth-1,thisy); + for(uint8_t y = bitheight + 12; y <= rows * rowheight; y += rowheight) { + for(uint8_t x = 0; x < 128; x += 4) { + bool bit = bitmap_get(app->msg_info->bits, app->msg_info->bits_bytes, idx); + uint8_t prevy = y + prevbit * (bitheight * -1) - 1; + uint8_t thisy = y + bit * (bitheight * -1) - 1; + canvas_draw_line(canvas, x, prevy, x, thisy); + canvas_draw_line(canvas, x, thisy, x + bitwidth - 1, thisy); prevbit = bit; - if (idx >= app->msg_info->pulses_count) { + if(idx >= app->msg_info->pulses_count) { canvas_set_color(canvas, ColorWhite); - canvas_draw_dot(canvas, x+1,thisy); - canvas_draw_dot(canvas, x+3,thisy); + canvas_draw_dot(canvas, x + 1, thisy); + canvas_draw_dot(canvas, x + 3, thisy); canvas_set_color(canvas, ColorBlack); } idx++; // Draw next bit @@ -118,28 +119,32 @@ static void render_subview_save(Canvas *const canvas, ProtoViewApp *app) { } /* Render the selected subview of this view. */ -void render_view_info(Canvas *const canvas, ProtoViewApp *app) { - if (app->signal_decoded == false) { +void render_view_info(Canvas* const canvas, ProtoViewApp* app) { + if(app->signal_decoded == false) { canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 30,36,"No signal decoded"); + canvas_draw_str(canvas, 30, 36, "No signal decoded"); return; } - ui_show_available_subviews(canvas,app,SubViewInfoLast); + ui_show_available_subviews(canvas, app, SubViewInfoLast); switch(app->current_subview[app->current_view]) { - case SubViewInfoMain: render_subview_main(canvas,app); break; - case SubViewInfoSave: render_subview_save(canvas,app); break; + case SubViewInfoMain: + render_subview_main(canvas, app); + break; + case SubViewInfoSave: + render_subview_save(canvas, app); + break; } } /* The user typed the file name. Let's save it and remove the keyboard * view. */ static void text_input_done_callback(void* context) { - ProtoViewApp *app = context; - InfoViewPrivData *privdata = app->view_privdata; + ProtoViewApp* app = context; + InfoViewPrivData* privdata = app->view_privdata; - FuriString *save_path = furi_string_alloc_printf( - "%s/%s.sub", EXT_PATH("subghz"), privdata->filename); + FuriString* save_path = + furi_string_alloc_printf("%s/%s.sub", EXT_PATH("subghz"), privdata->filename); save_signal(app, furi_string_get_cstr(save_path)); furi_string_free(save_path); @@ -151,22 +156,22 @@ static void text_input_done_callback(void* context) { /* Replace all the occurrences of character c1 with c2 in the specified * string. */ -void str_replace(char *buf, char c1, char c2) { - char *p = buf; +void str_replace(char* buf, char c1, char c2) { + char* p = buf; while(*p) { - if (*p == c1) *p = c2; + if(*p == c1) *p = c2; p++; } } /* Set a random filename the user can edit. */ -void set_signal_random_filename(ProtoViewApp *app, char *buf, size_t buflen) { +void set_signal_random_filename(ProtoViewApp* app, char* buf, size_t buflen) { char suffix[6]; - set_random_name(suffix,sizeof(suffix)); - snprintf(buf,buflen,"%.10s-%s-%d",app->msg_info->decoder->name,suffix,rand()%1000); - str_replace(buf,' ','_'); - str_replace(buf,'-','_'); - str_replace(buf,'/','_'); + set_random_name(suffix, sizeof(suffix)); + snprintf(buf, buflen, "%.10s-%s-%d", app->msg_info->decoder->name, suffix, rand() % 1000); + str_replace(buf, ' ', '_'); + str_replace(buf, '-', '_'); + str_replace(buf, '/', '_'); } /* ========================== Signal transmission =========================== */ @@ -180,20 +185,20 @@ typedef enum { SendSignalEndTransmission } SendSignalState; -#define PROTOVIEW_SENDSIGNAL_START_GAP 10000 /* microseconds. */ -#define PROTOVIEW_SENDSIGNAL_END_GAP 10000 /* microseconds. */ +#define PROTOVIEW_SENDSIGNAL_START_GAP 10000 /* microseconds. */ +#define PROTOVIEW_SENDSIGNAL_END_GAP 10000 /* microseconds. */ typedef struct { - SendSignalState state; // Current state. - uint32_t curpos; // Current bit position of data to send. - ProtoViewApp *app; // App reference. + SendSignalState state; // Current state. + uint32_t curpos; // Current bit position of data to send. + ProtoViewApp* app; // App reference. uint32_t start_gap_dur; // Gap to send at the start. - uint32_t end_gap_dur; // Gap to send at the end. + uint32_t end_gap_dur; // Gap to send at the end. } SendSignalCtx; /* Setup the state context for the callback responsible to feed data * to the subghz async tx system. */ -static void send_signal_init(SendSignalCtx *ss, ProtoViewApp *app) { +static void send_signal_init(SendSignalCtx* ss, ProtoViewApp* app) { ss->state = SendSignalSendStartGap; ss->curpos = 0; ss->app = app; @@ -214,27 +219,26 @@ static void send_signal_init(SendSignalCtx *ss, ProtoViewApp *app) { * message we are, in ss->curoff. We also send a start and end gap in order * to make sure the transmission is clear. */ -LevelDuration radio_tx_feed_data(void *ctx) { - SendSignalCtx *ss = ctx; +LevelDuration radio_tx_feed_data(void* ctx) { + SendSignalCtx* ss = ctx; /* Send start gap. */ - if (ss->state == SendSignalSendStartGap) { + if(ss->state == SendSignalSendStartGap) { ss->state = SendSignalSendBits; - return level_duration_make(0,ss->start_gap_dur); + return level_duration_make(0, ss->start_gap_dur); } /* Send data. */ - if (ss->state == SendSignalSendBits) { + if(ss->state == SendSignalSendBits) { uint32_t dur = 0, j; uint32_t level = 0; /* Let's see how many consecutive bits we have with the same * level. */ - for (j = 0; ss->curpos+j < ss->app->msg_info->pulses_count; j++) { - uint32_t l = bitmap_get(ss->app->msg_info->bits, - ss->app->msg_info->bits_bytes, - ss->curpos+j); - if (j == 0) { + for(j = 0; ss->curpos + j < ss->app->msg_info->pulses_count; j++) { + uint32_t l = + bitmap_get(ss->app->msg_info->bits, ss->app->msg_info->bits_bytes, ss->curpos + j); + if(j == 0) { /* At the first bit of this sequence, we store the * level of the sequence. */ level = l; @@ -244,22 +248,21 @@ LevelDuration radio_tx_feed_data(void *ctx) { /* As long as the level is the same, we update the duration. * Otherwise stop the loop and return this sample. */ - if (l != level) break; + if(l != level) break; dur += ss->app->msg_info->short_pulse_dur; } ss->curpos += j; /* If this was the last set of bits, change the state to * send the final gap. */ - if (ss->curpos >= ss->app->msg_info->pulses_count) - ss->state = SendSignalSendEndGap; + if(ss->curpos >= ss->app->msg_info->pulses_count) ss->state = SendSignalSendEndGap; return level_duration_make(level, dur); } /* Send end gap. */ - if (ss->state == SendSignalSendEndGap) { + if(ss->state == SendSignalSendEndGap) { ss->state = SendSignalEndTransmission; - return level_duration_make(0,ss->end_gap_dur); + return level_duration_make(0, ss->end_gap_dur); } /* End transmission. Here state is guaranteed @@ -268,7 +271,7 @@ LevelDuration radio_tx_feed_data(void *ctx) { } /* Vibrate and produce a click sound when a signal is sent. */ -void notify_signal_sent(ProtoViewApp *app) { +void notify_signal_sent(ProtoViewApp* app) { static const NotificationSequence sent_seq = { &message_blue_255, &message_vibro_on, @@ -277,59 +280,53 @@ void notify_signal_sent(ProtoViewApp *app) { &message_sound_off, &message_vibro_off, &message_blue_0, - NULL - }; + NULL}; notification_message(app->notification, &sent_seq); } /* Handle input for the info view. */ -void process_input_info(ProtoViewApp *app, InputEvent input) { +void process_input_info(ProtoViewApp* app, InputEvent input) { /* If we don't have a decoded signal, we don't allow to go up/down * in the subviews: they are only useful when a loaded signal. */ - if (app->signal_decoded && - ui_process_subview_updown(app,input,SubViewInfoLast)) return; + if(app->signal_decoded && ui_process_subview_updown(app, input, SubViewInfoLast)) return; - InfoViewPrivData *privdata = app->view_privdata; + InfoViewPrivData* privdata = app->view_privdata; int subview = ui_get_current_subview(app); /* Main subview. */ - if (subview == SubViewInfoMain) { - if (input.type == InputTypeLong && input.key == InputKeyOk) { + if(subview == SubViewInfoMain) { + if(input.type == InputTypeLong && input.key == InputKeyOk) { /* Reset the current sample to capture the next. */ reset_current_signal(app); - } else if (input.type == InputTypeShort && input.key == InputKeyOk) { + } else if(input.type == InputTypeShort && input.key == InputKeyOk) { /* Show next info page. */ privdata->cur_info_page++; } - } else if (subview == SubViewInfoSave) { - /* Save subview. */ - if (input.type == InputTypePress && input.key == InputKeyRight) { + } else if(subview == SubViewInfoSave) { + /* Save subview. */ + if(input.type == InputTypePress && input.key == InputKeyRight) { privdata->signal_display_start_row++; - } else if (input.type == InputTypePress && input.key == InputKeyLeft) { - if (privdata->signal_display_start_row != 0) - privdata->signal_display_start_row--; - } else if (input.type == InputTypeLong && input.key == InputKeyOk) - { + } else if(input.type == InputTypePress && input.key == InputKeyLeft) { + if(privdata->signal_display_start_row != 0) privdata->signal_display_start_row--; + } else if(input.type == InputTypeLong && input.key == InputKeyOk) { // We have have the buffer already allocated, in case the // user aborted with BACK a previous saving. - if (privdata->filename == NULL) - privdata->filename = malloc(SAVE_FILENAME_LEN); - set_signal_random_filename(app,privdata->filename,SAVE_FILENAME_LEN); - ui_show_keyboard(app, privdata->filename, SAVE_FILENAME_LEN, - text_input_done_callback); - } else if (input.type == InputTypeShort && input.key == InputKeyOk) { + if(privdata->filename == NULL) privdata->filename = malloc(SAVE_FILENAME_LEN); + set_signal_random_filename(app, privdata->filename, SAVE_FILENAME_LEN); + ui_show_keyboard(app, privdata->filename, SAVE_FILENAME_LEN, text_input_done_callback); + } else if(input.type == InputTypeShort && input.key == InputKeyOk) { SendSignalCtx send_state; - send_signal_init(&send_state,app); - radio_tx_signal(app,radio_tx_feed_data,&send_state); + send_signal_init(&send_state, app); + radio_tx_signal(app, radio_tx_feed_data, &send_state); notify_signal_sent(app); } } } /* Called on view exit. */ -void view_exit_info(ProtoViewApp *app) { - InfoViewPrivData *privdata = app->view_privdata; +void view_exit_info(ProtoViewApp* app) { + InfoViewPrivData* privdata = app->view_privdata; // When the user aborts the keyboard input, we are left with the // filename buffer allocated. - if (privdata->filename) free(privdata->filename); + if(privdata->filename) free(privdata->filename); } diff --git a/applications/plugins/protoview/view_raw_signal.c b/applications/plugins/protoview/view_raw_signal.c index 023e986f9..38354bef9 100644 --- a/applications/plugins/protoview/view_raw_signal.c +++ b/applications/plugins/protoview/view_raw_signal.c @@ -12,7 +12,7 @@ * * The 'idx' argument is the first sample to render in the circular * buffer. */ -void render_signal(ProtoViewApp *app, Canvas *const canvas, RawSamplesBuffer *buf, uint32_t idx) { +void render_signal(ProtoViewApp* app, Canvas* const canvas, RawSamplesBuffer* buf, uint32_t idx) { canvas_set_color(canvas, ColorBlack); int rows = 8; @@ -20,31 +20,29 @@ void render_signal(ProtoViewApp *app, Canvas *const canvas, RawSamplesBuffer *bu uint32_t start_idx = idx; bool level = 0; uint32_t dur = 0, sample_num = 0; - for (int row = 0; row < rows ; row++) { - for (int x = 0; x < 128; x++) { - int y = 3 + row*8; - if (dur < time_per_pixel/2) { + for(int row = 0; row < rows; row++) { + for(int x = 0; x < 128; x++) { + int y = 3 + row * 8; + if(dur < time_per_pixel / 2) { /* Get more data. */ raw_samples_get(buf, idx++, &level, &dur); sample_num++; } - canvas_draw_line(canvas, x,y,x,y-(level*3)); + canvas_draw_line(canvas, x, y, x, y - (level * 3)); /* Write a small triangle under the last sample detected. */ - if (app->signal_bestlen != 0 && - sample_num+start_idx == app->signal_bestlen+1) - { - canvas_draw_dot(canvas,x,y+2); - canvas_draw_dot(canvas,x-1,y+3); - canvas_draw_dot(canvas,x,y+3); - canvas_draw_dot(canvas,x+1,y+3); + if(app->signal_bestlen != 0 && sample_num + start_idx == app->signal_bestlen + 1) { + canvas_draw_dot(canvas, x, y + 2); + canvas_draw_dot(canvas, x - 1, y + 3); + canvas_draw_dot(canvas, x, y + 3); + canvas_draw_dot(canvas, x + 1, y + 3); sample_num++; /* Make sure we don't mark the next, too. */ } /* Remove from the current level duration the time we * just plot. */ - if (dur > time_per_pixel) + if(dur > time_per_pixel) dur -= time_per_pixel; else dur = 0; @@ -53,61 +51,63 @@ void render_signal(ProtoViewApp *app, Canvas *const canvas, RawSamplesBuffer *bu } /* Raw pulses rendering. This is our default view. */ -void render_view_raw_pulses(Canvas *const canvas, ProtoViewApp *app) { +void render_view_raw_pulses(Canvas* const canvas, ProtoViewApp* app) { /* Show signal. */ render_signal(app, canvas, DetectedSamples, app->signal_offset); /* Show signal information. */ char buf[64]; - snprintf(buf,sizeof(buf),"%luus", - (unsigned long)DetectedSamples->short_pulse_dur); + snprintf(buf, sizeof(buf), "%luus", (unsigned long)DetectedSamples->short_pulse_dur); canvas_set_font(canvas, FontSecondary); canvas_draw_str_with_border(canvas, 97, 63, buf, ColorWhite, ColorBlack); - if (app->signal_decoded) { + if(app->signal_decoded) { canvas_set_font(canvas, FontPrimary); - canvas_draw_str_with_border(canvas, 1, 61, app->msg_info->decoder->name, ColorWhite, ColorBlack); + canvas_draw_str_with_border( + canvas, 1, 61, app->msg_info->decoder->name, ColorWhite, ColorBlack); } } /* Handle input for the raw pulses view. */ -void process_input_raw_pulses(ProtoViewApp *app, InputEvent input) { - if (input.type == InputTypeRepeat) { +void process_input_raw_pulses(ProtoViewApp* app, InputEvent input) { + if(input.type == InputTypeRepeat) { /* Handle panning of the signal window. Long pressing * right will show successive samples, long pressing left * previous samples. */ - if (input.key == InputKeyRight) app->signal_offset++; - else if (input.key == InputKeyLeft) app->signal_offset--; - } else if (input.type == InputTypeLong) { - if (input.key == InputKeyOk) { + if(input.key == InputKeyRight) + app->signal_offset++; + else if(input.key == InputKeyLeft) + app->signal_offset--; + } else if(input.type == InputTypeLong) { + if(input.key == InputKeyOk) { /* Reset the current sample to capture the next. */ reset_current_signal(app); } - } else if (input.type == InputTypeShort) { - if (input.key == InputKeyOk) { + } else if(input.type == InputTypeShort) { + if(input.key == InputKeyOk) { app->signal_offset = 0; - adjust_raw_view_scale(app,DetectedSamples->short_pulse_dur); - } else if (input.key == InputKeyDown) { + adjust_raw_view_scale(app, DetectedSamples->short_pulse_dur); + } else if(input.key == InputKeyDown) { /* Rescaling. The set becomes finer under 50us per pixel. */ uint32_t scale_step = app->us_scale >= 50 ? 50 : 10; - if (app->us_scale < 500) app->us_scale += scale_step; - } else if (input.key == InputKeyUp) { + if(app->us_scale < 500) app->us_scale += scale_step; + } else if(input.key == InputKeyUp) { uint32_t scale_step = app->us_scale > 50 ? 50 : 10; - if (app->us_scale > 10) app->us_scale -= scale_step; + if(app->us_scale > 10) app->us_scale -= scale_step; } } } /* Adjust raw view scale depending on short pulse duration. */ -void adjust_raw_view_scale(ProtoViewApp *app, uint32_t short_pulse_dur) { - if (short_pulse_dur == 0) +void adjust_raw_view_scale(ProtoViewApp* app, uint32_t short_pulse_dur) { + if(short_pulse_dur == 0) app->us_scale = PROTOVIEW_RAW_VIEW_DEFAULT_SCALE; - else if (short_pulse_dur < 75) + else if(short_pulse_dur < 75) app->us_scale = 10; - else if (short_pulse_dur < 145) + else if(short_pulse_dur < 145) app->us_scale = 30; - else if (short_pulse_dur < 400) + else if(short_pulse_dur < 400) app->us_scale = 100; - else if (short_pulse_dur < 1000) + else if(short_pulse_dur < 1000) app->us_scale = 200; else app->us_scale = PROTOVIEW_RAW_VIEW_DEFAULT_SCALE; diff --git a/applications/plugins/protoview/view_settings.c b/applications/plugins/protoview/view_settings.c index 1e2dce226..94d80cfb5 100644 --- a/applications/plugins/protoview/view_settings.c +++ b/applications/plugins/protoview/view_settings.c @@ -6,30 +6,30 @@ /* Renders a single view with frequency and modulation setting. However * this are logically two different views, and only one of the settings * will be highlighted. */ -void render_view_settings(Canvas *const canvas, ProtoViewApp *app) { +void render_view_settings(Canvas* const canvas, ProtoViewApp* app) { canvas_set_font(canvas, FontPrimary); - if (app->current_view == ViewFrequencySettings) - canvas_draw_str_with_border(canvas,1,10,"Frequency",ColorWhite,ColorBlack); + if(app->current_view == ViewFrequencySettings) + canvas_draw_str_with_border(canvas, 1, 10, "Frequency", ColorWhite, ColorBlack); else - canvas_draw_str(canvas,1,10,"Frequency"); + canvas_draw_str(canvas, 1, 10, "Frequency"); - if (app->current_view == ViewModulationSettings) - canvas_draw_str_with_border(canvas,70,10,"Modulation",ColorWhite,ColorBlack); + if(app->current_view == ViewModulationSettings) + canvas_draw_str_with_border(canvas, 70, 10, "Modulation", ColorWhite, ColorBlack); else - canvas_draw_str(canvas,70,10,"Modulation"); + canvas_draw_str(canvas, 70, 10, "Modulation"); canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas,10,61,"Use up and down to modify"); + canvas_draw_str(canvas, 10, 61, "Use up and down to modify"); - if (app->txrx->debug_timer_sampling) - canvas_draw_str(canvas,3,52,"(DEBUG timer sampling is ON)"); + if(app->txrx->debug_timer_sampling) + canvas_draw_str(canvas, 3, 52, "(DEBUG timer sampling is ON)"); /* Show frequency. We can use big numbers font since it's just a number. */ - if (app->current_view == ViewFrequencySettings) { + if(app->current_view == ViewFrequencySettings) { char buf[16]; - snprintf(buf,sizeof(buf),"%.2f",(double)app->frequency/1000000); + snprintf(buf, sizeof(buf), "%.2f", (double)app->frequency / 1000000); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str(canvas, 30, 40, buf); - } else if (app->current_view == ViewModulationSettings) { + } else if(app->current_view == ViewModulationSettings) { int current = app->modulation; canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 33, 39, ProtoViewModulations[current].name); @@ -37,13 +37,13 @@ void render_view_settings(Canvas *const canvas, ProtoViewApp *app) { } /* Handle input for the settings view. */ -void process_input_settings(ProtoViewApp *app, InputEvent input) { - if (input.type == InputTypeLong && input.key == InputKeyOk) { +void process_input_settings(ProtoViewApp* app, InputEvent input) { + if(input.type == InputTypeLong && input.key == InputKeyOk) { /* Long pressing to OK sets the default frequency and * modulation. */ app->frequency = subghz_setting_get_default_frequency(app->setting); app->modulation = 0; - } else if (0 && input.type == InputTypeLong && input.key == InputKeyDown) { + } else if(0 && input.type == InputTypeLong && input.key == InputKeyDown) { /* Long pressing to down switches between normal and debug * timer sampling mode. NOTE: this feature is disabled for users, * only useful for devs (if useful at all). */ @@ -55,42 +55,40 @@ void process_input_settings(ProtoViewApp *app, InputEvent input) { app->txrx->debug_timer_sampling = !app->txrx->debug_timer_sampling; radio_begin(app); radio_rx(app); - } else if (input.type == InputTypePress && - (input.key != InputKeyDown || input.key != InputKeyUp)) - { + } else if(input.type == InputTypePress && (input.key != InputKeyDown || input.key != InputKeyUp)) { /* Handle up and down to change frequency or modulation. */ - if (app->current_view == ViewFrequencySettings) { + if(app->current_view == ViewFrequencySettings) { size_t curidx = 0, i; size_t count = subghz_setting_get_frequency_count(app->setting); /* Scan the list of frequencies to check for the index of the * currently set frequency. */ for(i = 0; i < count; i++) { - uint32_t freq = subghz_setting_get_frequency(app->setting,i); - if (freq == app->frequency) { + uint32_t freq = subghz_setting_get_frequency(app->setting, i); + if(freq == app->frequency) { curidx = i; break; } } - if (i == count) return; /* Should never happen. */ + if(i == count) return; /* Should never happen. */ - if (input.key == InputKeyUp) { - curidx = curidx == 0 ? count-1 : curidx-1; - } else if (input.key == InputKeyDown) { - curidx = (curidx+1) % count; + if(input.key == InputKeyUp) { + curidx = curidx == 0 ? count - 1 : curidx - 1; + } else if(input.key == InputKeyDown) { + curidx = (curidx + 1) % count; } else { return; } - app->frequency = subghz_setting_get_frequency(app->setting,curidx); - } else if (app->current_view == ViewModulationSettings) { + app->frequency = subghz_setting_get_frequency(app->setting, curidx); + } else if(app->current_view == ViewModulationSettings) { uint32_t count = 0; uint32_t modid = app->modulation; while(ProtoViewModulations[count].name != NULL) count++; - if (input.key == InputKeyUp) { - modid = modid == 0 ? count-1 : modid-1; - } else if (input.key == InputKeyDown) { - modid = (modid+1) % count; + if(input.key == InputKeyUp) { + modid = modid == 0 ? count - 1 : modid - 1; + } else if(input.key == InputKeyDown) { + modid = (modid + 1) % (count ? count : 1); } else { return; } @@ -106,9 +104,13 @@ void process_input_settings(ProtoViewApp *app, InputEvent input) { /* When the user switches to some other view, if they changed the parameters * we need to restart the radio with the right frequency and modulation. */ -void view_exit_settings(ProtoViewApp *app) { - if (app->txrx->freq_mod_changed) { - FURI_LOG_E(TAG, "Setting view, setting frequency/modulation to %lu %s", app->frequency, ProtoViewModulations[app->modulation].name); +void view_exit_settings(ProtoViewApp* app) { + if(app->txrx->freq_mod_changed) { + FURI_LOG_E( + TAG, + "Setting view, setting frequency/modulation to %lu %s", + app->frequency, + ProtoViewModulations[app->modulation].name); radio_rx_end(app); radio_begin(app); radio_rx(app); diff --git a/applications/plugins/qrcode/application.fam b/applications/plugins/qrcode/application.fam index 6de585837..68a378fa4 100644 --- a/applications/plugins/qrcode/application.fam +++ b/applications/plugins/qrcode/application.fam @@ -1,7 +1,7 @@ App( appid="QRCode", name="QR Code", - fap_version=(1,0), + fap_version=(1, 0), fap_description="Display qrcodes", fap_author="Bob Matcuk", fap_weburl="https://github.com/bmatcuk/flipperzero-qrcode", @@ -17,4 +17,4 @@ App( fap_icon="icons/qrcode_10px.png", fap_icon_assets="icons", fap_icon_assets_symbol="qrcode", -) \ No newline at end of file +) diff --git a/applications/plugins/scrambler/LICENSE b/applications/plugins/scrambler/LICENSE new file mode 100644 index 000000000..4a6de25cb --- /dev/null +++ b/applications/plugins/scrambler/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 RaZe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/applications/plugins/scrambler/README.md b/applications/plugins/scrambler/README.md new file mode 100644 index 000000000..7e4700bcd --- /dev/null +++ b/applications/plugins/scrambler/README.md @@ -0,0 +1,16 @@ +# Setting up the Rubik's Cube Scrambler + +## Installation +To install the Rubik's Cube Scrambler, simply add the `rubiks_cube_scrambler` folder to your `application_users` folder. + +## Cleaning the code and removing old files +Run `./fbt -c fap_rubiks_cube_scrambler` to clean the code and remove any old binaries or compilation artifacts. + +## Compiling the FAP +To compile the FAP, run `./fbt fap_rubiks_cube_scrambler`. + +## Launching the app +To run the Rubik's Cube Scrambler directly from the Flip.x0, use `./fbt launch_app APPSRC=rubiks_cube_scrambler`. + +# A special thanks to Tanish for their c scrambler example 🙏 +https://github.com/TanishBhongade/RubiksCubeScrambler-C/ diff --git a/applications/plugins/scrambler/application.fam b/applications/plugins/scrambler/application.fam new file mode 100644 index 000000000..4d48d7bb5 --- /dev/null +++ b/applications/plugins/scrambler/application.fam @@ -0,0 +1,20 @@ +# COMPILE ISTRUCTIONS: + +# Clean the code and remove old binaries/compilation artefact +# ./fbt -c fap_rubiks_cube_scrambler + +# Compile FAP +# ./fbt fap_rubiks_cube_scrambler + +# Run application directly inside the Flip.x0 +# ./fbt launch_app APPSRC=rubiks_cube_scrambler + +App( + appid="Rubiks_Cube_Scrambler", + name="Rubik's Cube Scrambler", + apptype=FlipperAppType.EXTERNAL, + entry_point="rubiks_cube_scrambler_main", + stack_size=1 * 1024, + fap_category="Misc", + fap_icon="cube.png", +) diff --git a/applications/plugins/scrambler/assets/1.png b/applications/plugins/scrambler/assets/1.png new file mode 100644 index 000000000..d2099ea34 Binary files /dev/null and b/applications/plugins/scrambler/assets/1.png differ diff --git a/applications/plugins/scrambler/cube.png b/applications/plugins/scrambler/cube.png new file mode 100644 index 000000000..3178a29d6 Binary files /dev/null and b/applications/plugins/scrambler/cube.png differ diff --git a/applications/plugins/scrambler/rubiks_cube_scrambler.c b/applications/plugins/scrambler/rubiks_cube_scrambler.c new file mode 100644 index 000000000..4c845b883 --- /dev/null +++ b/applications/plugins/scrambler/rubiks_cube_scrambler.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include + +#include "scrambler.h" +#include "furi_hal_random.h" + +int scrambleStarted = 0; +char scramble_str[100] = {0}; +char scramble_start[100] = {0}; +char scramble_end[100] = {0}; +int notifications_enabled = 0; + +static void success_vibration() { + furi_hal_vibro_on(false); + furi_hal_vibro_on(true); + furi_delay_ms(50); + furi_hal_vibro_on(false); + return; +} +void split_array(char original[], int size, char first[], char second[]) { + int mid = size / 2; + if(size % 2 != 0) { + mid++; + } + int first_index = 0, second_index = 0; + for(int i = 0; i < size; i++) { + if(i < mid) { + first[first_index++] = original[i]; + } else { + if(i == mid && (original[i] == '2' || original[i] == '\'')) { + continue; + } + second[second_index++] = original[i]; + } + } + first[first_index] = '\0'; + second[second_index] = '\0'; +} + +static void draw_callback(Canvas* canvas, void* ctx) { + UNUSED(ctx); + canvas_clear(canvas); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 4, 13, "Rubik's Cube Scrambler"); + + if(scrambleStarted) { + genScramble(); + scrambleReplace(); + strcpy(scramble_str, printData()); + if(notifications_enabled) { + success_vibration(); + } + split_array(scramble_str, strlen(scramble_str), scramble_start, scramble_end); + scrambleStarted = 0; + } + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 64, 28, AlignCenter, AlignCenter, scramble_start); + canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignCenter, scramble_end); + elements_button_center(canvas, "New"); + + elements_button_left(canvas, notifications_enabled ? "On" : "Off"); +}; + +static void input_callback(InputEvent* input_event, void* ctx) { + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; + furi_message_queue_put(event_queue, input_event, FuriWaitForever); +} + +int32_t rubiks_cube_scrambler_main(void* p) { + UNUSED(p); + InputEvent event; + + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); + + ViewPort* view_port = view_port_alloc(); + + view_port_draw_callback_set(view_port, draw_callback, NULL); + + view_port_input_callback_set(view_port, input_callback, event_queue); + + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + while(true) { + furi_check(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk); + + if(event.key == InputKeyOk && event.type == InputTypeShort) { + scrambleStarted = 1; + } + if(event.key == InputKeyLeft && event.type == InputTypeShort) { + if(notifications_enabled) { + notifications_enabled = 0; + } else { + notifications_enabled = 1; + success_vibration(); + } + } + if(event.key == InputKeyBack) { + break; + } + } + + furi_message_queue_free(event_queue); + + gui_remove_view_port(gui, view_port); + + view_port_free(view_port); + furi_record_close(RECORD_GUI); + return 0; +} diff --git a/applications/plugins/scrambler/scrambler.c b/applications/plugins/scrambler/scrambler.c new file mode 100644 index 000000000..ea5291940 --- /dev/null +++ b/applications/plugins/scrambler/scrambler.c @@ -0,0 +1,102 @@ +/* +Authors: Tanish Bhongade and RaZe +*/ + +#include +#include +#include +#include "furi_hal_random.h" +#include +#include +#include "scrambler.h" + +// 6 moves along with direction +char moves[6] = {'R', 'U', 'F', 'B', 'L', 'D'}; +char dir[4] = {' ', '\'', '2'}; +const int SLEN = 20; +#define RESULT_SIZE 100 +// Structure which holds main scramble +struct GetScramble { + char mainScramble[25][3]; +}; +struct GetScramble a; // Its object + +// Function prototypes to avoid bugs +void scrambleReplace(); +void genScramble(); +void valid(); +int getRand(int upr, int lwr); +char* printData(); +void writeToFile(); + +// Main function +/* int main(){ + genScramble ();//Calling genScramble + scrambleReplace();//Calling scrambleReplace + valid();//Calling valid to validate the scramble + printData ();//Printing the final scramble + //writeToFile();//If you want to write to a file, please uncomment this + + return 0; +} */ + +void genScramble() { + // Stage 1 + for(int i = 0; i < SLEN; i++) { + strcpy(a.mainScramble[i], "00"); + } + // This makes array like this 00 00 00....... +} + +void scrambleReplace() { + // Stage 2 + // Actual process begins here + + // Initialize the mainScramble array with all the possible moves + for(int i = 0; i < SLEN; i++) { + a.mainScramble[i][0] = moves[furi_hal_random_get() % 6]; + a.mainScramble[i][1] = dir[furi_hal_random_get() % 3]; + } + + // Perform the Fisher-Yates shuffle + for(int i = 6 - 1; i > 0; i--) { + int j = rand() % (i + 1); + char temp[3]; + strcpy(temp, a.mainScramble[i]); + strcpy(a.mainScramble[i], a.mainScramble[j]); + strcpy(a.mainScramble[j], temp); + } + + // Select the first 10 elements as the scramble, using only the first three elements of the dir array + for(int i = 0; i < SLEN; i++) { + a.mainScramble[i][1] = dir[furi_hal_random_get() % 3]; + } + for(int i = 1; i < SLEN; i++) { + while(a.mainScramble[i][0] == a.mainScramble[i - 2][0] || + a.mainScramble[i][0] == a.mainScramble[i - 1][0]) { + a.mainScramble[i][0] = moves[furi_hal_random_get() % 5]; + } + } +} + +// Let this function be here for now till I find out what is causing the extra space bug in the scrambles +void remove_double_spaces(char* str) { + int i, j; + int len = strlen(str); + for(i = 0, j = 0; i < len; i++, j++) { + if(str[i] == ' ' && str[i + 1] == ' ') { + i++; + } + str[j] = str[i]; + } + str[j] = '\0'; +} +char* printData() { + static char result[RESULT_SIZE]; + int offset = 0; + for(int loop = 0; loop < SLEN; loop++) { + offset += snprintf(result + offset, RESULT_SIZE - offset, "%s ", a.mainScramble[loop]); + } + remove_double_spaces(result); + return result; +} diff --git a/applications/plugins/scrambler/scrambler.h b/applications/plugins/scrambler/scrambler.h new file mode 100644 index 000000000..4b56c565d --- /dev/null +++ b/applications/plugins/scrambler/scrambler.h @@ -0,0 +1,3 @@ +void scrambleReplace(); +void genScramble(); +char* printData(); diff --git a/applications/plugins/signal_generator/signal_gen_app_i.h b/applications/plugins/signal_generator/signal_gen_app_i.h index 47c266475..60e4d7ed9 100644 --- a/applications/plugins/signal_generator/signal_gen_app_i.h +++ b/applications/plugins/signal_generator/signal_gen_app_i.h @@ -2,8 +2,8 @@ #include "scenes/signal_gen_scene.h" -#include "furi_hal_clock.h" -#include "furi_hal_pwm.h" +#include +#include #include #include diff --git a/applications/plugins/signal_generator/views/signal_gen_pwm.c b/applications/plugins/signal_generator/views/signal_gen_pwm.c index 6c6c19440..928be7916 100644 --- a/applications/plugins/signal_generator/views/signal_gen_pwm.c +++ b/applications/plugins/signal_generator/views/signal_gen_pwm.c @@ -1,5 +1,5 @@ #include "../signal_gen_app_i.h" -#include "furi_hal.h" +#include #include #include diff --git a/applications/plugins/solitaire/application.fam b/applications/plugins/solitaire/application.fam index 66e4567ec..4011c343e 100644 --- a/applications/plugins/solitaire/application.fam +++ b/applications/plugins/solitaire/application.fam @@ -4,10 +4,10 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="solitaire_app", cdefines=["APP_SOLITAIRE"], - requires=["gui","storage","canvas"], + requires=["gui", "storage", "canvas"], stack_size=2 * 1024, order=30, fap_icon="solitaire_10px.png", fap_category="Games", - fap_icon_assets="assets" -) \ No newline at end of file + fap_icon_assets="assets", +) diff --git a/applications/plugins/spi_mem_manager/application.fam b/applications/plugins/spi_mem_manager/application.fam new file mode 100644 index 000000000..09d801876 --- /dev/null +++ b/applications/plugins/spi_mem_manager/application.fam @@ -0,0 +1,17 @@ +App( + appid="spi_mem_manager", + name="SPI Mem Manager", + apptype=FlipperAppType.EXTERNAL, + entry_point="spi_mem_app", + requires=["gui"], + stack_size=1 * 2048, + order=30, + fap_icon="images/Dip8_10px.png", + fap_category="Tools", + fap_icon_assets="images", + fap_private_libs=[ + Lib( + name="spi", + ), + ], +) diff --git a/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_01.png b/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_01.png new file mode 100644 index 000000000..4ff2e3042 Binary files /dev/null and b/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_01.png differ diff --git a/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_02.png b/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_02.png new file mode 100644 index 000000000..8893a4881 Binary files /dev/null and b/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_02.png differ diff --git a/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_03.png b/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_03.png new file mode 100644 index 000000000..1342dc7bf Binary files /dev/null and b/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_03.png differ diff --git a/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_rate b/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_rate new file mode 100644 index 000000000..d8263ee98 --- /dev/null +++ b/applications/plugins/spi_mem_manager/images/ChipLooking_64x64/frame_rate @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/applications/plugins/spi_mem_manager/images/Dip8_10px.png b/applications/plugins/spi_mem_manager/images/Dip8_10px.png new file mode 100644 index 000000000..9de9364d1 Binary files /dev/null and b/applications/plugins/spi_mem_manager/images/Dip8_10px.png differ diff --git a/applications/plugins/spi_mem_manager/images/Dip8_32x36.png b/applications/plugins/spi_mem_manager/images/Dip8_32x36.png new file mode 100644 index 000000000..8f01af276 Binary files /dev/null and b/applications/plugins/spi_mem_manager/images/Dip8_32x36.png differ diff --git a/assets/icons/iButton/DolphinMafia_115x62_sfw.png b/applications/plugins/spi_mem_manager/images/DolphinMafia_115x62.png similarity index 100% rename from assets/icons/iButton/DolphinMafia_115x62_sfw.png rename to applications/plugins/spi_mem_manager/images/DolphinMafia_115x62.png diff --git a/assets/icons/iButton/DolphinNice_96x59_sfw.png b/applications/plugins/spi_mem_manager/images/DolphinNice_96x59.png similarity index 100% rename from assets/icons/iButton/DolphinNice_96x59_sfw.png rename to applications/plugins/spi_mem_manager/images/DolphinNice_96x59.png diff --git a/applications/plugins/spi_mem_manager/images/SDQuestion_35x43.png b/applications/plugins/spi_mem_manager/images/SDQuestion_35x43.png new file mode 100644 index 000000000..9b9c9a58e Binary files /dev/null and b/applications/plugins/spi_mem_manager/images/SDQuestion_35x43.png differ diff --git a/assets/icons/StatusBar/Alert_9x8.png b/applications/plugins/spi_mem_manager/images/Wiring_SPI_128x64.png similarity index 64% rename from assets/icons/StatusBar/Alert_9x8.png rename to applications/plugins/spi_mem_manager/images/Wiring_SPI_128x64.png index d03f107ef..e6c3ce363 100644 Binary files a/assets/icons/StatusBar/Alert_9x8.png and b/applications/plugins/spi_mem_manager/images/Wiring_SPI_128x64.png differ diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip.c b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip.c new file mode 100644 index 000000000..f7f98dce2 --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip.c @@ -0,0 +1,105 @@ +#include "spi_mem_chip_i.h" + +const SPIMemChipVendorName spi_mem_chip_vendor_names[] = { + {"Adesto", SPIMemChipVendorADESTO}, + {"AMIC", SPIMemChipVendorAMIC}, + {"Boya", SPIMemChipVendorBoya}, + {"EON", SPIMemChipVendorEON}, + {"PFlash", SPIMemChipVendorPFLASH}, + {"Terra", SPIMemChipVendorTERRA}, + {"Generalplus", SPIMemChipVendorGeneralplus}, + {"Deutron", SPIMemChipVendorDEUTRON}, + {"EFST", SPIMemChipVendorEFST}, + {"Excel Semi.", SPIMemChipVendorEXCELSEMI}, + {"Fidelix", SPIMemChipVendorFIDELIX}, + {"GigaDevice", SPIMemChipVendorGIGADEVICE}, + {"ICE", SPIMemChipVendorICE}, + {"Intel", SPIMemChipVendorINTEL}, + {"KHIC", SPIMemChipVendorKHIC}, + {"Macronix", SPIMemChipVendorMACRONIX}, + {"Micron", SPIMemChipVendorMICRON}, + {"Mshine", SPIMemChipVendorMSHINE}, + {"Nantronics", SPIMemChipVendorNANTRONICS}, + {"Nexflash", SPIMemChipVendorNEXFLASH}, + {"Numonyx", SPIMemChipVendorNUMONYX}, + {"PCT", SPIMemChipVendorPCT}, + {"Spansion", SPIMemChipVendorSPANSION}, + {"SST", SPIMemChipVendorSST}, + {"ST", SPIMemChipVendorST}, + {"Winbond", SPIMemChipVendorWINBOND}, + {"Zempro", SPIMemChipVendorZEMPRO}, + {"Zbit", SPIMemChipVendorZbit}, + {"Berg Micro.", SPIMemChipVendorBerg_Micro}, + {"Atmel", SPIMemChipVendorATMEL}, + {"ACE", SPIMemChipVendorACE}, + {"ATO", SPIMemChipVendorATO}, + {"Douqi", SPIMemChipVendorDOUQI}, + {"Fremont", SPIMemChipVendorFremont}, + {"Fudan", SPIMemChipVendorFudan}, + {"Genitop", SPIMemChipVendorGenitop}, + {"Paragon", SPIMemChipVendorParagon}, + {"Unknown", SPIMemChipVendorUnknown}}; + +static const char* spi_mem_chip_search_vendor_name(SPIMemChipVendor vendor_enum) { + const SPIMemChipVendorName* vendor = spi_mem_chip_vendor_names; + while(vendor->vendor_enum != SPIMemChipVendorUnknown && vendor->vendor_enum != vendor_enum) + vendor++; + return vendor->vendor_name; +} + +bool spi_mem_chip_find_all(SPIMemChip* chip_info, found_chips_t found_chips) { + const SPIMemChip* chip_info_arr; + found_chips_reset(found_chips); + for(chip_info_arr = SPIMemChips; chip_info_arr->model_name != NULL; chip_info_arr++) { + if(chip_info->vendor_id != chip_info_arr->vendor_id) continue; + if(chip_info->type_id != chip_info_arr->type_id) continue; + if(chip_info->capacity_id != chip_info_arr->capacity_id) continue; + found_chips_push_back(found_chips, chip_info_arr); + } + if(found_chips_size(found_chips)) return true; + return false; +} + +void spi_mem_chip_copy_chip_info(SPIMemChip* dest, const SPIMemChip* src) { + memcpy(dest, src, sizeof(SPIMemChip)); +} + +size_t spi_mem_chip_get_size(SPIMemChip* chip) { + return (chip->size); +} + +const char* spi_mem_chip_get_vendor_name(const SPIMemChip* chip) { + return (spi_mem_chip_search_vendor_name(chip->vendor_enum)); +} + +const char* spi_mem_chip_get_vendor_name_by_enum(uint32_t vendor_enum) { + return (spi_mem_chip_search_vendor_name(vendor_enum)); +} + +const char* spi_mem_chip_get_model_name(const SPIMemChip* chip) { + return (chip->model_name); +} + +uint8_t spi_mem_chip_get_vendor_id(SPIMemChip* chip) { + return (chip->vendor_id); +} + +uint8_t spi_mem_chip_get_type_id(SPIMemChip* chip) { + return (chip->type_id); +} + +uint8_t spi_mem_chip_get_capacity_id(SPIMemChip* chip) { + return (chip->capacity_id); +} + +SPIMemChipWriteMode spi_mem_chip_get_write_mode(SPIMemChip* chip) { + return (chip->write_mode); +} + +size_t spi_mem_chip_get_page_size(SPIMemChip* chip) { + return (chip->page_size); +} + +uint32_t spi_mem_chip_get_vendor_enum(const SPIMemChip* chip) { + return ((uint32_t)chip->vendor_enum); +} diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip.h b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip.h new file mode 100644 index 000000000..683937df4 --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +typedef struct SPIMemChip SPIMemChip; + +ARRAY_DEF(found_chips, const SPIMemChip*, M_POD_OPLIST) + +typedef enum { + SPIMemChipStatusBusy, + SPIMemChipStatusIdle, + SPIMemChipStatusError +} SPIMemChipStatus; + +typedef enum { + SPIMemChipWriteModeUnknown = 0, + SPIMemChipWriteModePage = (0x01 << 0), + SPIMemChipWriteModeAAIByte = (0x01 << 1), + SPIMemChipWriteModeAAIWord = (0x01 << 2), +} SPIMemChipWriteMode; + +const char* spi_mem_chip_get_vendor_name(const SPIMemChip* chip); +const char* spi_mem_chip_get_model_name(const SPIMemChip* chip); +size_t spi_mem_chip_get_size(SPIMemChip* chip); +uint8_t spi_mem_chip_get_vendor_id(SPIMemChip* chip); +uint8_t spi_mem_chip_get_type_id(SPIMemChip* chip); +uint8_t spi_mem_chip_get_capacity_id(SPIMemChip* chip); +SPIMemChipWriteMode spi_mem_chip_get_write_mode(SPIMemChip* chip); +size_t spi_mem_chip_get_page_size(SPIMemChip* chip); +bool spi_mem_chip_find_all(SPIMemChip* chip_info, found_chips_t found_chips); +void spi_mem_chip_copy_chip_info(SPIMemChip* dest, const SPIMemChip* src); +uint32_t spi_mem_chip_get_vendor_enum(const SPIMemChip* chip); +const char* spi_mem_chip_get_vendor_name_by_enum(uint32_t vendor_enum); diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip_arr.c b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip_arr.c new file mode 100644 index 000000000..25b237d68 --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip_arr.c @@ -0,0 +1,1399 @@ +#include "spi_mem_chip_i.h" +const SPIMemChip SPIMemChips[] = { + {0x1F, 0x40, 0x00, "AT25DN256", 32768, 256, SPIMemChipVendorADESTO, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x20, "A25L05PT", 65536, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x10, "A25L05PU", 65536, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x21, "A25L10PT", 131072, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x11, "A25L10PU", 131072, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x22, "A25L20PT", 262144, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x12, "A25L20PU", 262144, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x23, "A25L40PT", 524288, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x13, "A25L40PU", 524288, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x24, "A25L80PT", 1048576, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x14, "A25L80PU", 1048576, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x25, "A25L16PT", 2097152, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x15, "A25L16PU", 2097152, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x10, "A25L512", 65536, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x11, "A25L010", 131072, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x12, "A25L020", 262144, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x13, "A25L040", 524288, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x14, "A25L080", 1048576, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x15, "A25L016", 2097152, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x16, "A25L032", 4194304, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x40, 0x15, "A25LQ16", 2097152, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x37, 0x40, 0x16, "A25LQ32A", 4194304, 256, SPIMemChipVendorAMIC, SPIMemChipWriteModePage}, + {0x68, 0x40, 0x14, "BY25D80", 1048576, 256, SPIMemChipVendorBoya, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x10, "EN25B05", 65536, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x10, "EN25B05T", 65536, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x11, "EN25B10", 131072, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x11, "EN25B10T", 131072, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x12, "EN25B20", 262144, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x12, "EN25B20T", 262144, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x13, "EN25B40", 524288, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x13, "EN25B40T", 524288, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x14, "EN25B80", 1048576, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x14, "EN25B80T", 1048576, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x15, "EN25B16", 2097152, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x15, "EN25B16T", 2097152, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x16, "EN25B32", 4194304, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x16, "EN25B32T", 4194304, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x17, "EN25B64", 8388608, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x17, "EN25B64T", 8388608, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x10, "EN25F05", 65536, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x11, "EN25F10", 131072, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x12, "EN25F20", 262144, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x13, "EN25F40", 524288, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x14, "EN25F80", 1048576, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x15, "EN25F16", 2097152, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x16, "EN25F32", 4194304, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x10, "EN25LF05", 65536, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x11, "EN25LF10", 131072, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x12, "EN25LF20", 262144, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x13, "EN25LF40", 524288, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x10, "EN25P05", 65536, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x11, "EN25P10", 131072, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x12, "EN25P20", 262144, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x13, "EN25P40", 524288, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x14, "EN25P80", 1048576, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x15, "EN25P16", 2097152, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x16, "EN25P32", 4194304, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x17, "EN25P64", 8388608, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x30, 0x13, "EN25Q40", 524288, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x30, 0x14, "EN25Q80A", 1048576, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x30, 0x15, "EN25Q16A", 2097152, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x30, 0x16, "EN25Q32A", 4194304, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x70, 0x16, "EN25Q32A", 4194304, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x30, 0x16, "EN25Q32B", 4194304, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x30, 0x17, "EN25Q64", 8388608, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x30, 0x18, "EN25Q128", 16777216, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x70, 0x15, "EN25QH16", 2097152, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x70, 0x16, "EN25QH32", 4194304, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x70, 0x17, "EN25QH64", 8388608, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x70, 0x18, "EN25QH128", 16777216, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x70, 0x19, "EN25QH256", 33554432, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x51, 0x14, "EN25T80", 1048576, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x51, 0x15, "EN25T16", 2097152, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x1C, 0x31, 0x17, "EN25F64", 8388608, 256, SPIMemChipVendorEON, SPIMemChipWriteModePage}, + {0x7F, 0x9D, 0x7C, "Pm25LV010", 131072, 256, SPIMemChipVendorPFLASH, SPIMemChipWriteModePage}, + {0x7F, 0x9D, 0x21, "Pm25LD010", 131072, 256, SPIMemChipVendorPFLASH, SPIMemChipWriteModePage}, + {0x7F, 0x9D, 0x22, "Pm25LV020", 262144, 256, SPIMemChipVendorPFLASH, SPIMemChipWriteModePage}, + {0x7F, 0x9D, 0x7D, "Pm25W020", 262144, 256, SPIMemChipVendorPFLASH, SPIMemChipWriteModePage}, + {0x7F, 0x9D, 0x7E, "Pm25LV040", 524288, 256, SPIMemChipVendorPFLASH, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x10, "TS25L512A", 65536, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x11, "TS25L010A", 131072, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x12, "TS25L020A", 262144, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x15, "TS25L16AP", 2097152, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x15, "TS25L16BP", 2097152, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x15, "ZP25L16P", 2097152, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x20, 0x80, 0x15, "TS25L16PE", 2097152, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x20, 0x80, 0x14, "TS25L80PE", 1048576, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x16, "TS25L032A", 4194304, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x13, "TS25L40P", 524288, 256, SPIMemChipVendorTERRA, SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x10, + "GPR25L005E", + 65536, + 256, + SPIMemChipVendorGeneralplus, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x15, + "GPR25L161B", + 262144, + 256, + SPIMemChipVendorGeneralplus, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x12, + "GPR25L020B", + 262144, + 256, + SPIMemChipVendorGeneralplus, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "GPR25L3203F", + 4194304, + 256, + SPIMemChipVendorGeneralplus, + SPIMemChipWriteModePage}, + {0x9D, 0x7B, 0x00, "AC25LV512", 65536, 256, SPIMemChipVendorDEUTRON, SPIMemChipWriteModePage}, + {0x9D, 0x7C, 0x00, "AC25LV010", 131072, 256, SPIMemChipVendorDEUTRON, SPIMemChipWriteModePage}, + {0x9D, 0x7B, 0x00, "EM25LV512", 65536, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x9D, 0x7C, 0x00, "EM25LV010", 131072, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x20, 0x13, "F25L004A", 524288, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x20, 0x14, "F25L008A", 1048576, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x20, 0x15, "F25L016A", 2097152, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x8C, 0x8C, "F25L04UA", 524288, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x20, 0x13, "F25L04P", 524288, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x30, 0x13, "F25S04P", 524288, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x20, 0x14, "F25L08P", 1048576, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x20, 0x15, "F25L16P", 2097152, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x20, 0x16, "F25L32P", 4194304, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x8C, 0x40, 0x16, "F25L32Q", 4194304, 256, SPIMemChipVendorEFST, SPIMemChipWriteModePage}, + {0x4A, 0x20, 0x11, "ES25P10", 131072, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0x4A, 0x20, 0x12, "ES25P20", 262144, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0x4A, 0x20, 0x13, "ES25P40", 524288, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0x4A, 0x20, 0x14, "ES25P80", 1048576, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0x4A, 0x20, 0x15, "ES25P16", 2097152, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0x4A, 0x20, 0x16, "ES25P32", 4194304, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0x4A, 0x32, 0x13, "ES25M40A", 524288, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0x4A, 0x32, 0x14, "ES25M80A", 1048576, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0x4A, 0x32, 0x15, "ES25M16A", 2097152, 256, SPIMemChipVendorEXCELSEMI, SPIMemChipWriteModePage}, + {0xF8, 0x32, 0x14, "FM25Q08A", 1048576, 256, SPIMemChipVendorFIDELIX, SPIMemChipWriteModePage}, + {0xF8, 0x32, 0x15, "FM25Q16A", 2097152, 256, SPIMemChipVendorFIDELIX, SPIMemChipWriteModePage}, + {0xF8, 0x32, 0x15, "FM25Q16B", 2097152, 256, SPIMemChipVendorFIDELIX, SPIMemChipWriteModePage}, + {0xF8, 0x32, 0x16, "FM25Q32A", 4194304, 256, SPIMemChipVendorFIDELIX, SPIMemChipWriteModePage}, + {0xF8, 0x32, 0x17, "FM25Q64A", 8388608, 256, SPIMemChipVendorFIDELIX, SPIMemChipWriteModePage}, + {0xC8, 0x30, 0x13, "GD25D40", 524288, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, 0x30, 0x14, "GD25D80", 1048576, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, 0x20, 0x13, "GD25F40", 524288, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, 0x20, 0x14, "GD25F80", 1048576, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, 0x40, 0x10, "GD25Q512", 65536, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, 0x40, 0x11, "GD25Q10", 131072, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, 0x40, 0x12, "GD25Q20", 262144, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, + 0x60, + 0x12, + "GD25LQ20C_1.8V", + 262144, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, 0x40, 0x13, "GD25Q40", 524288, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, 0x40, 0x14, "GD25Q80", 1048576, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, + 0x40, + 0x14, + "GD25Q80B", + 1048576, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, + 0x40, + 0x14, + "GD25Q80C", + 1048576, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, 0x40, 0x15, "GD25Q16", 2097152, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, + 0x40, + 0x15, + "GD25Q16B", + 2097152, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, 0x40, 0x16, "GD25Q32", 4194304, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, + 0x40, + 0x16, + "GD25Q32B", + 4194304, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, 0x40, 0x17, "GD25Q64", 8388608, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0xC8, + 0x40, + 0x17, + "GD25Q64B", + 8388608, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, + 0x40, + 0x17, + "GD25B64C", + 8388608, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, + 0x40, + 0x18, + "GD25Q128B", + 16777216, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, + 0x40, + 0x18, + "GD25Q128C", + 16777216, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, + 0x60, + 0x17, + "GD25LQ064C_1.8V", + 8388608, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, + 0x60, + 0x18, + "GD25LQ128C_1.8V", + 16777216, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, + 0x60, + 0x19, + "GD25LQ256C_1.8V", + 33554432, + 256, + SPIMemChipVendorGIGADEVICE, + SPIMemChipWriteModePage}, + {0xC8, 0x31, 0x14, "MD25T80", 1048576, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0x51, 0x40, 0x12, "MD25D20", 262144, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0x51, 0x40, 0x13, "MD25D40", 524288, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0x51, 0x40, 0x14, "MD25D80", 1048576, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0x51, 0x40, 0x15, "MD25D16", 2097152, 256, SPIMemChipVendorGIGADEVICE, SPIMemChipWriteModePage}, + {0x1C, 0x20, 0x10, "ICE25P05", 65536, 128, SPIMemChipVendorICE, SPIMemChipWriteModePage}, + {0x89, 0x89, 0x11, "QB25F016S33B", 2097152, 256, SPIMemChipVendorINTEL, SPIMemChipWriteModePage}, + {0x89, 0x89, 0x11, "QB25F160S33B", 2097152, 256, SPIMemChipVendorINTEL, SPIMemChipWriteModePage}, + {0x89, 0x89, 0x12, "QB25F320S33B", 4194304, 256, SPIMemChipVendorINTEL, SPIMemChipWriteModePage}, + {0x89, 0x89, 0x13, "QB25F640S33B", 8388608, 256, SPIMemChipVendorINTEL, SPIMemChipWriteModePage}, + {0x89, 0x89, 0x11, "QH25F016S33B", 2097152, 256, SPIMemChipVendorINTEL, SPIMemChipWriteModePage}, + {0x89, 0x89, 0x11, "QH25F160S33B", 2097152, 256, SPIMemChipVendorINTEL, SPIMemChipWriteModePage}, + {0x89, 0x89, 0x12, "QH25F320S33B", 4194304, 256, SPIMemChipVendorINTEL, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "KH25L1005", 131072, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "KH25L1005A", 131072, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x12, "KH25L2005", 262144, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "KH25L4005", 524288, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "KH25L4005A", 524288, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x10, "KH25L512", 65536, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x10, "KH25L512A", 65536, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x14, "KH25L8005", 1048576, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x26, 0x15, "KH25L8036D", 1048576, 256, SPIMemChipVendorKHIC, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "MX25L1005", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "MX25L1005A", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "MX25L1005C", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "MX25L1006E", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x22, 0x11, "MX25L1021E", 131072, 32, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "MX25L1025C", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "MX25L1026E", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12805D", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12835E", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12835F", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12836E", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12839F", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12845E", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12845G", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12845F", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12865E", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12865F", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12873F", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x18, + "MX25L12875F", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x19, + "MX25L25635E", + 33554432, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x15, "MX25L1605", 2097152, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x15, + "MX25L1605A", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x15, + "MX25L1605D", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x15, + "MX25L1606E", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x24, + 0x15, + "MX25L1633E", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x24, + 0x15, + "MX25L1635D", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x15, + "MX25L1635E", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x24, + 0x15, + "MX25L1636D", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x15, + "MX25L1636E", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x24, + 0x15, + "MX25L1673E", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x24, + 0x15, + "MX25L1675E", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x12, "MX25L2005", 262144, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x12, "MX25L2005C", 262144, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x12, "MX25L2006E", 262144, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x12, "MX25L2026C", 262144, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x12, "MX25L2026E", 262144, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x16, "MX25L3205", 4194304, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3205A", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3205D", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3206E", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3208E", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x5E, + 0x16, + "MX25L3225D", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3233F", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x5E, + 0x16, + "MX25L3235D", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3235E", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x5E, + 0x16, + "MX25L3236D", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x5E, + 0x16, + "MX25L3237D", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x36, + "MX25L3239E", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3273E", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3273F", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x16, + "MX25L3275E", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "MX25L4005", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "MX25L4005A", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "MX25L4005C", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "MX25L4006E", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "MX25L4026E", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x10, "MX25L512", 65536, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x10, "MX25L512A", 65536, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x10, "MX25L512C", 65536, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x22, 0x10, "MX25L5121E", 65536, 32, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x17, "MX25L6405", 8388608, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6405D", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6406E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6408E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6433F", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6435E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6436E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6436F", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x37, + "MX25L6439E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6445E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6465E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6473E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6473F", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x17, + "MX25L6475E", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x14, "MX25L8005", 1048576, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x14, + "MX25L8006E", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x14, + "MX25L8008E", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x14, + "MX25L8035E", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x14, + "MX25L8036E", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x14, + "MX25L8073E", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x14, + "MX25L8075E", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x19, + "MX25L25673G", + 33554432, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x28, 0x10, "MX25R512F", 65536, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x28, 0x11, "MX25R1035F", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x28, + 0x15, + "MX25R1635F", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x28, 0x12, "MX25R2035F", 262144, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x28, + 0x16, + "MX25R3235F", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x28, 0x13, "MX25R4035F", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x28, + 0x17, + "MX25R6435F", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x28, + 0x14, + "MX25R8035F", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x31, + "MX25U1001E_1.8V", + 131072, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x18, + "MX25U12835F_1.8V", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x39, + "MX25U25673G_1.8V", + 33554432, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x39, + "MX25U25645G_1.8V", + 33554432, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x35, + "MX25U1635E_1.8V", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x35, + "MX25U1635F_1.8V", + 2097152, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x32, + "MX25U2032E_1.8V", + 262144, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x32, + "MX25U2033E_1.8V", + 262144, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x36, + "MX25U3235E_1.8V", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x36, + "MX25U3235F_1.8V", + 4194304, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x33, + "MX25U4032E_1.8V", + 524288, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x33, + "MX25U4033E_1.8V", + 524288, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x33, + "MX25U4035_1.8V", + 524288, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x30, + "MX25U5121E_1.8V", + 65536, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x37, + "MX25U6435F_1.8V", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x37, + "MX25U6473F_1.8V", + 8388608, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x34, + "MX25U8032E_1.8V", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x34, + "MX25U8033E_1.8V", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x34, + "MX25U8035_1.8V", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x34, + "MX25U8035E_1.8V", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x38, + "MX25U12873F_1.8V", + 16777216, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x11, "MX25V1006E", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x23, 0x11, "MX25V1035F", 131072, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x12, "MX25V2006E", 262144, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x23, 0x12, "MX25V2035F", 262144, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x10, "MX25V512", 65536, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x10, "MX25V512C", 65536, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x10, "MX25V512E", 65536, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x23, 0x10, "MX25V512F", 65536, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "MX25V4005", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x13, "MX25V4006E", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x25, 0x53, "MX25V4035", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x23, 0x13, "MX25V4035F", 524288, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, 0x20, 0x14, "MX25V8005", 1048576, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x20, + 0x14, + "MX25V8006E", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, 0x25, 0x54, "MX25V8035", 1048576, 256, SPIMemChipVendorMACRONIX, SPIMemChipWriteModePage}, + {0xC2, + 0x23, + 0x14, + "MX25V8035F", + 1048576, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x3A, + "MX66U51235F_1.8V", + 67108864, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0xC2, + 0x25, + 0x3B, + "MX66U1G45G_1.8V", + 134217728, + 256, + SPIMemChipVendorMACRONIX, + SPIMemChipWriteModePage}, + {0x20, 0xBA, 0x16, "N25Q032A", 4194304, 256, SPIMemChipVendorMICRON, SPIMemChipWriteModePage}, + {0x20, 0xBA, 0x17, "N25Q064A", 8388608, 256, SPIMemChipVendorMICRON, SPIMemChipWriteModePage}, + {0x20, 0xBA, 0x19, "N25Q256A13", 33554432, 256, SPIMemChipVendorMICRON, SPIMemChipWriteModePage}, + {0x20, 0xBA, 0x20, "N25Q512A83", 67108864, 256, SPIMemChipVendorMICRON, SPIMemChipWriteModePage}, + {0x2C, 0xCB, 0x19, "N25W256A11", 33554432, 256, SPIMemChipVendorMICRON, SPIMemChipWriteModePage}, + {0x20, + 0xBA, + 0x18, + "MT25QL128AB", + 16777216, + 256, + SPIMemChipVendorMICRON, + SPIMemChipWriteModePage}, + {0x20, 0xBA, 0x19, "MT25QL256A", 33554432, 256, SPIMemChipVendorMICRON, SPIMemChipWriteModePage}, + {0x20, 0xBA, 0x20, "MT25QL512A", 67108864, 256, SPIMemChipVendorMICRON, SPIMemChipWriteModePage}, + {0x20, + 0xBA, + 0x22, + "MT25QL02GC", + 268435456, + 256, + SPIMemChipVendorMICRON, + SPIMemChipWriteModePage}, + {0x20, 0xBB, 0x19, "MT25QU256", 33554432, 256, SPIMemChipVendorMICRON, SPIMemChipWriteModePage}, + {0x20, + 0xBA, + 0x21, + "N25Q00AA13G", + 134217728, + 256, + SPIMemChipVendorMICRON, + SPIMemChipWriteModePage}, + {0x37, 0x30, 0x10, "MS25X512", 65536, 256, SPIMemChipVendorMSHINE, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x11, "MS25X10", 131072, 256, SPIMemChipVendorMSHINE, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x12, "MS25X20", 262144, 256, SPIMemChipVendorMSHINE, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x13, "MS25X40", 524288, 256, SPIMemChipVendorMSHINE, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x14, "MS25X80", 1048576, 256, SPIMemChipVendorMSHINE, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x15, "MS25X16", 2097152, 256, SPIMemChipVendorMSHINE, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x16, "MS25X32", 4194304, 256, SPIMemChipVendorMSHINE, SPIMemChipWriteModePage}, + {0xD5, 0x30, 0x11, "N25S10", 131072, 256, SPIMemChipVendorNANTRONICS, SPIMemChipWriteModePage}, + {0xD5, 0x30, 0x12, "N25S20", 262144, 256, SPIMemChipVendorNANTRONICS, SPIMemChipWriteModePage}, + {0xD5, 0x30, 0x13, "N25S40", 524288, 256, SPIMemChipVendorNANTRONICS, SPIMemChipWriteModePage}, + {0xD5, 0x30, 0x15, "N25S16", 2097152, 256, SPIMemChipVendorNANTRONICS, SPIMemChipWriteModePage}, + {0xD5, 0x30, 0x16, "N25S32", 4194304, 256, SPIMemChipVendorNANTRONICS, SPIMemChipWriteModePage}, + {0xD5, 0x30, 0x14, "N25S80", 1048576, 256, SPIMemChipVendorNANTRONICS, SPIMemChipWriteModePage}, + {0x9D, 0x7F, 0x7C, "NX25P10", 131072, 256, SPIMemChipVendorNEXFLASH, SPIMemChipWriteModePage}, + {0xEF, 0x20, 0x15, "NX25P16", 2097152, 256, SPIMemChipVendorNEXFLASH, SPIMemChipWriteModePage}, + {0x9D, 0x7F, 0x7D, "NX25P20", 262144, 256, SPIMemChipVendorNEXFLASH, SPIMemChipWriteModePage}, + {0xEF, 0x20, 0x16, "NX25P32", 4194304, 256, SPIMemChipVendorNEXFLASH, SPIMemChipWriteModePage}, + {0x9D, 0x7F, 0x7E, "NX25P40", 524288, 256, SPIMemChipVendorNEXFLASH, SPIMemChipWriteModePage}, + {0x9D, 0x7F, 0x13, "NX25P80", 1048576, 256, SPIMemChipVendorNEXFLASH, SPIMemChipWriteModePage}, + {0x20, 0x40, 0x15, "M45PE16", 2097152, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x10, "M25P05", 65536, 128, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x10, "M25P05A", 65536, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x11, "M25P10", 131072, 128, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x11, "M25P10A", 131072, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x12, "M25P20", 262144, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x13, "M25P40", 524288, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x14, "M25P80", 1048576, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x15, "M25P16", 2097152, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x16, "M25P32", 4194304, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x17, "M25P64", 8388608, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, + 0x20, + 0x18, + "M25P128_ST25P28V6G", + 16777216, + 256, + SPIMemChipVendorNUMONYX, + SPIMemChipWriteModePage}, + {0x20, 0x80, 0x11, "M25PE10", 131072, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x80, 0x15, "M25PE16", 2097152, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x80, 0x12, "M25PE20", 262144, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x80, 0x13, "M25PE40", 524288, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0x20, 0x80, 0x14, "M25PE80", 1048576, 256, SPIMemChipVendorNUMONYX, SPIMemChipWriteModePage}, + {0xBF, 0x43, 0x00, "PCT25LF020A", 262144, 256, SPIMemChipVendorPCT, SPIMemChipWriteModePage}, + {0xBF, 0x49, 0x00, "PCT25VF010A", 131072, 256, SPIMemChipVendorPCT, SPIMemChipWriteModePage}, + {0xBF, 0x25, 0x41, "PCT25VF016B", 2097152, 256, SPIMemChipVendorPCT, SPIMemChipWriteModePage}, + {0xBF, 0x43, 0x00, "PCT25VF020A", 262144, 256, SPIMemChipVendorPCT, SPIMemChipWriteModePage}, + {0xBF, 0x25, 0x4A, "PCT25VF032B", 4194304, 256, SPIMemChipVendorPCT, SPIMemChipWriteModePage}, + {0xBF, 0x44, 0x00, "PCT25VF040A", 524288, 256, SPIMemChipVendorPCT, SPIMemChipWriteModePage}, + {0xBF, 0x25, 0x8D, "PCT25VF040B", 524288, 256, SPIMemChipVendorPCT, SPIMemChipWriteModePage}, + {0xBF, 0x25, 0x8E, "PCT25VF080B", 1048576, 256, SPIMemChipVendorPCT, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x10, "S25FL001D", 131072, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x11, "S25FL002D", 262144, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x12, "S25FL004A", 524288, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x12, "S25FL004D", 524288, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x13, "S25FL004K", 524288, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x13, "S25FL008A", 1048576, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x13, "S25FL008D", 1048576, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x14, "S25FL008K", 1048576, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x14, "S25FL016A", 2097152, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x15, "S25FL016K", 2097152, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x15, "S25FL032A", 4194304, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x16, "S25FL032K", 4194304, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x15, "S25FL032P", 4194304, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x12, "S25FL040A", 524288, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, + 0x02, + 0x26, + "S25FL040A_BOT", + 524288, + 256, + SPIMemChipVendorSPANSION, + SPIMemChipWriteModePage}, + {0x01, + 0x02, + 0x25, + "S25FL040A_TOP", + 524288, + 256, + SPIMemChipVendorSPANSION, + SPIMemChipWriteModePage}, + {0x01, 0x02, 0x16, "S25FL064A", 8388608, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x17, "S25FL064K", 8388608, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x02, 0x16, "S25FL064P", 8388608, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x40, 0x15, "S25FL116K", 2097152, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0xEF, + 0x40, + 0x18, + "S25FL128K", + 16777216, + 256, + SPIMemChipVendorSPANSION, + SPIMemChipWriteModePage}, + {0x01, + 0x20, + 0x18, + "S25FL128P", + 16777216, + 256, + SPIMemChipVendorSPANSION, + SPIMemChipWriteModePage}, + {0x01, + 0x20, + 0x18, + "S25FL128S", + 16777216, + 256, + SPIMemChipVendorSPANSION, + SPIMemChipWriteModePage}, + {0x01, 0x40, 0x16, "S25FL132K", 4194304, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, 0x40, 0x17, "S25FL164K", 8388608, 256, SPIMemChipVendorSPANSION, SPIMemChipWriteModePage}, + {0x01, + 0x02, + 0x19, + "S25FL256S", + 33554432, + 256, + SPIMemChipVendorSPANSION, + SPIMemChipWriteModePage}, + {0xBF, 0x25, 0x41, "SST25VF016B", 2097152, 1, SPIMemChipVendorSST, SPIMemChipWriteModeAAIWord}, + {0xBF, 0x25, 0x8C, "SST25VF020B", 262144, 1, SPIMemChipVendorSST, SPIMemChipWriteModeAAIWord}, + {0xBF, 0x25, 0x4A, "SST25VF032B", 4194304, 1, SPIMemChipVendorSST, SPIMemChipWriteModeAAIWord}, + {0xBF, 0x25, 0x4B, "SST25VF064C", 8388608, 256, SPIMemChipVendorSST, SPIMemChipWriteModePage}, + {0xBF, 0x25, 0x8D, "SST25VF040B", 524288, 1, SPIMemChipVendorSST, SPIMemChipWriteModeAAIWord}, + {0xBF, 0x25, 0x8E, "SST25VF080B", 1048576, 1, SPIMemChipVendorSST, SPIMemChipWriteModeAAIWord}, + {0x20, 0x71, 0x15, "M25PX16", 2097152, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x71, 0x16, "M25PX32", 4194304, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x71, 0x17, "M25PX64", 8388608, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x71, 0x14, "M25PX80", 1048576, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x10, "ST25P05", 65536, 128, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x10, "ST25P05A", 65536, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x11, "ST25P10", 131072, 128, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x11, "ST25P10A", 131072, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x15, "ST25P16", 2097152, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x12, "ST25P20", 262144, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x16, "ST25P32", 4194304, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x13, "ST25P40", 524288, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x17, "ST25P64", 8388608, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x14, "ST25P80", 1048576, 256, SPIMemChipVendorST, SPIMemChipWriteModePage}, + {0xEF, 0x10, 0x00, "W25P10", 131072, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x20, 0x15, "W25P16", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x11, 0x00, "W25P20", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x20, 0x16, "W25P32", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x12, 0x00, "W25P40", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x20, 0x17, "W25P64", 8388608, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x20, 0x14, "W25P80", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x60, + 0x11, + "W25Q10EW_1.8V", + 131072, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x18, "W25Q128BV", 16777216, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x18, "W25Q128FV", 16777216, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x70, 0x18, "W25Q128JV", 16777216, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x19, "W25Q256FV", 33554432, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x19, "W25Q256JV", 33554432, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x70, 0x19, "W25Q256JV", 33554432, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x60, + 0x18, + "W25Q128FW_1.8V", + 16777216, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x15, "W25Q16", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x15, "W25Q16BV", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x15, "W25Q16CL", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x15, "W25Q16CV", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x15, "W25Q16DV", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x60, + 0x15, + "W25Q16FW_1.8V", + 2097152, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x15, "W25Q16V", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x12, "W25Q20CL", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x60, + 0x12, + "W25Q20EW_1.8V", + 262144, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x16, "W25Q32", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x16, "W25Q32BV", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x16, "W25Q32FV", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x60, + 0x16, + "W25Q32FW_1.8V", + 4194304, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x16, "W25Q32V", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x13, "W25Q40BL", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x13, "W25Q40BV", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x13, "W25Q40CL", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x60, + 0x13, + "W25Q40EW_1.8V", + 524288, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x17, "W25Q64BV", 8388608, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x17, "W25Q64CV", 8388608, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x17, "W25Q64FV", 8388608, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x17, "W25Q64JV", 8388608, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x60, + 0x17, + "W25Q64FW_1.8V", + 8388608, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x14, "W25Q80BL", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x14, "W25Q80BV", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x50, + 0x14, + "W25Q80BW_1.8V", + 1048576, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x14, "W25Q80DV", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, + 0x60, + 0x14, + "W25Q80EW_1.8V", + 1048576, + 256, + SPIMemChipVendorWINBOND, + SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x10, "W25X05", 65536, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x10, "W25X05CL", 65536, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x11, "W25X10AV", 131072, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x11, "W25X10BL", 131072, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x11, "W25X10BV", 131072, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x11, "W25X10CL", 131072, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x11, "W25X10L", 131072, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x11, "W25X10V", 131072, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x15, "W25X16", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x15, "W25X16AL", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x15, "W25X16AV", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x15, "W25X16BV", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x15, "W25X16V", 2097152, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x12, "W25X20AL", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x12, "W25X20AV", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x12, "W25X20BL", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x12, "W25X20BV", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x12, "W25X20CL", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x12, "W25X20L", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x12, "W25X20V", 262144, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x16, "W25X32", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x16, "W25X32AV", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x16, "W25X32BV", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x16, "W25X32V", 4194304, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x13, "W25X40AL", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x13, "W25X40AV", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x13, "W25X40BL", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x13, "W25X40BV", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x13, "W25X40CL", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x13, "W25X40L", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x13, "W25X40V", 524288, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x17, "W25X64", 8388608, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x17, "W25X64BV", 8388608, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x17, "W25X64V", 8388608, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x14, "W25X80AL", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x14, "W25X80AV", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x14, "W25X80BV", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x14, "W25X80L", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x30, 0x14, "W25X80V", 1048576, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x71, 0x19, "W25M512JV", 67108864, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0xEF, 0x40, 0x19, "W25R256JV", 33554432, 256, SPIMemChipVendorWINBOND, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x10, "TS25L512A", 65536, 256, SPIMemChipVendorZEMPRO, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x11, "TS25L010A", 131072, 256, SPIMemChipVendorZEMPRO, SPIMemChipWriteModePage}, + {0x37, 0x30, 0x12, "TS25L020A", 262144, 256, SPIMemChipVendorZEMPRO, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x15, "TS25L16AP", 2097152, 256, SPIMemChipVendorZEMPRO, SPIMemChipWriteModePage}, + {0x20, 0x20, 0x15, "TS25L16BP", 2097152, 256, SPIMemChipVendorZEMPRO, SPIMemChipWriteModePage}, + {0x37, 0x20, 0x15, "TS25L16P", 2097152, 256, SPIMemChipVendorZEMPRO, SPIMemChipWriteModePage}, + {0x5E, 0x40, 0x15, "ZB25D16", 2097152, 256, SPIMemChipVendorZbit, SPIMemChipWriteModePage}, + {0xE0, 0x40, 0x13, "BG25Q40A", 524288, 256, SPIMemChipVendorBerg_Micro, SPIMemChipWriteModePage}, + {0xE0, + 0x40, + 0x14, + "BG25Q80A", + 1048576, + 256, + SPIMemChipVendorBerg_Micro, + SPIMemChipWriteModePage}, + {0xE0, + 0x40, + 0x15, + "BG25Q16A", + 2097152, + 256, + SPIMemChipVendorBerg_Micro, + SPIMemChipWriteModePage}, + {0xE0, + 0x40, + 0x16, + "BG25Q32A", + 4194304, + 256, + SPIMemChipVendorBerg_Micro, + SPIMemChipWriteModePage}, + {0x1F, 0x23, 0x00, "AT45DB021D", 270336, 264, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x24, 0x00, "AT45DB041D", 540672, 264, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x26, 0x00, "AT45DB161D", 2162688, 528, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x27, 0x01, "AT45DB321D", 4325376, 528, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x43, 0x00, "AT25DF021", 262144, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x44, 0x00, "AT25DF041", 524288, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x44, 0x00, "AT25DF041A", 524288, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x84, 0x00, "AT25SF041", 524288, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x45, 0x00, "AT25DF081", 1048576, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x45, 0x00, "AT25DF081A", 1048576, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x46, 0x00, "AT25DF161", 2097152, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x47, 0x00, "AT25DF321", 4194304, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x47, 0x00, "AT25DF321A", 4194304, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x48, 0x00, "AT25DF641", 8388608, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x65, 0x00, "AT25F512B", 65536, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x45, 0x00, "AT26DF081", 1048576, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x45, 0x00, "AT26DF081A", 1048576, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x46, 0x00, "AT26DF161", 2097152, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x46, 0x00, "AT26DF161A", 2097152, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x47, 0x00, "AT26DF321", 4194304, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x47, 0x00, "AT26DF321A", 4194304, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0x1F, 0x04, 0x00, "AT26F004", 524288, 256, SPIMemChipVendorATMEL, SPIMemChipWriteModePage}, + {0xE0, + 0x60, + 0x18, + "ACE25A128G_1.8V", + 16777216, + 256, + SPIMemChipVendorACE, + SPIMemChipWriteModePage}, + {0x9B, 0x32, 0x16, "ATO25Q32", 4194304, 256, SPIMemChipVendorATO, SPIMemChipWriteModePage}, + {0x54, 0x40, 0x17, "DQ25Q64A", 8388608, 256, SPIMemChipVendorDOUQI, SPIMemChipWriteModePage}, + {0x0E, 0x40, 0x15, "FT25H16", 2097152, 256, SPIMemChipVendorFremont, SPIMemChipWriteModePage}, + {0xA1, 0x40, 0x13, "FM25Q04A", 524288, 256, SPIMemChipVendorFudan, SPIMemChipWriteModePage}, + {0xA1, 0x40, 0x16, "FM25Q32", 4194304, 256, SPIMemChipVendorFudan, SPIMemChipWriteModePage}, + {0xE0, 0x40, 0x14, "GT25Q80A", 1048576, 256, SPIMemChipVendorGenitop, SPIMemChipWriteModePage}, + {0xE0, 0x40, 0x13, "PN25F04A", 524288, 256, SPIMemChipVendorParagon, SPIMemChipWriteModePage}}; diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip_i.h b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip_i.h new file mode 100644 index 000000000..30d607094 --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip_i.h @@ -0,0 +1,85 @@ +#pragma once + +#include +#include "spi_mem_chip.h" + +typedef enum { + SPIMemChipVendorUnknown, + SPIMemChipVendorADESTO, + SPIMemChipVendorAMIC, + SPIMemChipVendorBoya, + SPIMemChipVendorEON, + SPIMemChipVendorPFLASH, + SPIMemChipVendorTERRA, + SPIMemChipVendorGeneralplus, + SPIMemChipVendorDEUTRON, + SPIMemChipVendorEFST, + SPIMemChipVendorEXCELSEMI, + SPIMemChipVendorFIDELIX, + SPIMemChipVendorGIGADEVICE, + SPIMemChipVendorICE, + SPIMemChipVendorINTEL, + SPIMemChipVendorKHIC, + SPIMemChipVendorMACRONIX, + SPIMemChipVendorMICRON, + SPIMemChipVendorMSHINE, + SPIMemChipVendorNANTRONICS, + SPIMemChipVendorNEXFLASH, + SPIMemChipVendorNUMONYX, + SPIMemChipVendorPCT, + SPIMemChipVendorSPANSION, + SPIMemChipVendorSST, + SPIMemChipVendorST, + SPIMemChipVendorWINBOND, + SPIMemChipVendorZEMPRO, + SPIMemChipVendorZbit, + SPIMemChipVendorBerg_Micro, + SPIMemChipVendorATMEL, + SPIMemChipVendorACE, + SPIMemChipVendorATO, + SPIMemChipVendorDOUQI, + SPIMemChipVendorFremont, + SPIMemChipVendorFudan, + SPIMemChipVendorGenitop, + SPIMemChipVendorParagon +} SPIMemChipVendor; + +typedef enum { + SPIMemChipCMDReadJEDECChipID = 0x9F, + SPIMemChipCMDReadData = 0x03, + SPIMemChipCMDChipErase = 0xC7, + SPIMemChipCMDWriteEnable = 0x06, + SPIMemChipCMDWriteDisable = 0x04, + SPIMemChipCMDReadStatus = 0x05, + SPIMemChipCMDWriteData = 0x02, + SPIMemChipCMDReleasePowerDown = 0xAB +} SPIMemChipCMD; + +enum SPIMemChipStatusBit { + SPIMemChipStatusBitBusy = (0x01 << 0), + SPIMemChipStatusBitWriteEnabled = (0x01 << 1), + SPIMemChipStatusBitBitProtection1 = (0x01 << 2), + SPIMemChipStatusBitBitProtection2 = (0x01 << 3), + SPIMemChipStatusBitBitProtection3 = (0x01 << 4), + SPIMemChipStatusBitTopBottomProtection = (0x01 << 5), + SPIMemChipStatusBitSectorProtect = (0x01 << 6), + SPIMemChipStatusBitRegisterProtect = (0x01 << 7) +}; + +typedef struct { + const char* vendor_name; + SPIMemChipVendor vendor_enum; +} SPIMemChipVendorName; + +struct SPIMemChip { + uint8_t vendor_id; + uint8_t type_id; + uint8_t capacity_id; + const char* model_name; + size_t size; + size_t page_size; + SPIMemChipVendor vendor_enum; + SPIMemChipWriteMode write_mode; +}; + +extern const SPIMemChip SPIMemChips[]; diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_tools.c b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_tools.c new file mode 100644 index 000000000..7a788241b --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_tools.c @@ -0,0 +1,152 @@ +#include +#include +#include "spi_mem_chip_i.h" +#include "spi_mem_tools.h" + +static uint8_t spi_mem_tools_addr_to_byte_arr(uint32_t addr, uint8_t* cmd) { + uint8_t len = 3; // TODO(add support of 4 bytes address mode) + for(uint8_t i = 0; i < len; i++) { + cmd[i] = (addr >> ((len - (i + 1)) * 8)) & 0xFF; + } + return len; +} + +static bool spi_mem_tools_trx( + SPIMemChipCMD cmd, + uint8_t* tx_buf, + size_t tx_size, + uint8_t* rx_buf, + size_t rx_size) { + bool success = false; + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_external); + do { + if(!furi_hal_spi_bus_tx( + &furi_hal_spi_bus_handle_external, (uint8_t*)&cmd, 1, SPI_MEM_SPI_TIMEOUT)) + break; + if(tx_buf) { + if(!furi_hal_spi_bus_tx( + &furi_hal_spi_bus_handle_external, tx_buf, tx_size, SPI_MEM_SPI_TIMEOUT)) + break; + } + if(rx_buf) { + if(!furi_hal_spi_bus_rx( + &furi_hal_spi_bus_handle_external, rx_buf, rx_size, SPI_MEM_SPI_TIMEOUT)) + break; + } + success = true; + } while(0); + furi_hal_spi_release(&furi_hal_spi_bus_handle_external); + return success; +} + +static bool spi_mem_tools_write_buffer(uint8_t* data, size_t size, size_t offset) { + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_external); + uint8_t cmd = (uint8_t)SPIMemChipCMDWriteData; + uint8_t address[4]; + uint8_t address_size = spi_mem_tools_addr_to_byte_arr(offset, address); + bool success = false; + do { + if(!furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_external, &cmd, 1, SPI_MEM_SPI_TIMEOUT)) + break; + if(!furi_hal_spi_bus_tx( + &furi_hal_spi_bus_handle_external, address, address_size, SPI_MEM_SPI_TIMEOUT)) + break; + if(!furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_external, data, size, SPI_MEM_SPI_TIMEOUT)) + break; + success = true; + } while(0); + furi_hal_spi_release(&furi_hal_spi_bus_handle_external); + return success; +} + +bool spi_mem_tools_read_chip_info(SPIMemChip* chip) { + uint8_t rx_buf[3] = {0, 0, 0}; + do { + if(!spi_mem_tools_trx(SPIMemChipCMDReadJEDECChipID, NULL, 0, rx_buf, 3)) break; + if(rx_buf[0] == 0 || rx_buf[0] == 255) break; + chip->vendor_id = rx_buf[0]; + chip->type_id = rx_buf[1]; + chip->capacity_id = rx_buf[2]; + return true; + } while(0); + return false; +} + +bool spi_mem_tools_check_chip_info(SPIMemChip* chip) { + SPIMemChip new_chip_info; + do { + if(!spi_mem_tools_read_chip_info(&new_chip_info)) break; + if(chip->vendor_id != new_chip_info.vendor_id) break; + if(chip->type_id != new_chip_info.type_id) break; + if(chip->capacity_id != new_chip_info.capacity_id) break; + return true; + } while(0); + return false; +} + +bool spi_mem_tools_read_block(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size) { + if(!spi_mem_tools_check_chip_info(chip)) return false; + for(size_t i = 0; i < block_size; i += SPI_MEM_MAX_BLOCK_SIZE) { + uint8_t cmd[4]; + if((offset + SPI_MEM_MAX_BLOCK_SIZE) > chip->size) return false; + if(!spi_mem_tools_trx( + SPIMemChipCMDReadData, + cmd, + spi_mem_tools_addr_to_byte_arr(offset, cmd), + data, + SPI_MEM_MAX_BLOCK_SIZE)) + return false; + offset += SPI_MEM_MAX_BLOCK_SIZE; + data += SPI_MEM_MAX_BLOCK_SIZE; + } + return true; +} + +size_t spi_mem_tools_get_file_max_block_size(SPIMemChip* chip) { + UNUSED(chip); + return (SPI_MEM_FILE_BUFFER_SIZE); +} + +SPIMemChipStatus spi_mem_tools_get_chip_status(SPIMemChip* chip) { + UNUSED(chip); + uint8_t status; + if(!spi_mem_tools_trx(SPIMemChipCMDReadStatus, NULL, 0, &status, 1)) + return SPIMemChipStatusError; + if(status & SPIMemChipStatusBitBusy) return SPIMemChipStatusBusy; + return SPIMemChipStatusIdle; +} + +static bool spi_mem_tools_set_write_enabled(SPIMemChip* chip, bool enable) { + UNUSED(chip); + uint8_t status; + SPIMemChipCMD cmd = SPIMemChipCMDWriteDisable; + if(enable) cmd = SPIMemChipCMDWriteEnable; + do { + if(!spi_mem_tools_trx(cmd, NULL, 0, NULL, 0)) break; + if(!spi_mem_tools_trx(SPIMemChipCMDReadStatus, NULL, 0, &status, 1)) break; + if(!(status & SPIMemChipStatusBitWriteEnabled) && enable) break; + if((status & SPIMemChipStatusBitWriteEnabled) && !enable) break; + return true; + } while(0); + return false; +} + +bool spi_mem_tools_erase_chip(SPIMemChip* chip) { + do { + if(!spi_mem_tools_set_write_enabled(chip, true)) break; + if(!spi_mem_tools_trx(SPIMemChipCMDChipErase, NULL, 0, NULL, 0)) break; + return true; + } while(0); + return true; +} + +bool spi_mem_tools_write_bytes(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size) { + do { + if(!spi_mem_tools_check_chip_info(chip)) break; + if(!spi_mem_tools_set_write_enabled(chip, true)) break; + if((offset + block_size) > chip->size) break; + if(!spi_mem_tools_write_buffer(data, block_size, offset)) break; + return true; + } while(0); + return false; +} diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_tools.h b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_tools.h new file mode 100644 index 000000000..ad006b8ff --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_tools.h @@ -0,0 +1,14 @@ +#pragma once + +#include "spi_mem_chip.h" + +#define SPI_MEM_SPI_TIMEOUT 1000 +#define SPI_MEM_MAX_BLOCK_SIZE 256 +#define SPI_MEM_FILE_BUFFER_SIZE 4096 + +bool spi_mem_tools_read_chip_info(SPIMemChip* chip); +bool spi_mem_tools_read_block(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size); +size_t spi_mem_tools_get_file_max_block_size(SPIMemChip* chip); +SPIMemChipStatus spi_mem_tools_get_chip_status(SPIMemChip* chip); +bool spi_mem_tools_erase_chip(SPIMemChip* chip); +bool spi_mem_tools_write_bytes(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size); diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker.c b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker.c new file mode 100644 index 000000000..438f338f1 --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker.c @@ -0,0 +1,129 @@ +#include "spi_mem_worker_i.h" + +typedef enum { + SPIMemEventStopThread = (1 << 0), + SPIMemEventChipDetect = (1 << 1), + SPIMemEventRead = (1 << 2), + SPIMemEventVerify = (1 << 3), + SPIMemEventErase = (1 << 4), + SPIMemEventWrite = (1 << 5), + SPIMemEventAll = + (SPIMemEventStopThread | SPIMemEventChipDetect | SPIMemEventRead | SPIMemEventVerify | + SPIMemEventErase | SPIMemEventWrite) +} SPIMemEventEventType; + +static int32_t spi_mem_worker_thread(void* thread_context); + +SPIMemWorker* spi_mem_worker_alloc() { + SPIMemWorker* worker = malloc(sizeof(SPIMemWorker)); + worker->callback = NULL; + worker->thread = furi_thread_alloc(); + worker->mode_index = SPIMemWorkerModeIdle; + furi_thread_set_name(worker->thread, "SPIMemWorker"); + furi_thread_set_callback(worker->thread, spi_mem_worker_thread); + furi_thread_set_context(worker->thread, worker); + furi_thread_set_stack_size(worker->thread, 10240); + return worker; +} + +void spi_mem_worker_free(SPIMemWorker* worker) { + furi_thread_free(worker->thread); + free(worker); +} + +bool spi_mem_worker_check_for_stop(SPIMemWorker* worker) { + UNUSED(worker); + uint32_t flags = furi_thread_flags_get(); + return (flags & SPIMemEventStopThread); +} + +static int32_t spi_mem_worker_thread(void* thread_context) { + SPIMemWorker* worker = thread_context; + while(true) { + uint32_t flags = furi_thread_flags_wait(SPIMemEventAll, FuriFlagWaitAny, FuriWaitForever); + if(flags != (unsigned)FuriFlagErrorTimeout) { + if(flags & SPIMemEventStopThread) break; + if(flags & SPIMemEventChipDetect) worker->mode_index = SPIMemWorkerModeChipDetect; + if(flags & SPIMemEventRead) worker->mode_index = SPIMemWorkerModeRead; + if(flags & SPIMemEventVerify) worker->mode_index = SPIMemWorkerModeVerify; + if(flags & SPIMemEventErase) worker->mode_index = SPIMemWorkerModeErase; + if(flags & SPIMemEventWrite) worker->mode_index = SPIMemWorkerModeWrite; + if(spi_mem_worker_modes[worker->mode_index].process) { + spi_mem_worker_modes[worker->mode_index].process(worker); + } + worker->mode_index = SPIMemWorkerModeIdle; + } + } + return 0; +} + +void spi_mem_worker_start_thread(SPIMemWorker* worker) { + furi_thread_start(worker->thread); +} + +void spi_mem_worker_stop_thread(SPIMemWorker* worker) { + furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventStopThread); + furi_thread_join(worker->thread); +} + +void spi_mem_worker_chip_detect_start( + SPIMemChip* chip_info, + found_chips_t* found_chips, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context) { + furi_check(worker->mode_index == SPIMemWorkerModeIdle); + worker->callback = callback; + worker->cb_ctx = context; + worker->chip_info = chip_info; + worker->found_chips = found_chips; + furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventChipDetect); +} + +void spi_mem_worker_read_start( + SPIMemChip* chip_info, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context) { + furi_check(worker->mode_index == SPIMemWorkerModeIdle); + worker->callback = callback; + worker->cb_ctx = context; + worker->chip_info = chip_info; + furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventRead); +} + +void spi_mem_worker_verify_start( + SPIMemChip* chip_info, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context) { + furi_check(worker->mode_index == SPIMemWorkerModeIdle); + worker->callback = callback; + worker->cb_ctx = context; + worker->chip_info = chip_info; + furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventVerify); +} + +void spi_mem_worker_erase_start( + SPIMemChip* chip_info, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context) { + furi_check(worker->mode_index == SPIMemWorkerModeIdle); + worker->callback = callback; + worker->cb_ctx = context; + worker->chip_info = chip_info; + furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventErase); +} + +void spi_mem_worker_write_start( + SPIMemChip* chip_info, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context) { + furi_check(worker->mode_index == SPIMemWorkerModeIdle); + worker->callback = callback; + worker->cb_ctx = context; + worker->chip_info = chip_info; + furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventWrite); +} diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker.h b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker.h new file mode 100644 index 000000000..c3761cd5a --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include "spi_mem_chip.h" + +typedef struct SPIMemWorker SPIMemWorker; + +typedef struct { + void (*const process)(SPIMemWorker* worker); +} SPIMemWorkerModeType; + +typedef enum { + SPIMemCustomEventWorkerChipIdentified, + SPIMemCustomEventWorkerChipUnknown, + SPIMemCustomEventWorkerBlockReaded, + SPIMemCustomEventWorkerChipFail, + SPIMemCustomEventWorkerFileFail, + SPIMemCustomEventWorkerDone, + SPIMemCustomEventWorkerVerifyFail, +} SPIMemCustomEventWorker; + +typedef void (*SPIMemWorkerCallback)(void* context, SPIMemCustomEventWorker event); + +SPIMemWorker* spi_mem_worker_alloc(); +void spi_mem_worker_free(SPIMemWorker* worker); +void spi_mem_worker_start_thread(SPIMemWorker* worker); +void spi_mem_worker_stop_thread(SPIMemWorker* worker); +bool spi_mem_worker_check_for_stop(SPIMemWorker* worker); +void spi_mem_worker_chip_detect_start( + SPIMemChip* chip_info, + found_chips_t* found_chips, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context); +void spi_mem_worker_read_start( + SPIMemChip* chip_info, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context); +void spi_mem_worker_verify_start( + SPIMemChip* chip_info, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context); +void spi_mem_worker_erase_start( + SPIMemChip* chip_info, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context); +void spi_mem_worker_write_start( + SPIMemChip* chip_info, + SPIMemWorker* worker, + SPIMemWorkerCallback callback, + void* context); diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker_i.h b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker_i.h new file mode 100644 index 000000000..43e2d2287 --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker_i.h @@ -0,0 +1,24 @@ +#pragma once + +#include "spi_mem_worker.h" + +typedef enum { + SPIMemWorkerModeIdle, + SPIMemWorkerModeChipDetect, + SPIMemWorkerModeRead, + SPIMemWorkerModeVerify, + SPIMemWorkerModeErase, + SPIMemWorkerModeWrite +} SPIMemWorkerMode; + +struct SPIMemWorker { + SPIMemChip* chip_info; + found_chips_t* found_chips; + SPIMemWorkerMode mode_index; + SPIMemWorkerCallback callback; + void* cb_ctx; + FuriThread* thread; + FuriString* file_name; +}; + +extern const SPIMemWorkerModeType spi_mem_worker_modes[]; diff --git a/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker_modes.c b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker_modes.c new file mode 100644 index 000000000..a393e5490 --- /dev/null +++ b/applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker_modes.c @@ -0,0 +1,214 @@ +#include "spi_mem_worker_i.h" +#include "spi_mem_chip.h" +#include "spi_mem_tools.h" +#include "../../spi_mem_files.h" + +static void spi_mem_worker_chip_detect_process(SPIMemWorker* worker); +static void spi_mem_worker_read_process(SPIMemWorker* worker); +static void spi_mem_worker_verify_process(SPIMemWorker* worker); +static void spi_mem_worker_erase_process(SPIMemWorker* worker); +static void spi_mem_worker_write_process(SPIMemWorker* worker); + +const SPIMemWorkerModeType spi_mem_worker_modes[] = { + [SPIMemWorkerModeIdle] = {.process = NULL}, + [SPIMemWorkerModeChipDetect] = {.process = spi_mem_worker_chip_detect_process}, + [SPIMemWorkerModeRead] = {.process = spi_mem_worker_read_process}, + [SPIMemWorkerModeVerify] = {.process = spi_mem_worker_verify_process}, + [SPIMemWorkerModeErase] = {.process = spi_mem_worker_erase_process}, + [SPIMemWorkerModeWrite] = {.process = spi_mem_worker_write_process}}; + +static void spi_mem_worker_run_callback(SPIMemWorker* worker, SPIMemCustomEventWorker event) { + if(worker->callback) { + worker->callback(worker->cb_ctx, event); + } +} + +static bool spi_mem_worker_await_chip_busy(SPIMemWorker* worker) { + while(true) { + furi_delay_tick(10); // to give some time to OS + if(spi_mem_worker_check_for_stop(worker)) return true; + SPIMemChipStatus chip_status = spi_mem_tools_get_chip_status(worker->chip_info); + if(chip_status == SPIMemChipStatusError) return false; + if(chip_status == SPIMemChipStatusBusy) continue; + return true; + } +} + +static size_t spi_mem_worker_modes_get_total_size(SPIMemWorker* worker) { + size_t chip_size = spi_mem_chip_get_size(worker->chip_info); + size_t file_size = spi_mem_file_get_size(worker->cb_ctx); + size_t total_size = chip_size; + if(chip_size > file_size) total_size = file_size; + return total_size; +} + +// ChipDetect +static void spi_mem_worker_chip_detect_process(SPIMemWorker* worker) { + SPIMemCustomEventWorker event; + while(!spi_mem_tools_read_chip_info(worker->chip_info)) { + furi_delay_tick(10); // to give some time to OS + if(spi_mem_worker_check_for_stop(worker)) return; + } + if(spi_mem_chip_find_all(worker->chip_info, *worker->found_chips)) { + event = SPIMemCustomEventWorkerChipIdentified; + } else { + event = SPIMemCustomEventWorkerChipUnknown; + } + spi_mem_worker_run_callback(worker, event); +} + +// Read +static bool spi_mem_worker_read(SPIMemWorker* worker, SPIMemCustomEventWorker* event) { + uint8_t data_buffer[SPI_MEM_FILE_BUFFER_SIZE]; + size_t chip_size = spi_mem_chip_get_size(worker->chip_info); + size_t offset = 0; + bool success = true; + while(true) { + furi_delay_tick(10); // to give some time to OS + size_t block_size = SPI_MEM_FILE_BUFFER_SIZE; + if(spi_mem_worker_check_for_stop(worker)) break; + if(offset >= chip_size) break; + if((offset + block_size) > chip_size) block_size = chip_size - offset; + if(!spi_mem_tools_read_block(worker->chip_info, offset, data_buffer, block_size)) { + *event = SPIMemCustomEventWorkerChipFail; + success = false; + break; + } + if(!spi_mem_file_write_block(worker->cb_ctx, data_buffer, block_size)) { + success = false; + break; + } + offset += block_size; + spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded); + } + if(success) *event = SPIMemCustomEventWorkerDone; + return success; +} + +static void spi_mem_worker_read_process(SPIMemWorker* worker) { + SPIMemCustomEventWorker event = SPIMemCustomEventWorkerFileFail; + do { + if(!spi_mem_worker_await_chip_busy(worker)) break; + if(!spi_mem_file_create_open(worker->cb_ctx)) break; + if(!spi_mem_worker_read(worker, &event)) break; + } while(0); + spi_mem_file_close(worker->cb_ctx); + spi_mem_worker_run_callback(worker, event); +} + +// Verify +static bool + spi_mem_worker_verify(SPIMemWorker* worker, size_t total_size, SPIMemCustomEventWorker* event) { + uint8_t data_buffer_chip[SPI_MEM_FILE_BUFFER_SIZE]; + uint8_t data_buffer_file[SPI_MEM_FILE_BUFFER_SIZE]; + size_t offset = 0; + bool success = true; + while(true) { + furi_delay_tick(10); // to give some time to OS + size_t block_size = SPI_MEM_FILE_BUFFER_SIZE; + if(spi_mem_worker_check_for_stop(worker)) break; + if(offset >= total_size) break; + if((offset + block_size) > total_size) block_size = total_size - offset; + if(!spi_mem_tools_read_block(worker->chip_info, offset, data_buffer_chip, block_size)) { + *event = SPIMemCustomEventWorkerChipFail; + success = false; + break; + } + if(!spi_mem_file_read_block(worker->cb_ctx, data_buffer_file, block_size)) { + success = false; + break; + } + if(memcmp(data_buffer_chip, data_buffer_file, block_size) != 0) { + *event = SPIMemCustomEventWorkerVerifyFail; + success = false; + break; + } + offset += block_size; + spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded); + } + if(success) *event = SPIMemCustomEventWorkerDone; + return success; +} + +static void spi_mem_worker_verify_process(SPIMemWorker* worker) { + SPIMemCustomEventWorker event = SPIMemCustomEventWorkerFileFail; + size_t total_size = spi_mem_worker_modes_get_total_size(worker); + do { + if(!spi_mem_worker_await_chip_busy(worker)) break; + if(!spi_mem_file_open(worker->cb_ctx)) break; + if(!spi_mem_worker_verify(worker, total_size, &event)) break; + } while(0); + spi_mem_file_close(worker->cb_ctx); + spi_mem_worker_run_callback(worker, event); +} + +// Erase +static void spi_mem_worker_erase_process(SPIMemWorker* worker) { + SPIMemCustomEventWorker event = SPIMemCustomEventWorkerChipFail; + do { + if(!spi_mem_worker_await_chip_busy(worker)) break; + if(!spi_mem_tools_erase_chip(worker->chip_info)) break; + if(!spi_mem_worker_await_chip_busy(worker)) break; + event = SPIMemCustomEventWorkerDone; + } while(0); + spi_mem_worker_run_callback(worker, event); +} + +// Write +static bool spi_mem_worker_write_block_by_page( + SPIMemWorker* worker, + size_t offset, + uint8_t* data, + size_t block_size, + size_t page_size) { + for(size_t i = 0; i < block_size; i += page_size) { + if(!spi_mem_worker_await_chip_busy(worker)) return false; + if(!spi_mem_tools_write_bytes(worker->chip_info, offset, data, page_size)) return false; + offset += page_size; + data += page_size; + } + return true; +} + +static bool + spi_mem_worker_write(SPIMemWorker* worker, size_t total_size, SPIMemCustomEventWorker* event) { + bool success = true; + uint8_t data_buffer[SPI_MEM_FILE_BUFFER_SIZE]; + size_t page_size = spi_mem_chip_get_page_size(worker->chip_info); + size_t offset = 0; + while(true) { + furi_delay_tick(10); // to give some time to OS + size_t block_size = SPI_MEM_FILE_BUFFER_SIZE; + if(spi_mem_worker_check_for_stop(worker)) break; + if(offset >= total_size) break; + if((offset + block_size) > total_size) block_size = total_size - offset; + if(!spi_mem_file_read_block(worker->cb_ctx, data_buffer, block_size)) { + *event = SPIMemCustomEventWorkerFileFail; + success = false; + break; + } + if(!spi_mem_worker_write_block_by_page( + worker, offset, data_buffer, block_size, page_size)) { + success = false; + break; + } + offset += block_size; + spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded); + } + return success; +} + +static void spi_mem_worker_write_process(SPIMemWorker* worker) { + SPIMemCustomEventWorker event = SPIMemCustomEventWorkerChipFail; + size_t total_size = + spi_mem_worker_modes_get_total_size(worker); // need to be executed before opening file + do { + if(!spi_mem_file_open(worker->cb_ctx)) break; + if(!spi_mem_worker_await_chip_busy(worker)) break; + if(!spi_mem_worker_write(worker, total_size, &event)) break; + if(!spi_mem_worker_await_chip_busy(worker)) break; + event = SPIMemCustomEventWorkerDone; + } while(0); + spi_mem_file_close(worker->cb_ctx); + spi_mem_worker_run_callback(worker, event); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene.c new file mode 100644 index 000000000..7780005f4 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene.c @@ -0,0 +1,30 @@ +#include "spi_mem_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const spi_mem_on_enter_handlers[])(void*) = { +#include "spi_mem_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const spi_mem_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "spi_mem_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const spi_mem_on_exit_handlers[])(void* context) = { +#include "spi_mem_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers spi_mem_scene_handlers = { + .on_enter_handlers = spi_mem_on_enter_handlers, + .on_event_handlers = spi_mem_on_event_handlers, + .on_exit_handlers = spi_mem_on_exit_handlers, + .scene_num = SPIMemSceneNum, +}; diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene.h b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene.h new file mode 100644 index 000000000..2ac6d21e3 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) SPIMemScene##id, +typedef enum { +#include "spi_mem_scene_config.h" + SPIMemSceneNum, +} SPIMemScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers spi_mem_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "spi_mem_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "spi_mem_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "spi_mem_scene_config.h" +#undef ADD_SCENE diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_about.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_about.c new file mode 100644 index 000000000..9e0f6f0c6 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_about.c @@ -0,0 +1,43 @@ +#include "../spi_mem_app_i.h" +#include "../lib/spi/spi_mem_chip.h" + +#define SPI_MEM_VERSION_APP "0.1.0" +#define SPI_MEM_DEVELOPER "DrunkBatya" +#define SPI_MEM_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" +#define SPI_MEM_NAME "\e#\e! SPI Mem Manager \e!\n" // NOSONAR +#define SPI_MEM_BLANK_INV \ + "\e#\e! \e!\n" // NOSONAR + +void spi_mem_scene_about_on_enter(void* context) { + SPIMemApp* app = context; + FuriString* tmp_string = furi_string_alloc(); + + widget_add_text_box_element( + app->widget, 0, 0, 128, 14, AlignCenter, AlignBottom, SPI_MEM_BLANK_INV, false); + widget_add_text_box_element( + app->widget, 0, 2, 128, 14, AlignCenter, AlignBottom, SPI_MEM_NAME, false); + furi_string_printf(tmp_string, "\e#%s\n", "Information"); // NOSONAR + furi_string_cat_printf(tmp_string, "Version: %s\n", SPI_MEM_VERSION_APP); + furi_string_cat_printf(tmp_string, "Developed by: %s\n", SPI_MEM_DEVELOPER); + furi_string_cat_printf(tmp_string, "Github: %s\n\n", SPI_MEM_GITHUB); + furi_string_cat_printf(tmp_string, "\e#%s\n", "Description"); // NOSONAR + furi_string_cat_printf( + tmp_string, + "SPI memory dumper\n" + "Originally written by Hedger, ghettorce and x893 at\n" + "Flipper Hackathon 2021\n\n"); + widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(tmp_string)); + + furi_string_free(tmp_string); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); +} + +bool spi_mem_scene_about_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} +void spi_mem_scene_about_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detect.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detect.c new file mode 100644 index 000000000..d9b8f0aa3 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detect.c @@ -0,0 +1,37 @@ +#include "../spi_mem_app_i.h" + +static void spi_mem_scene_chip_detect_callback(void* context, SPIMemCustomEventWorker event) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void spi_mem_scene_chip_detect_on_enter(void* context) { + SPIMemApp* app = context; + notification_message(app->notifications, &sequence_blink_start_yellow); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewDetect); + spi_mem_worker_start_thread(app->worker); + spi_mem_worker_chip_detect_start( + app->chip_info, &app->found_chips, app->worker, spi_mem_scene_chip_detect_callback, app); +} + +bool spi_mem_scene_chip_detect_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == SPIMemCustomEventWorkerChipIdentified) { + scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, 0); + scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectVendor); + } else if(event.event == SPIMemCustomEventWorkerChipUnknown) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetectFail); + } + } + return success; +} + +void spi_mem_scene_chip_detect_on_exit(void* context) { + SPIMemApp* app = context; + spi_mem_worker_stop_thread(app->worker); + notification_message(app->notifications, &sequence_blink_stop); + popup_reset(app->popup); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detect_fail.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detect_fail.c new file mode 100644 index 000000000..876a28721 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detect_fail.c @@ -0,0 +1,57 @@ +#include "../spi_mem_app_i.h" +#include "../lib/spi/spi_mem_chip.h" + +static void spi_mem_scene_chip_detect_fail_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + SPIMemApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void spi_mem_scene_chip_detect_fail_on_enter(void* context) { + SPIMemApp* app = context; + FuriString* str = furi_string_alloc(); + widget_add_button_element( + app->widget, + GuiButtonTypeCenter, + "Retry", + spi_mem_scene_chip_detect_fail_widget_callback, + app); + widget_add_string_element( + app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Detected"); + widget_add_string_element( + app->widget, 64, 20, AlignCenter, AlignBottom, FontPrimary, "unknown SPI chip"); + furi_string_printf(str, "Vendor\nid: 0x%02X", spi_mem_chip_get_vendor_id(app->chip_info)); + widget_add_string_multiline_element( + app->widget, 16, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str)); + furi_string_printf(str, "Type\nid: 0x%02X", spi_mem_chip_get_type_id(app->chip_info)); + widget_add_string_multiline_element( + app->widget, 64, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str)); + furi_string_printf(str, "Capacity\nid: 0x%02X", spi_mem_chip_get_capacity_id(app->chip_info)); + widget_add_string_multiline_element( + app->widget, 110, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str)); + furi_string_free(str); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); +} + +bool spi_mem_scene_chip_detect_fail_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SPIMemSceneStart); + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == GuiButtonTypeCenter) { + scene_manager_previous_scene(app->scene_manager); + } + } + return success; +} +void spi_mem_scene_chip_detect_fail_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detected.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detected.c new file mode 100644 index 000000000..539578a45 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_detected.c @@ -0,0 +1,94 @@ +#include "../spi_mem_app_i.h" + +static void spi_mem_scene_chip_detected_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + SPIMemApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +static void spi_mem_scene_chip_detected_print_chip_info(Widget* widget, SPIMemChip* chip_info) { + FuriString* tmp_string = furi_string_alloc(); + widget_add_string_element( + widget, + 40, + 12, + AlignLeft, + AlignTop, + FontSecondary, + spi_mem_chip_get_vendor_name(chip_info)); + widget_add_string_element( + widget, 40, 20, AlignLeft, AlignTop, FontSecondary, spi_mem_chip_get_model_name(chip_info)); + furi_string_printf(tmp_string, "Size: %zu KB", spi_mem_chip_get_size(chip_info) / 1024); + widget_add_string_element( + widget, 40, 28, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp_string)); + furi_string_free(tmp_string); +} + +static void spi_mem_scene_chip_detect_draw_next_button(SPIMemApp* app) { + FuriString* str = furi_string_alloc(); + if(app->mode == SPIMemModeRead) furi_string_printf(str, "%s", "Read"); + if(app->mode == SPIMemModeWrite) furi_string_printf(str, "%s", "Write"); + if(app->mode == SPIMemModeErase) furi_string_printf(str, "%s", "Erase"); + if(app->mode == SPIMemModeCompare) furi_string_printf(str, "%s", "Check"); + widget_add_button_element( + app->widget, + GuiButtonTypeRight, + furi_string_get_cstr(str), + spi_mem_scene_chip_detected_widget_callback, + app); + furi_string_free(str); +} + +static void spi_mem_scene_chip_detected_set_previous_scene(SPIMemApp* app) { + uint32_t scene = SPIMemSceneStart; + if(app->mode == SPIMemModeCompare || app->mode == SPIMemModeWrite) + scene = SPIMemSceneSavedFileMenu; + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene); +} + +static void spi_mem_scene_chip_detected_set_next_scene(SPIMemApp* app) { + uint32_t scene = SPIMemSceneStart; + if(app->mode == SPIMemModeRead) scene = SPIMemSceneReadFilename; + if(app->mode == SPIMemModeWrite) scene = SPIMemSceneErase; + if(app->mode == SPIMemModeErase) scene = SPIMemSceneErase; + if(app->mode == SPIMemModeCompare) scene = SPIMemSceneVerify; + scene_manager_next_scene(app->scene_manager, scene); +} + +void spi_mem_scene_chip_detected_on_enter(void* context) { + SPIMemApp* app = context; + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Retry", spi_mem_scene_chip_detected_widget_callback, app); + spi_mem_scene_chip_detect_draw_next_button(app); + widget_add_icon_element(app->widget, 0, 12, &I_Dip8_32x36); + widget_add_string_element( + app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Detected SPI chip"); + spi_mem_scene_chip_detected_print_chip_info(app->widget, app->chip_info); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); +} + +bool spi_mem_scene_chip_detected_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + spi_mem_scene_chip_detected_set_previous_scene(app); + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SPIMemSceneChipDetect); + } else if(event.event == GuiButtonTypeRight) { + spi_mem_scene_chip_detected_set_next_scene(app); + } + } + return success; +} +void spi_mem_scene_chip_detected_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_error.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_error.c new file mode 100644 index 000000000..ca4b765a2 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_chip_error.c @@ -0,0 +1,52 @@ +#include "../spi_mem_app_i.h" + +static void + spi_mem_scene_chip_error_widget_callback(GuiButtonType result, InputType type, void* context) { + SPIMemApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void spi_mem_scene_chip_error_on_enter(void* context) { + SPIMemApp* app = context; + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_chip_error_widget_callback, app); + widget_add_string_element( + app->widget, 85, 15, AlignCenter, AlignBottom, FontPrimary, "SPI chip error"); + widget_add_string_multiline_element( + app->widget, + 85, + 52, + AlignCenter, + AlignBottom, + FontSecondary, + "Error while\ncommunicating\nwith chip"); + widget_add_icon_element(app->widget, 5, 6, &I_Dip8_32x36); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); +} + +static void spi_mem_scene_chip_error_set_previous_scene(SPIMemApp* app) { + uint32_t scene = SPIMemSceneChipDetect; + if(app->mode == SPIMemModeRead || app->mode == SPIMemModeErase) scene = SPIMemSceneStart; + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene); +} + +bool spi_mem_scene_chip_error_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + spi_mem_scene_chip_error_set_previous_scene(app); + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == GuiButtonTypeLeft) { + spi_mem_scene_chip_error_set_previous_scene(app); + } + } + return success; +} +void spi_mem_scene_chip_error_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_config.h b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_config.h new file mode 100644 index 000000000..c0e377303 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_config.h @@ -0,0 +1,21 @@ +ADD_SCENE(spi_mem, start, Start) +ADD_SCENE(spi_mem, chip_detect, ChipDetect) +ADD_SCENE(spi_mem, chip_detected, ChipDetected) +ADD_SCENE(spi_mem, chip_detect_fail, ChipDetectFail) +ADD_SCENE(spi_mem, select_file, SelectFile) +ADD_SCENE(spi_mem, saved_file_menu, SavedFileMenu) +ADD_SCENE(spi_mem, read, Read) +ADD_SCENE(spi_mem, read_filename, ReadFilename) +ADD_SCENE(spi_mem, delete_confirm, DeleteConfirm) +ADD_SCENE(spi_mem, success, Success) +ADD_SCENE(spi_mem, about, About) +ADD_SCENE(spi_mem, verify, Verify) +ADD_SCENE(spi_mem, file_info, FileInfo) +ADD_SCENE(spi_mem, erase, Erase) +ADD_SCENE(spi_mem, chip_error, ChipError) +ADD_SCENE(spi_mem, verify_error, VerifyError) +ADD_SCENE(spi_mem, write, Write) +ADD_SCENE(spi_mem, storage_error, StorageError) +ADD_SCENE(spi_mem, select_vendor, SelectVendor) +ADD_SCENE(spi_mem, select_model, SelectModel) +ADD_SCENE(spi_mem, wiring, Wiring) diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_delete_confirm.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_delete_confirm.c new file mode 100644 index 000000000..5d0c0b8d8 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_delete_confirm.c @@ -0,0 +1,62 @@ +#include "../spi_mem_app_i.h" +#include "../spi_mem_files.h" + +static void spi_mem_scene_delete_confirm_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + SPIMemApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void spi_mem_scene_delete_confirm_on_enter(void* context) { + SPIMemApp* app = context; + FuriString* file_name = furi_string_alloc(); + FuriString* message = furi_string_alloc(); + path_extract_filename(app->file_path, file_name, true); + furi_string_printf(message, "\e#Delete %s?\e#", furi_string_get_cstr(file_name)); // NOSONAR + widget_add_text_box_element( + app->widget, 0, 0, 128, 27, AlignCenter, AlignCenter, furi_string_get_cstr(message), true); + widget_add_button_element( + app->widget, + GuiButtonTypeLeft, + "Cancel", + spi_mem_scene_delete_confirm_widget_callback, + app); + widget_add_button_element( + app->widget, + GuiButtonTypeRight, + "Delete", + spi_mem_scene_delete_confirm_widget_callback, + app); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); + furi_string_free(file_name); + furi_string_free(message); +} + +bool spi_mem_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == GuiButtonTypeRight) { + app->mode = SPIMemModeDelete; + if(spi_mem_file_delete(app)) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess); + } else { + scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError); + } + } else if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SPIMemSceneSavedFileMenu); + } + } + return success; +} + +void spi_mem_scene_delete_confirm_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_erase.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_erase.c new file mode 100644 index 000000000..0d3ae66bf --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_erase.c @@ -0,0 +1,65 @@ +#include "../spi_mem_app_i.h" + +static void + spi_mem_scene_erase_widget_callback(GuiButtonType result, InputType type, void* context) { + SPIMemApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +static void spi_mem_scene_erase_callback(void* context, SPIMemCustomEventWorker event) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void spi_mem_scene_erase_on_enter(void* context) { + SPIMemApp* app = context; + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Cancel", spi_mem_scene_erase_widget_callback, app); + widget_add_string_element( + app->widget, 64, 15, AlignCenter, AlignBottom, FontPrimary, "Erasing SPI chip"); + widget_add_string_element( + app->widget, 64, 27, AlignCenter, AlignBottom, FontSecondary, "Please be patient"); + notification_message(app->notifications, &sequence_blink_start_magenta); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); + spi_mem_worker_start_thread(app->worker); + spi_mem_worker_erase_start(app->chip_info, app->worker, spi_mem_scene_erase_callback, app); +} + +static void spi_mem_scene_erase_set_previous_scene(SPIMemApp* app) { + uint32_t scene = SPIMemSceneStart; + if(app->mode == SPIMemModeWrite) scene = SPIMemSceneSavedFileMenu; + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene); +} + +static void spi_mem_scene_erase_set_next_scene(SPIMemApp* app) { + uint32_t scene = SPIMemSceneSuccess; + if(app->mode == SPIMemModeWrite) scene = SPIMemSceneWrite; + scene_manager_next_scene(app->scene_manager, scene); +} + +bool spi_mem_scene_erase_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + spi_mem_scene_erase_set_previous_scene(app); + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_previous_scene(app->scene_manager); + } else if(event.event == SPIMemCustomEventWorkerDone) { + spi_mem_scene_erase_set_next_scene(app); + } else if(event.event == SPIMemCustomEventWorkerChipFail) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError); + } + } + return success; +} +void spi_mem_scene_erase_on_exit(void* context) { + SPIMemApp* app = context; + spi_mem_worker_stop_thread(app->worker); + notification_message(app->notifications, &sequence_blink_stop); + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_file_info.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_file_info.c new file mode 100644 index 000000000..687f17f81 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_file_info.c @@ -0,0 +1,29 @@ +#include "../spi_mem_app_i.h" +#include "../spi_mem_files.h" + +void spi_mem_scene_file_info_on_enter(void* context) { + SPIMemApp* app = context; + FuriString* str = furi_string_alloc(); + furi_string_printf(str, "Size: %zu KB", spi_mem_file_get_size(app) / 1024); + widget_add_string_element( + app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "File info"); + widget_add_string_element( + app->widget, 64, 20, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str)); + furi_string_free(str); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); +} + +bool spi_mem_scene_file_info_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SPIMemSceneSavedFileMenu); + } + return success; +} +void spi_mem_scene_file_info_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_read.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_read.c new file mode 100644 index 000000000..bbf38a303 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_read.c @@ -0,0 +1,57 @@ +#include "../spi_mem_app_i.h" +#include "../spi_mem_files.h" +#include "../lib/spi/spi_mem_chip.h" +#include "../lib/spi/spi_mem_tools.h" + +void spi_mem_scene_read_progress_view_result_callback(void* context) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewReadCancel); +} + +static void spi_mem_scene_read_callback(void* context, SPIMemCustomEventWorker event) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void spi_mem_scene_read_on_enter(void* context) { + SPIMemApp* app = context; + spi_mem_view_progress_set_read_callback( + app->view_progress, spi_mem_scene_read_progress_view_result_callback, app); + notification_message(app->notifications, &sequence_blink_start_blue); + spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info)); + spi_mem_view_progress_set_block_size( + app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info)); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress); + spi_mem_worker_start_thread(app->worker); + spi_mem_worker_read_start(app->chip_info, app->worker, spi_mem_scene_read_callback, app); +} + +bool spi_mem_scene_read_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + UNUSED(app); + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == SPIMemCustomEventViewReadCancel) { + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SPIMemSceneChipDetect); + } else if(event.event == SPIMemCustomEventWorkerBlockReaded) { + spi_mem_view_progress_inc_progress(app->view_progress); + } else if(event.event == SPIMemCustomEventWorkerDone) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneVerify); + } else if(event.event == SPIMemCustomEventWorkerChipFail) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError); + } else if(event.event == SPIMemCustomEventWorkerFileFail) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError); + } + } + return success; +} +void spi_mem_scene_read_on_exit(void* context) { + SPIMemApp* app = context; + spi_mem_worker_stop_thread(app->worker); + spi_mem_view_progress_reset(app->view_progress); + notification_message(app->notifications, &sequence_blink_stop); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_read_filename.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_read_filename.c new file mode 100644 index 000000000..4b16baa2e --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_read_filename.c @@ -0,0 +1,46 @@ +#include "../spi_mem_app_i.h" +#include "../spi_mem_files.h" + +void spi_mem_scene_read_filename_view_result_callback(void* context) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventTextEditResult); +} + +void spi_mem_scene_read_set_random_filename(SPIMemApp* app) { + if(furi_string_end_with(app->file_path, SPI_MEM_FILE_EXTENSION)) { + size_t filename_start = furi_string_search_rchar(app->file_path, '/'); + furi_string_left(app->file_path, filename_start); + } + set_random_name(app->text_buffer, SPI_MEM_TEXT_BUFFER_SIZE); +} + +void spi_mem_scene_read_filename_on_enter(void* context) { + SPIMemApp* app = context; + spi_mem_scene_read_set_random_filename(app); + text_input_set_header_text(app->text_input, "Name the dump"); + text_input_set_result_callback( + app->text_input, + spi_mem_scene_read_filename_view_result_callback, + app, + app->text_buffer, + SPI_MEM_FILE_NAME_SIZE, + true); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewTextInput); +} + +bool spi_mem_scene_read_filename_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + UNUSED(app); + bool success = false; + if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == SPIMemCustomEventTextEditResult) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneRead); + } + } + return success; +} +void spi_mem_scene_read_filename_on_exit(void* context) { + SPIMemApp* app = context; + text_input_reset(app->text_input); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_saved_file_menu.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_saved_file_menu.c new file mode 100644 index 000000000..d5767455e --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_saved_file_menu.c @@ -0,0 +1,76 @@ +#include "../spi_mem_app_i.h" + +typedef enum { + SPIMemSceneSavedFileMenuSubmenuIndexWrite, + SPIMemSceneSavedFileMenuSubmenuIndexCompare, + SPIMemSceneSavedFileMenuSubmenuIndexInfo, + SPIMemSceneSavedFileMenuSubmenuIndexDelete, +} SPIMemSceneSavedFileMenuSubmenuIndex; + +static void spi_mem_scene_saved_file_menu_submenu_callback(void* context, uint32_t index) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void spi_mem_scene_saved_file_menu_on_enter(void* context) { + SPIMemApp* app = context; + submenu_add_item( + app->submenu, + "Write", + SPIMemSceneSavedFileMenuSubmenuIndexWrite, + spi_mem_scene_saved_file_menu_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Compare", + SPIMemSceneSavedFileMenuSubmenuIndexCompare, + spi_mem_scene_saved_file_menu_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Info", + SPIMemSceneSavedFileMenuSubmenuIndexInfo, + spi_mem_scene_saved_file_menu_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Delete", + SPIMemSceneSavedFileMenuSubmenuIndexDelete, + spi_mem_scene_saved_file_menu_submenu_callback, + app); + submenu_set_selected_item( + app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu)); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu); +} + +bool spi_mem_scene_saved_file_menu_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu, event.event); + if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexWrite) { + app->mode = SPIMemModeWrite; + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect); + success = true; + } + if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexCompare) { + app->mode = SPIMemModeCompare; + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect); + success = true; + } + if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexDelete) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneDeleteConfirm); + success = true; + } + if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexInfo) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneFileInfo); + success = true; + } + } + return success; +} + +void spi_mem_scene_saved_file_menu_on_exit(void* context) { + SPIMemApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_file.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_file.c new file mode 100644 index 000000000..cb48035b5 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_file.c @@ -0,0 +1,22 @@ +#include "../spi_mem_app_i.h" +#include "../spi_mem_files.h" + +void spi_mem_scene_select_file_on_enter(void* context) { + SPIMemApp* app = context; + if(spi_mem_file_select(app)) { + scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu, 0); + scene_manager_next_scene(app->scene_manager, SPIMemSceneSavedFileMenu); + } else { + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SPIMemSceneStart); + } +} + +bool spi_mem_scene_select_file_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void spi_mem_scene_select_file_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_model.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_model.c new file mode 100644 index 000000000..c39c4a182 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_model.c @@ -0,0 +1,45 @@ +#include "../spi_mem_app_i.h" + +static void spi_mem_scene_select_model_submenu_callback(void* context, uint32_t index) { + SPIMemApp* app = context; + spi_mem_chip_copy_chip_info(app->chip_info, *found_chips_get(app->found_chips, index)); + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void spi_mem_scene_select_model_on_enter(void* context) { + SPIMemApp* app = context; + size_t models_on_vendor = 0; + for(size_t index = 0; index < found_chips_size(app->found_chips); index++) { + if(spi_mem_chip_get_vendor_enum(*found_chips_get(app->found_chips, index)) != + app->chip_vendor_enum) + continue; + submenu_add_item( + app->submenu, + spi_mem_chip_get_model_name(*found_chips_get(app->found_chips, index)), + index, + spi_mem_scene_select_model_submenu_callback, + app); + models_on_vendor++; + } + if(models_on_vendor == 1) spi_mem_scene_select_model_submenu_callback(context, 0); + submenu_set_header(app->submenu, "Choose chip model"); + submenu_set_selected_item( + app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSelectVendor)); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu); +} + +bool spi_mem_scene_select_model_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, event.event); + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetected); + success = true; + } + return success; +} + +void spi_mem_scene_select_model_on_exit(void* context) { + SPIMemApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_vendor.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_vendor.c new file mode 100644 index 000000000..c7f736f88 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_select_vendor.c @@ -0,0 +1,70 @@ +#include "../spi_mem_app_i.h" +#include +#include + +ARRAY_DEF(vendors, uint32_t) +ALGO_DEF(vendors, ARRAY_OPLIST(vendors)) + +static void spi_mem_scene_select_vendor_submenu_callback(void* context, uint32_t index) { + SPIMemApp* app = context; + app->chip_vendor_enum = index; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +static void spi_mem_scene_select_vendor_sort_vendors(SPIMemApp* app, vendors_t vendors_arr) { + for(size_t index = 0; index < found_chips_size(app->found_chips); index++) { + vendors_push_back( + vendors_arr, spi_mem_chip_get_vendor_enum(*found_chips_get(app->found_chips, index))); + } + vendors_uniq(vendors_arr); +} + +void spi_mem_scene_select_vendor_on_enter(void* context) { + SPIMemApp* app = context; + vendors_t vendors_arr; + vendors_init(vendors_arr); + spi_mem_scene_select_vendor_sort_vendors(app, vendors_arr); + size_t vendors_arr_size = vendors_size(vendors_arr); + if(vendors_arr_size == 1) + spi_mem_scene_select_vendor_submenu_callback(context, *vendors_get(vendors_arr, 0)); + for(size_t index = 0; index < vendors_arr_size; index++) { + uint32_t vendor_enum = *vendors_get(vendors_arr, index); + submenu_add_item( + app->submenu, + spi_mem_chip_get_vendor_name_by_enum(vendor_enum), + vendor_enum, + spi_mem_scene_select_vendor_submenu_callback, + app); + } + vendors_clear(vendors_arr); + submenu_set_header(app->submenu, "Choose chip vendor"); + submenu_set_selected_item( + app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSelectVendor)); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu); +} + +static void spi_mem_scene_select_vendor_set_previous_scene(SPIMemApp* app) { + uint32_t scene = SPIMemSceneStart; + if(app->mode == SPIMemModeCompare || app->mode == SPIMemModeWrite) + scene = SPIMemSceneSavedFileMenu; + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene); +} + +bool spi_mem_scene_select_vendor_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + spi_mem_scene_select_vendor_set_previous_scene(app); + } else if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, event.event); + scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectModel); + success = true; + } + return success; +} + +void spi_mem_scene_select_vendor_on_exit(void* context) { + SPIMemApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_start.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_start.c new file mode 100644 index 000000000..b664df687 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_start.c @@ -0,0 +1,84 @@ +#include "../spi_mem_app_i.h" + +typedef enum { + SPIMemSceneStartSubmenuIndexRead, + SPIMemSceneStartSubmenuIndexSaved, + SPIMemSceneStartSubmenuIndexErase, + SPIMemSceneStartSubmenuIndexWiring, + SPIMemSceneStartSubmenuIndexAbout +} SPIMemSceneStartSubmenuIndex; + +static void spi_mem_scene_start_submenu_callback(void* context, uint32_t index) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void spi_mem_scene_start_on_enter(void* context) { + SPIMemApp* app = context; + submenu_add_item( + app->submenu, + "Read", + SPIMemSceneStartSubmenuIndexRead, + spi_mem_scene_start_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Saved", + SPIMemSceneStartSubmenuIndexSaved, + spi_mem_scene_start_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Erase", + SPIMemSceneStartSubmenuIndexErase, + spi_mem_scene_start_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Wiring", + SPIMemSceneStartSubmenuIndexWiring, + spi_mem_scene_start_submenu_callback, + app); + submenu_add_item( + app->submenu, + "About", + SPIMemSceneStartSubmenuIndexAbout, + spi_mem_scene_start_submenu_callback, + app); + submenu_set_selected_item( + app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneStart)); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu); +} + +bool spi_mem_scene_start_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(app->scene_manager, SPIMemSceneStart, event.event); + if(event.event == SPIMemSceneStartSubmenuIndexRead) { + app->mode = SPIMemModeRead; + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect); + success = true; + } else if(event.event == SPIMemSceneStartSubmenuIndexSaved) { + furi_string_set(app->file_path, SPI_MEM_FILE_FOLDER); + scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectFile); + success = true; + } else if(event.event == SPIMemSceneStartSubmenuIndexErase) { + app->mode = SPIMemModeErase; + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect); + success = true; + } else if(event.event == SPIMemSceneStartSubmenuIndexWiring) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneWiring); + success = true; + } else if(event.event == SPIMemSceneStartSubmenuIndexAbout) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneAbout); + success = true; + } + } + return success; +} + +void spi_mem_scene_start_on_exit(void* context) { + SPIMemApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_storage_error.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_storage_error.c new file mode 100644 index 000000000..d5e289e24 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_storage_error.c @@ -0,0 +1,56 @@ +#include "../spi_mem_app_i.h" + +static void spi_mem_scene_storage_error_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + SPIMemApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void spi_mem_scene_storage_error_on_enter(void* context) { + SPIMemApp* app = context; + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_storage_error_widget_callback, app); + widget_add_string_element( + app->widget, 85, 15, AlignCenter, AlignBottom, FontPrimary, "Storage error"); + widget_add_string_multiline_element( + app->widget, + 85, + 52, + AlignCenter, + AlignBottom, + FontSecondary, + "Error while\nworking with\nfilesystem"); + widget_add_icon_element(app->widget, 5, 6, &I_SDQuestion_35x43); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); +} + +static void spi_mem_scene_storage_error_set_previous_scene(SPIMemApp* app) { + uint32_t scene = SPIMemSceneChipDetect; + if(app->mode == SPIMemModeRead) scene = SPIMemSceneStart; + if(app->mode == SPIMemModeErase) scene = SPIMemSceneStart; + if(app->mode == SPIMemModeDelete) scene = SPIMemSceneStart; + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene); +} + +bool spi_mem_scene_storage_error_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + spi_mem_scene_storage_error_set_previous_scene(app); + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == GuiButtonTypeLeft) { + spi_mem_scene_storage_error_set_previous_scene(app); + } + } + return success; +} +void spi_mem_scene_storage_error_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_success.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_success.c new file mode 100644 index 000000000..39039466f --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_success.c @@ -0,0 +1,40 @@ +#include "../spi_mem_app_i.h" + +static void spi_mem_scene_success_popup_callback(void* context) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventPopupBack); +} + +void spi_mem_scene_success_on_enter(void* context) { + SPIMemApp* app = context; + popup_set_icon(app->popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(app->popup, "Success!", 5, 7, AlignLeft, AlignTop); + popup_set_callback(app->popup, spi_mem_scene_success_popup_callback); + popup_set_context(app->popup, app); + popup_set_timeout(app->popup, 1500); + popup_enable_timeout(app->popup); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewPopup); +} + +static void spi_mem_scene_success_set_previous_scene(SPIMemApp* app) { + uint32_t scene = SPIMemSceneSelectFile; + if(app->mode == SPIMemModeErase) scene = SPIMemSceneStart; + scene_manager_search_and_switch_to_another_scene(app->scene_manager, scene); +} + +bool spi_mem_scene_success_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == SPIMemCustomEventPopupBack) { + spi_mem_scene_success_set_previous_scene(app); + } + } + return success; +} + +void spi_mem_scene_success_on_exit(void* context) { + SPIMemApp* app = context; + popup_reset(app->popup); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_verify.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_verify.c new file mode 100644 index 000000000..08a8d1057 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_verify.c @@ -0,0 +1,59 @@ +#include "../spi_mem_app_i.h" +#include "../spi_mem_files.h" +#include "../lib/spi/spi_mem_chip.h" +#include "../lib/spi/spi_mem_tools.h" + +void spi_mem_scene_verify_view_result_callback(void* context) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewVerifySkip); +} + +static void spi_mem_scene_verify_callback(void* context, SPIMemCustomEventWorker event) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void spi_mem_scene_verify_on_enter(void* context) { + SPIMemApp* app = context; + spi_mem_view_progress_set_verify_callback( + app->view_progress, spi_mem_scene_verify_view_result_callback, app); + notification_message(app->notifications, &sequence_blink_start_cyan); + spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info)); + spi_mem_view_progress_set_file_size(app->view_progress, spi_mem_file_get_size(app)); + spi_mem_view_progress_set_block_size( + app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info)); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress); + spi_mem_worker_start_thread(app->worker); + spi_mem_worker_verify_start(app->chip_info, app->worker, spi_mem_scene_verify_callback, app); +} + +bool spi_mem_scene_verify_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + UNUSED(app); + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == SPIMemCustomEventViewVerifySkip) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess); + } else if(event.event == SPIMemCustomEventWorkerBlockReaded) { + spi_mem_view_progress_inc_progress(app->view_progress); + } else if(event.event == SPIMemCustomEventWorkerChipFail) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError); + } else if(event.event == SPIMemCustomEventWorkerFileFail) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError); + } else if(event.event == SPIMemCustomEventWorkerDone) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess); + } else if(event.event == SPIMemCustomEventWorkerVerifyFail) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneVerifyError); + } + } + return success; +} +void spi_mem_scene_verify_on_exit(void* context) { + SPIMemApp* app = context; + spi_mem_worker_stop_thread(app->worker); + spi_mem_view_progress_reset(app->view_progress); + notification_message(app->notifications, &sequence_blink_stop); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_verify_error.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_verify_error.c new file mode 100644 index 000000000..fbe954fa6 --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_verify_error.c @@ -0,0 +1,43 @@ +#include "../spi_mem_app_i.h" + +static void spi_mem_scene_verify_error_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + SPIMemApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void spi_mem_scene_verify_error_on_enter(void* context) { + SPIMemApp* app = context; + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_verify_error_widget_callback, app); + widget_add_string_element( + app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Verification error"); + widget_add_string_element( + app->widget, 64, 21, AlignCenter, AlignBottom, FontSecondary, "Data mismatch"); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); +} + +bool spi_mem_scene_verify_error_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SPIMemSceneChipDetect); + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SPIMemSceneChipDetect); + } + } + return success; +} +void spi_mem_scene_verify_error_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_wiring.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_wiring.c new file mode 100644 index 000000000..22036f4bc --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_wiring.c @@ -0,0 +1,18 @@ +#include "../spi_mem_app_i.h" +#include "../lib/spi/spi_mem_chip.h" + +void spi_mem_scene_wiring_on_enter(void* context) { + SPIMemApp* app = context; + widget_add_icon_element(app->widget, 0, 0, &I_Wiring_SPI_128x64); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget); +} + +bool spi_mem_scene_wiring_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} +void spi_mem_scene_wiring_on_exit(void* context) { + SPIMemApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_write.c b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_write.c new file mode 100644 index 000000000..dfa384fbb --- /dev/null +++ b/applications/plugins/spi_mem_manager/scenes/spi_mem_scene_write.c @@ -0,0 +1,58 @@ +#include "../spi_mem_app_i.h" +#include "../spi_mem_files.h" +#include "../lib/spi/spi_mem_chip.h" +#include "../lib/spi/spi_mem_tools.h" + +void spi_mem_scene_write_progress_view_result_callback(void* context) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewReadCancel); +} + +static void spi_mem_scene_write_callback(void* context, SPIMemCustomEventWorker event) { + SPIMemApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void spi_mem_scene_write_on_enter(void* context) { + SPIMemApp* app = context; + spi_mem_view_progress_set_write_callback( + app->view_progress, spi_mem_scene_write_progress_view_result_callback, app); + notification_message(app->notifications, &sequence_blink_start_cyan); + spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info)); + spi_mem_view_progress_set_file_size(app->view_progress, spi_mem_file_get_size(app)); + spi_mem_view_progress_set_block_size( + app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info)); + view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress); + spi_mem_worker_start_thread(app->worker); + spi_mem_worker_write_start(app->chip_info, app->worker, spi_mem_scene_write_callback, app); +} + +bool spi_mem_scene_write_on_event(void* context, SceneManagerEvent event) { + SPIMemApp* app = context; + UNUSED(app); + bool success = false; + if(event.type == SceneManagerEventTypeBack) { + success = true; + } else if(event.type == SceneManagerEventTypeCustom) { + success = true; + if(event.event == SPIMemCustomEventViewReadCancel) { + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SPIMemSceneChipDetect); + } else if(event.event == SPIMemCustomEventWorkerBlockReaded) { + spi_mem_view_progress_inc_progress(app->view_progress); + } else if(event.event == SPIMemCustomEventWorkerDone) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneVerify); + } else if(event.event == SPIMemCustomEventWorkerChipFail) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError); + } else if(event.event == SPIMemCustomEventWorkerFileFail) { + scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError); + } + } + return success; +} +void spi_mem_scene_write_on_exit(void* context) { + SPIMemApp* app = context; + spi_mem_worker_stop_thread(app->worker); + spi_mem_view_progress_reset(app->view_progress); + notification_message(app->notifications, &sequence_blink_stop); +} diff --git a/applications/plugins/spi_mem_manager/spi_mem_app.c b/applications/plugins/spi_mem_manager/spi_mem_app.c new file mode 100644 index 000000000..63531b74c --- /dev/null +++ b/applications/plugins/spi_mem_manager/spi_mem_app.c @@ -0,0 +1,112 @@ +#include +#include "spi_mem_app_i.h" +#include "spi_mem_files.h" +#include "lib/spi/spi_mem_chip_i.h" + +static bool spi_mem_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + SPIMemApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool spi_mem_back_event_callback(void* context) { + furi_assert(context); + SPIMemApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +SPIMemApp* spi_mem_alloc(void) { + SPIMemApp* instance = malloc(sizeof(SPIMemApp)); + + instance->file_path = furi_string_alloc(); + instance->gui = furi_record_open(RECORD_GUI); + instance->notifications = furi_record_open(RECORD_NOTIFICATION); + instance->view_dispatcher = view_dispatcher_alloc(); + instance->scene_manager = scene_manager_alloc(&spi_mem_scene_handlers, instance); + instance->submenu = submenu_alloc(); + instance->dialog_ex = dialog_ex_alloc(); + instance->popup = popup_alloc(); + instance->worker = spi_mem_worker_alloc(); + instance->dialogs = furi_record_open(RECORD_DIALOGS); + instance->storage = furi_record_open(RECORD_STORAGE); + instance->widget = widget_alloc(); + instance->chip_info = malloc(sizeof(SPIMemChip)); + found_chips_init(instance->found_chips); + instance->view_progress = spi_mem_view_progress_alloc(); + instance->view_detect = spi_mem_view_detect_alloc(); + instance->text_input = text_input_alloc(); + instance->mode = SPIMemModeUnknown; + + furi_string_set(instance->file_path, SPI_MEM_FILE_FOLDER); + + view_dispatcher_enable_queue(instance->view_dispatcher); + view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); + view_dispatcher_set_custom_event_callback( + instance->view_dispatcher, spi_mem_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + instance->view_dispatcher, spi_mem_back_event_callback); + view_dispatcher_attach_to_gui( + instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_add_view( + instance->view_dispatcher, SPIMemViewSubmenu, submenu_get_view(instance->submenu)); + view_dispatcher_add_view( + instance->view_dispatcher, SPIMemViewDialogEx, dialog_ex_get_view(instance->dialog_ex)); + view_dispatcher_add_view( + instance->view_dispatcher, SPIMemViewPopup, popup_get_view(instance->popup)); + view_dispatcher_add_view( + instance->view_dispatcher, SPIMemViewWidget, widget_get_view(instance->widget)); + view_dispatcher_add_view( + instance->view_dispatcher, + SPIMemViewProgress, + spi_mem_view_progress_get_view(instance->view_progress)); + view_dispatcher_add_view( + instance->view_dispatcher, + SPIMemViewDetect, + spi_mem_view_detect_get_view(instance->view_detect)); + view_dispatcher_add_view( + instance->view_dispatcher, SPIMemViewTextInput, text_input_get_view(instance->text_input)); + + furi_hal_power_enable_otg(); + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_external); + scene_manager_next_scene(instance->scene_manager, SPIMemSceneStart); + return instance; +} + +void spi_mem_free(SPIMemApp* instance) { + view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewSubmenu); + view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewDialogEx); + view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewPopup); + view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewWidget); + view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewProgress); + view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewDetect); + view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewTextInput); + spi_mem_view_progress_free(instance->view_progress); + spi_mem_view_detect_free(instance->view_detect); + submenu_free(instance->submenu); + dialog_ex_free(instance->dialog_ex); + popup_free(instance->popup); + widget_free(instance->widget); + text_input_free(instance->text_input); + view_dispatcher_free(instance->view_dispatcher); + scene_manager_free(instance->scene_manager); + spi_mem_worker_free(instance->worker); + free(instance->chip_info); + found_chips_clear(instance->found_chips); + furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_NOTIFICATION); + furi_record_close(RECORD_GUI); + furi_string_free(instance->file_path); + furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_external); + furi_hal_power_disable_otg(); + free(instance); +} + +int32_t spi_mem_app(void* p) { + UNUSED(p); + SPIMemApp* instance = spi_mem_alloc(); + spi_mem_file_create_folder(instance); + view_dispatcher_run(instance->view_dispatcher); + spi_mem_free(instance); + return 0; +} diff --git a/applications/plugins/spi_mem_manager/spi_mem_app.h b/applications/plugins/spi_mem_manager/spi_mem_app.h new file mode 100644 index 000000000..37ac927db --- /dev/null +++ b/applications/plugins/spi_mem_manager/spi_mem_app.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct SPIMemApp SPIMemApp; diff --git a/applications/plugins/spi_mem_manager/spi_mem_app_i.h b/applications/plugins/spi_mem_manager/spi_mem_app_i.h new file mode 100644 index 000000000..4ce056175 --- /dev/null +++ b/applications/plugins/spi_mem_manager/spi_mem_app_i.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include "spi_mem_app.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scenes/spi_mem_scene.h" +#include "lib/spi/spi_mem_worker.h" +#include "spi_mem_manager_icons.h" +#include "views/spi_mem_view_progress.h" +#include "views/spi_mem_view_detect.h" + +#define TAG "SPIMem" +#define SPI_MEM_FILE_EXTENSION ".bin" +#define SPI_MEM_FILE_FOLDER EXT_PATH("spimem") +#define SPI_MEM_FILE_NAME_SIZE 100 +#define SPI_MEM_TEXT_BUFFER_SIZE 128 + +typedef enum { + SPIMemModeRead, + SPIMemModeWrite, + SPIMemModeCompare, + SPIMemModeErase, + SPIMemModeDelete, + SPIMemModeUnknown +} SPIMemMode; + +struct SPIMemApp { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + Submenu* submenu; + DialogEx* dialog_ex; + Popup* popup; + NotificationApp* notifications; + FuriString* file_path; + DialogsApp* dialogs; + Storage* storage; + File* file; + Widget* widget; + SPIMemWorker* worker; + SPIMemChip* chip_info; + found_chips_t found_chips; + uint32_t chip_vendor_enum; + SPIMemProgressView* view_progress; + SPIMemDetectView* view_detect; + TextInput* text_input; + SPIMemMode mode; + char text_buffer[SPI_MEM_TEXT_BUFFER_SIZE + 1]; +}; + +typedef enum { + SPIMemViewSubmenu, + SPIMemViewDialogEx, + SPIMemViewPopup, + SPIMemViewWidget, + SPIMemViewTextInput, + SPIMemViewProgress, + SPIMemViewDetect +} SPIMemView; + +typedef enum { + SPIMemCustomEventViewReadCancel, + SPIMemCustomEventViewVerifySkip, + SPIMemCustomEventTextEditResult, + SPIMemCustomEventPopupBack +} SPIMemCustomEvent; diff --git a/applications/plugins/spi_mem_manager/spi_mem_files.c b/applications/plugins/spi_mem_manager/spi_mem_files.c new file mode 100644 index 000000000..a7374da19 --- /dev/null +++ b/applications/plugins/spi_mem_manager/spi_mem_files.c @@ -0,0 +1,74 @@ +#include "spi_mem_app_i.h" + +void spi_mem_file_create_folder(SPIMemApp* app) { + if(!storage_simply_mkdir(app->storage, SPI_MEM_FILE_FOLDER)) { + dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder"); + } +} + +bool spi_mem_file_delete(SPIMemApp* app) { + return (storage_simply_remove(app->storage, furi_string_get_cstr(app->file_path))); +} + +bool spi_mem_file_select(SPIMemApp* app) { + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, SPI_MEM_FILE_EXTENSION, &I_Dip8_10px); + browser_options.base_path = SPI_MEM_FILE_FOLDER; + bool success = + dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); + return success; +} + +bool spi_mem_file_create_open(SPIMemApp* app) { + bool success = false; + app->file = storage_file_alloc(app->storage); + do { + if(furi_string_end_with(app->file_path, SPI_MEM_FILE_EXTENSION)) { + if(!spi_mem_file_delete(app)) break; + size_t filename_start = furi_string_search_rchar(app->file_path, '/'); + furi_string_left(app->file_path, filename_start); + } + furi_string_cat_printf(app->file_path, "/%s%s", app->text_buffer, SPI_MEM_FILE_EXTENSION); + if(!storage_file_open( + app->file, furi_string_get_cstr(app->file_path), FSAM_WRITE, FSOM_CREATE_NEW)) + break; + success = true; + } while(0); + if(!success) { //-V547 + dialog_message_show_storage_error(app->dialogs, "Cannot save\nfile"); + } + return success; +} + +bool spi_mem_file_open(SPIMemApp* app) { + app->file = storage_file_alloc(app->storage); + if(!storage_file_open( + app->file, furi_string_get_cstr(app->file_path), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) { + dialog_message_show_storage_error(app->dialogs, "Cannot save\nfile"); + return false; + } + return true; +} + +bool spi_mem_file_write_block(SPIMemApp* app, uint8_t* data, size_t size) { + if(storage_file_write(app->file, data, size) != size) return false; + return true; +} + +bool spi_mem_file_read_block(SPIMemApp* app, uint8_t* data, size_t size) { + if(storage_file_read(app->file, data, size) != size) return false; + return true; +} + +void spi_mem_file_close(SPIMemApp* app) { + storage_file_close(app->file); + storage_file_free(app->file); +} + +size_t spi_mem_file_get_size(SPIMemApp* app) { + FileInfo file_info; + if(storage_common_stat(app->storage, furi_string_get_cstr(app->file_path), &file_info) != + FSE_OK) + return 0; + return file_info.size; +} diff --git a/applications/plugins/spi_mem_manager/spi_mem_files.h b/applications/plugins/spi_mem_manager/spi_mem_files.h new file mode 100644 index 000000000..0e735d951 --- /dev/null +++ b/applications/plugins/spi_mem_manager/spi_mem_files.h @@ -0,0 +1,14 @@ +#pragma once +#include "spi_mem_app.h" + +void spi_mem_file_create_folder(SPIMemApp* app); +bool spi_mem_file_select(SPIMemApp* app); +bool spi_mem_file_create(SPIMemApp* app, const char* file_name); +bool spi_mem_file_delete(SPIMemApp* app); +bool spi_mem_file_create_open(SPIMemApp* app); +bool spi_mem_file_open(SPIMemApp* app); +bool spi_mem_file_write_block(SPIMemApp* app, uint8_t* data, size_t size); +bool spi_mem_file_read_block(SPIMemApp* app, uint8_t* data, size_t size); +void spi_mem_file_close(SPIMemApp* app); +void spi_mem_file_show_storage_error(SPIMemApp* app, const char* error_text); +size_t spi_mem_file_get_size(SPIMemApp* app); diff --git a/applications/plugins/spi_mem_manager/tools/README.md b/applications/plugins/spi_mem_manager/tools/README.md new file mode 100644 index 000000000..91080941f --- /dev/null +++ b/applications/plugins/spi_mem_manager/tools/README.md @@ -0,0 +1,7 @@ +This utility can convert nofeletru's UsbAsp-flash's chiplist.xml to C array + +Usage: +```bash + ./chiplist_convert.py chiplist/chiplist.xml + mv spi_mem_chip_arr.c ../lib/spi/spi_mem_chip_arr.c +``` diff --git a/applications/plugins/spi_mem_manager/tools/chiplist/LICENSE b/applications/plugins/spi_mem_manager/tools/chiplist/LICENSE new file mode 100644 index 000000000..56364f150 --- /dev/null +++ b/applications/plugins/spi_mem_manager/tools/chiplist/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 nofeletru + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/applications/plugins/spi_mem_manager/tools/chiplist/chiplist.xml b/applications/plugins/spi_mem_manager/tools/chiplist/chiplist.xml new file mode 100644 index 000000000..91a654743 --- /dev/null +++ b/applications/plugins/spi_mem_manager/tools/chiplist/chiplist.xml @@ -0,0 +1,984 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_25AA010A page="16" size="128" spicmd="95"/> + <_25AA020A page="16" size="256" spicmd="95"/> + <_25AA040 page="16" size="512" spicmd="95"/> + <_25AA040A page="16" size="512" spicmd="95"/> + <_25AA080 page="16" size="1024" spicmd="95"/> + <_25AA080A page="16" size="1024" spicmd="95"/> + <_25AA080B page="32" size="1024" spicmd="95"/> + <_25AA080C page="16" size="1024" spicmd="95"/> + <_25AA080D page="32" size="1024" spicmd="95"/> + <_25AA1024 page="256" size="131072" spicmd="95"/> + <_25AA128 page="64" size="16384" spicmd="95"/> + <_25AA160 page="16" size="2048" spicmd="95"/> + <_25AA160A page="16" size="2048" spicmd="95"/> + <_25AA160B page="32" size="2048" spicmd="95"/> + <_25AA256 page="64" size="32768" spicmd="95"/> + <_25AA320 page="32" size="4096" spicmd="95"/> + <_25AA512 page="128" size="65536" spicmd="95"/> + <_25AA640 page="32" size="8192" spicmd="95"/> + <_25C040 page="16" size="512" spicmd="95"/> + <_25C080 page="16" size="1024" spicmd="95"/> + <_25C160 page="16" size="2048" spicmd="95"/> + <_25C320 page="32" size="4096" spicmd="95"/> + <_25C640 page="32" size="8192" spicmd="95"/> + <_25LC010A page="16" size="128" spicmd="95"/> + <_25LC020A page="16" size="256" spicmd="95"/> + <_25LC040 page="16" size="512" spicmd="95"/> + <_25LC040A page="16" size="512" spicmd="95"/> + <_25LC080 page="16" size="1024" spicmd="95"/> + <_25LC080A page="16" size="1024" spicmd="95"/> + <_25LC080B page="32" size="1024" spicmd="95"/> + <_25LC080C page="16" size="1024" spicmd="95"/> + <_25LC080D page="32" size="1024" spicmd="95"/> + <_25LC1024 page="256" size="131072" spicmd="95"/> + <_25LC128 page="64" size="16384" spicmd="95"/> + <_25LC160 page="16" size="2048" spicmd="95"/> + <_25LC160A page="16" size="2048" spicmd="95"/> + <_25LC160B page="32" size="2048" spicmd="95"/> + <_25LC256 page="64" size="32768" spicmd="95"/> + <_25LC320 page="32" size="4096" spicmd="95"/> + <_25LC512 page="128" size="65536" spicmd="95"/> + <_25LC640 page="32" size="8192" spicmd="95"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_24Cxxx> + + <_24C01 page="1" size="128" addrtype="1"/> + <_24C02 page="1" size="256" addrtype="1"/> + <_24C04 page="1" size="512" addrtype="2"/> + <_24C08 page="16" size="1024" addrtype="3"/> + <_24C16 page="16" size="2048" addrtype="4"/> + <_24C32 page="32" size="4096" addrtype="5"/> + <_24C64 page="32" size="8192" addrtype="5"/> + <_24C128 page="64" size="16384" addrtype="5"/> + <_24C256 page="64" size="32768" addrtype="5"/> + <_24C512 page="128" size="65536" addrtype="5"/> + <_24C1024 page="128" size="131072" addrtype="6"/> + + + + + + + + + + + + + diff --git a/applications/plugins/spi_mem_manager/tools/chiplist_convert.py b/applications/plugins/spi_mem_manager/tools/chiplist_convert.py new file mode 100755 index 000000000..8b623eb3e --- /dev/null +++ b/applications/plugins/spi_mem_manager/tools/chiplist_convert.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 + +import argparse +import xml.etree.ElementTree as XML +import sys + + +def getArgs(): + parser = argparse.ArgumentParser( + description="chiplist.xml to C array converter", + ) + parser.add_argument("file", help="chiplist.xml file") + return parser.parse_args() + + +def getXML(file): + tree = XML.parse(file) + root = tree.getroot() + return root + + +def parseChip(cur, arr, vendor, vendorCodeArr): + chip = {} + chipAttr = cur.attrib + if "page" not in chipAttr: # chip without page size not supported + return + if "id" not in chipAttr: # I2C not supported yet + return + if len(chipAttr["id"]) < 6: # ID wihout capacity id not supported yet + return + chip["modelName"] = cur.tag + chip["vendorEnum"] = "SPIMemChipVendor" + vendor + chip["vendorID"] = "0x" + chipAttr["id"][0] + chipAttr["id"][1] + chip["typeID"] = chipAttr["id"][2] + chipAttr["id"][3] + chip["capacityID"] = chipAttr["id"][4] + chipAttr["id"][5] + chip["size"] = chipAttr["size"] + if chipAttr["page"] == "SSTW": + chip["writeMode"] = "SPIMemChipWriteModeAAIWord" + chip["pageSize"] = "1" + elif chipAttr["page"] == "SSTB": + chip["writeMode"] = "SPIMemChipWriteModeAAIByte" + chip["pageSize"] = "1" + else: + chip["writeMode"] = "SPIMemChipWriteModePage" + chip["pageSize"] = chipAttr["page"] + arr.append(chip) + vendorCodeArr[vendor].add(chip["vendorID"]) + + +def cleanEmptyVendors(vendors): + for cur in list(vendors): + if not vendors[cur]: + vendors.pop(cur) + + +def getVendors(xml, interface): + arr = {} + for cur in xml.find(interface): + arr[cur.tag] = set() + return arr + + +def parseXML(xml, interface, vendorCodeArr): + arr = [] + for vendor in xml.find(interface): + for cur in vendor: + parseChip(cur, arr, vendor.tag, vendorCodeArr) + return arr + + +def getVendorNameEnum(vendorID): + try: + return vendors[vendorID] + except: + print("Unknown vendor: " + vendorID) + sys.exit(1) + + +def generateCArr(arr, filename): + with open(filename, "w") as out: + print('#include "spi_mem_chip_i.h"', file=out) + print("const SPIMemChip SPIMemChips[] = {", file=out) + for cur in arr: + print(" {" + cur["vendorID"] + ",", file=out, end="") + print(" 0x" + cur["typeID"] + ",", file=out, end="") + print(" 0x" + cur["capacityID"] + ",", file=out, end="") + print(' "' + cur["modelName"] + '",', file=out, end="") + print(" " + cur["size"] + ",", file=out, end="") + print(" " + cur["pageSize"] + ",", file=out, end="") + print(" " + cur["vendorEnum"] + ",", file=out, end="") + if cur == arr[-1]: + print(" " + cur["writeMode"] + "}};", file=out) + else: + print(" " + cur["writeMode"] + "},", file=out) + +def main(): + filename = "spi_mem_chip_arr.c" + args = getArgs() + xml = getXML(args.file) + vendors = getVendors(xml, "SPI") + chipArr = parseXML(xml, "SPI", vendors) + cleanEmptyVendors(vendors) + for cur in vendors: + print(' {"' + cur + '", SPIMemChipVendor' + cur + "},") + generateCArr(chipArr, filename) + + +if __name__ == "__main__": + main() diff --git a/applications/plugins/spi_mem_manager/views/spi_mem_view_detect.c b/applications/plugins/spi_mem_manager/views/spi_mem_view_detect.c new file mode 100644 index 000000000..eddf36e49 --- /dev/null +++ b/applications/plugins/spi_mem_manager/views/spi_mem_view_detect.c @@ -0,0 +1,64 @@ +#include "spi_mem_view_detect.h" +#include "spi_mem_manager_icons.h" +#include + +struct SPIMemDetectView { + View* view; + IconAnimation* icon; + SPIMemDetectViewCallback callback; + void* cb_ctx; +}; + +typedef struct { + IconAnimation* icon; +} SPIMemDetectViewModel; + +View* spi_mem_view_detect_get_view(SPIMemDetectView* app) { + return app->view; +} + +static void spi_mem_view_detect_draw_callback(Canvas* canvas, void* context) { + SPIMemDetectViewModel* model = context; + canvas_set_font(canvas, FontPrimary); + canvas_draw_icon_animation(canvas, 0, 0, model->icon); + canvas_draw_str_aligned(canvas, 64, 26, AlignLeft, AlignCenter, "Detecting"); + canvas_draw_str_aligned(canvas, 64, 36, AlignLeft, AlignCenter, "SPI chip..."); +} + +static void spi_mem_view_detect_enter_callback(void* context) { + SPIMemDetectView* app = context; + with_view_model( + app->view, SPIMemDetectViewModel * model, { icon_animation_start(model->icon); }, false); +} + +static void spi_mem_view_detect_exit_callback(void* context) { + SPIMemDetectView* app = context; + with_view_model( + app->view, SPIMemDetectViewModel * model, { icon_animation_stop(model->icon); }, false); +} + +SPIMemDetectView* spi_mem_view_detect_alloc() { + SPIMemDetectView* app = malloc(sizeof(SPIMemDetectView)); + app->view = view_alloc(); + view_set_context(app->view, app); + view_allocate_model(app->view, ViewModelTypeLocking, sizeof(SPIMemDetectViewModel)); + with_view_model( + app->view, + SPIMemDetectViewModel * model, + { + model->icon = icon_animation_alloc(&A_ChipLooking_64x64); + view_tie_icon_animation(app->view, model->icon); + }, + false); + view_set_draw_callback(app->view, spi_mem_view_detect_draw_callback); + view_set_enter_callback(app->view, spi_mem_view_detect_enter_callback); + view_set_exit_callback(app->view, spi_mem_view_detect_exit_callback); + return app; +} + +void spi_mem_view_detect_free(SPIMemDetectView* app) { + with_view_model( + app->view, SPIMemDetectViewModel * model, { icon_animation_free(model->icon); }, false); + view_free(app->view); + free(app); +} diff --git a/applications/plugins/spi_mem_manager/views/spi_mem_view_detect.h b/applications/plugins/spi_mem_manager/views/spi_mem_view_detect.h new file mode 100644 index 000000000..f95edb60d --- /dev/null +++ b/applications/plugins/spi_mem_manager/views/spi_mem_view_detect.h @@ -0,0 +1,9 @@ +#pragma once +#include + +typedef struct SPIMemDetectView SPIMemDetectView; +typedef void (*SPIMemDetectViewCallback)(void* context); + +View* spi_mem_view_detect_get_view(SPIMemDetectView* app); +SPIMemDetectView* spi_mem_view_detect_alloc(); +void spi_mem_view_detect_free(SPIMemDetectView* app); diff --git a/applications/plugins/spi_mem_manager/views/spi_mem_view_progress.c b/applications/plugins/spi_mem_manager/views/spi_mem_view_progress.c new file mode 100644 index 000000000..790f97997 --- /dev/null +++ b/applications/plugins/spi_mem_manager/views/spi_mem_view_progress.c @@ -0,0 +1,230 @@ +#include "spi_mem_view_progress.h" +#include + +struct SPIMemProgressView { + View* view; + SPIMemProgressViewCallback callback; + void* cb_ctx; +}; + +typedef enum { + SPIMemProgressViewTypeRead, + SPIMemProgressViewTypeVerify, + SPIMemProgressViewTypeWrite, + SPIMemProgressViewTypeUnknown +} SPIMemProgressViewType; + +typedef struct { + size_t chip_size; + size_t file_size; + size_t blocks_written; + size_t block_size; + float progress; + SPIMemProgressViewType view_type; +} SPIMemProgressViewModel; + +View* spi_mem_view_progress_get_view(SPIMemProgressView* app) { + return app->view; +} + +static void spi_mem_view_progress_draw_progress(Canvas* canvas, float progress) { + FuriString* progress_str = furi_string_alloc(); + if(progress > 1.0) progress = 1.0; + furi_string_printf(progress_str, "%d %%", (int)(progress * 100)); + elements_progress_bar(canvas, 13, 35, 100, progress); + canvas_draw_str_aligned( + canvas, 64, 25, AlignCenter, AlignTop, furi_string_get_cstr(progress_str)); + furi_string_free(progress_str); +} + +static void + spi_mem_view_progress_read_draw_callback(Canvas* canvas, SPIMemProgressViewModel* model) { + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Reading dump"); + spi_mem_view_progress_draw_progress(canvas, model->progress); + elements_button_left(canvas, "Cancel"); +} + +static void + spi_mem_view_progress_draw_size_warning(Canvas* canvas, SPIMemProgressViewModel* model) { + if(model->file_size > model->chip_size) { + canvas_draw_str_aligned(canvas, 64, 13, AlignCenter, AlignTop, "Size clamped to chip!"); + } + if(model->chip_size > model->file_size) { + canvas_draw_str_aligned(canvas, 64, 13, AlignCenter, AlignTop, "Size clamped to file!"); + } +} + +static void + spi_mem_view_progress_verify_draw_callback(Canvas* canvas, SPIMemProgressViewModel* model) { + canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Verifying dump"); + spi_mem_view_progress_draw_size_warning(canvas, model); + spi_mem_view_progress_draw_progress(canvas, model->progress); + elements_button_center(canvas, "Skip"); +} + +static void + spi_mem_view_progress_write_draw_callback(Canvas* canvas, SPIMemProgressViewModel* model) { + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Writing dump"); + spi_mem_view_progress_draw_size_warning(canvas, model); + spi_mem_view_progress_draw_progress(canvas, model->progress); + elements_button_left(canvas, "Cancel"); +} + +static void spi_mem_view_progress_draw_callback(Canvas* canvas, void* context) { + SPIMemProgressViewModel* model = context; + SPIMemProgressViewType view_type = model->view_type; + if(view_type == SPIMemProgressViewTypeRead) { + spi_mem_view_progress_read_draw_callback(canvas, model); + } else if(view_type == SPIMemProgressViewTypeVerify) { + spi_mem_view_progress_verify_draw_callback(canvas, model); + } else if(view_type == SPIMemProgressViewTypeWrite) { + spi_mem_view_progress_write_draw_callback(canvas, model); + } +} + +static bool + spi_mem_view_progress_read_write_input_callback(InputEvent* event, SPIMemProgressView* app) { + bool success = false; + if(event->type == InputTypeShort && event->key == InputKeyLeft) { + if(app->callback) { + app->callback(app->cb_ctx); + } + success = true; + } + return success; +} + +static bool + spi_mem_view_progress_verify_input_callback(InputEvent* event, SPIMemProgressView* app) { + bool success = false; + if(event->type == InputTypeShort && event->key == InputKeyOk) { + if(app->callback) { + app->callback(app->cb_ctx); + } + success = true; + } + return success; +} + +static bool spi_mem_view_progress_input_callback(InputEvent* event, void* context) { + SPIMemProgressView* app = context; + bool success = false; + SPIMemProgressViewType view_type; + with_view_model( + app->view, SPIMemProgressViewModel * model, { view_type = model->view_type; }, true); + if(view_type == SPIMemProgressViewTypeRead) { + success = spi_mem_view_progress_read_write_input_callback(event, app); + } else if(view_type == SPIMemProgressViewTypeVerify) { + success = spi_mem_view_progress_verify_input_callback(event, app); + } else if(view_type == SPIMemProgressViewTypeWrite) { + success = spi_mem_view_progress_read_write_input_callback(event, app); + } + return success; +} + +SPIMemProgressView* spi_mem_view_progress_alloc() { + SPIMemProgressView* app = malloc(sizeof(SPIMemProgressView)); + app->view = view_alloc(); + view_allocate_model(app->view, ViewModelTypeLocking, sizeof(SPIMemProgressViewModel)); + view_set_context(app->view, app); + view_set_draw_callback(app->view, spi_mem_view_progress_draw_callback); + view_set_input_callback(app->view, spi_mem_view_progress_input_callback); + spi_mem_view_progress_reset(app); + return app; +} + +void spi_mem_view_progress_free(SPIMemProgressView* app) { + view_free(app->view); + free(app); +} + +void spi_mem_view_progress_set_read_callback( + SPIMemProgressView* app, + SPIMemProgressViewCallback callback, + void* cb_ctx) { + app->callback = callback; + app->cb_ctx = cb_ctx; + with_view_model( + app->view, + SPIMemProgressViewModel * model, + { model->view_type = SPIMemProgressViewTypeRead; }, + true); +} + +void spi_mem_view_progress_set_verify_callback( + SPIMemProgressView* app, + SPIMemProgressViewCallback callback, + void* cb_ctx) { + app->callback = callback; + app->cb_ctx = cb_ctx; + with_view_model( + app->view, + SPIMemProgressViewModel * model, + { model->view_type = SPIMemProgressViewTypeVerify; }, + true); +} + +void spi_mem_view_progress_set_write_callback( + SPIMemProgressView* app, + SPIMemProgressViewCallback callback, + void* cb_ctx) { + app->callback = callback; + app->cb_ctx = cb_ctx; + with_view_model( + app->view, + SPIMemProgressViewModel * model, + { model->view_type = SPIMemProgressViewTypeWrite; }, + true); +} + +void spi_mem_view_progress_set_chip_size(SPIMemProgressView* app, size_t chip_size) { + with_view_model( + app->view, SPIMemProgressViewModel * model, { model->chip_size = chip_size; }, true); +} + +void spi_mem_view_progress_set_file_size(SPIMemProgressView* app, size_t file_size) { + with_view_model( + app->view, SPIMemProgressViewModel * model, { model->file_size = file_size; }, true); +} + +void spi_mem_view_progress_set_block_size(SPIMemProgressView* app, size_t block_size) { + with_view_model( + app->view, SPIMemProgressViewModel * model, { model->block_size = block_size; }, true); +} + +static size_t spi_mem_view_progress_set_total_size(SPIMemProgressViewModel* model) { + size_t total_size = model->chip_size; + if((model->chip_size > model->file_size) && model->view_type != SPIMemProgressViewTypeRead) { + total_size = model->file_size; + } + return total_size; +} + +void spi_mem_view_progress_inc_progress(SPIMemProgressView* app) { + with_view_model( + app->view, + SPIMemProgressViewModel * model, + { + size_t total_size = spi_mem_view_progress_set_total_size(model); + if(total_size == 0) total_size = 1; + model->blocks_written++; + model->progress = + ((float)model->block_size * (float)model->blocks_written) / ((float)total_size); + }, + true); +} + +void spi_mem_view_progress_reset(SPIMemProgressView* app) { + with_view_model( + app->view, + SPIMemProgressViewModel * model, + { + model->blocks_written = 0; + model->block_size = 0; + model->chip_size = 0; + model->file_size = 0; + model->progress = 0; + model->view_type = SPIMemProgressViewTypeUnknown; + }, + true); +} diff --git a/applications/plugins/spi_mem_manager/views/spi_mem_view_progress.h b/applications/plugins/spi_mem_manager/views/spi_mem_view_progress.h new file mode 100644 index 000000000..6a8645b6c --- /dev/null +++ b/applications/plugins/spi_mem_manager/views/spi_mem_view_progress.h @@ -0,0 +1,26 @@ +#pragma once +#include + +typedef struct SPIMemProgressView SPIMemProgressView; +typedef void (*SPIMemProgressViewCallback)(void* context); + +View* spi_mem_view_progress_get_view(SPIMemProgressView* app); +SPIMemProgressView* spi_mem_view_progress_alloc(); +void spi_mem_view_progress_free(SPIMemProgressView* app); +void spi_mem_view_progress_set_read_callback( + SPIMemProgressView* app, + SPIMemProgressViewCallback callback, + void* cb_ctx); +void spi_mem_view_progress_set_verify_callback( + SPIMemProgressView* app, + SPIMemProgressViewCallback callback, + void* cb_ctx); +void spi_mem_view_progress_set_write_callback( + SPIMemProgressView* app, + SPIMemProgressViewCallback callback, + void* cb_ctx); +void spi_mem_view_progress_set_chip_size(SPIMemProgressView* app, size_t chip_size); +void spi_mem_view_progress_set_file_size(SPIMemProgressView* app, size_t file_size); +void spi_mem_view_progress_set_block_size(SPIMemProgressView* app, size_t block_size); +void spi_mem_view_progress_inc_progress(SPIMemProgressView* app); +void spi_mem_view_progress_reset(SPIMemProgressView* app); diff --git a/applications/plugins/subbrute/application.fam b/applications/plugins/subbrute/application.fam index 455bb822f..20a5f5367 100644 --- a/applications/plugins/subbrute/application.fam +++ b/applications/plugins/subbrute/application.fam @@ -4,7 +4,7 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="subbrute_app", cdefines=["APP_SUB_BRUTE"], - requires=["gui","dialogs"], + requires=["gui", "dialogs"], stack_size=2 * 1024, order=11, fap_icon="images/subbrute_10px.png", diff --git a/applications/plugins/tama_p1/hal.c b/applications/plugins/tama_p1/hal.c index 211457803..585cd88c4 100644 --- a/applications/plugins/tama_p1/hal.c +++ b/applications/plugins/tama_p1/hal.c @@ -40,7 +40,7 @@ static void tama_p1_hal_log(log_level_t level, char* buff, ...) { va_list args; va_start(args, buff); furi_string_cat_vprintf(string, buff, args); - va_end(args); + va_end(args); switch(level) { case LOG_ERROR: diff --git a/applications/plugins/tama_p1/tama.h b/applications/plugins/tama_p1/tama.h index e2a267443..e8eecc945 100644 --- a/applications/plugins/tama_p1/tama.h +++ b/applications/plugins/tama_p1/tama.h @@ -13,7 +13,6 @@ #define STATE_FILE_VERSION 2 #define TAMA_SAVE_PATH EXT_PATH("tama_p1/save.bin") - typedef struct { FuriThread* thread; hal_t hal; diff --git a/applications/plugins/tama_p1/tama_p1.c b/applications/plugins/tama_p1/tama_p1.c index 7184638d7..0e7686a06 100644 --- a/applications/plugins/tama_p1/tama_p1.c +++ b/applications/plugins/tama_p1/tama_p1.c @@ -52,7 +52,6 @@ static void tama_p1_draw_callback(Canvas* const canvas, void* cb_ctx) { uint16_t lcd_icon_lower_left = lcd_matrix_left; uint16_t lcd_icon_spacing_horiz = (lcd_matrix_scaled_width - (4 * TAMA_LCD_ICON_SIZE)) / 3 + TAMA_LCD_ICON_SIZE; - uint16_t y = lcd_matrix_top; for(uint8_t row = 0; row < 16; ++row) { @@ -71,7 +70,7 @@ static void tama_p1_draw_callback(Canvas* const canvas, void* cb_ctx) { // Start drawing icons uint8_t lcd_icons = g_ctx->icons; - + // Draw top icons y = lcd_icon_upper_top; // y = 64 - TAMA_LCD_ICON_SIZE; @@ -114,135 +113,134 @@ static void tama_p1_update_timer_callback(FuriMessageQueue* event_queue) { TamaEvent event = {.type = EventTypeTick}; furi_message_queue_put(event_queue, &event, 0); } - -static void tama_p1_load_state() { - state_t *state; + +static void tama_p1_load_state() { + state_t* state; uint8_t buf[4]; - bool error = false; + bool error = false; state = tamalib_get_state(); - Storage* storage = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(storage); - if(storage_file_open(file, TAMA_SAVE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - - storage_file_read(file, &buf, 4); - if (buf[0] != (uint8_t) STATE_FILE_MAGIC[0] || buf[1] != (uint8_t) STATE_FILE_MAGIC[1] || - buf[2] != (uint8_t) STATE_FILE_MAGIC[2] || buf[3] != (uint8_t) STATE_FILE_MAGIC[3]) { + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); + if(storage_file_open(file, TAMA_SAVE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + storage_file_read(file, &buf, 4); + if(buf[0] != (uint8_t)STATE_FILE_MAGIC[0] || buf[1] != (uint8_t)STATE_FILE_MAGIC[1] || + buf[2] != (uint8_t)STATE_FILE_MAGIC[2] || buf[3] != (uint8_t)STATE_FILE_MAGIC[3]) { FURI_LOG_E(TAG, "FATAL: Wrong state file magic in \"%s\" !\n", TAMA_SAVE_PATH); error = true; } - storage_file_read(file, &buf, 1); - if (buf[0] != STATE_FILE_VERSION) { + storage_file_read(file, &buf, 1); + if(buf[0] != STATE_FILE_VERSION) { FURI_LOG_E(TAG, "FATAL: Unsupported version"); error = true; } - if (!error) { + if(!error) { FURI_LOG_D(TAG, "Reading save.bin"); - storage_file_read(file, &buf, 2); - *(state->pc) = buf[0] | ((buf[1] & 0x1F) << 8); - - storage_file_read(file, &buf, 2); - *(state->x) = buf[0] | ((buf[1] & 0xF) << 8); + storage_file_read(file, &buf, 2); + *(state->pc) = buf[0] | ((buf[1] & 0x1F) << 8); - storage_file_read(file, &buf, 2); - *(state->y) = buf[0] | ((buf[1] & 0xF) << 8); + storage_file_read(file, &buf, 2); + *(state->x) = buf[0] | ((buf[1] & 0xF) << 8); - storage_file_read(file, &buf, 1); - *(state->a) = buf[0] & 0xF; + storage_file_read(file, &buf, 2); + *(state->y) = buf[0] | ((buf[1] & 0xF) << 8); - storage_file_read(file, &buf, 1); - *(state->b) = buf[0] & 0xF; + storage_file_read(file, &buf, 1); + *(state->a) = buf[0] & 0xF; - storage_file_read(file, &buf, 1); + storage_file_read(file, &buf, 1); + *(state->b) = buf[0] & 0xF; + + storage_file_read(file, &buf, 1); *(state->np) = buf[0] & 0x1F; - storage_file_read(file, &buf, 1); + storage_file_read(file, &buf, 1); *(state->sp) = buf[0]; - storage_file_read(file, &buf, 1); + storage_file_read(file, &buf, 1); *(state->flags) = buf[0] & 0xF; - storage_file_read(file, &buf, 4); + storage_file_read(file, &buf, 4); *(state->tick_counter) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); - storage_file_read(file, &buf, 4); - *(state->clk_timer_timestamp) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); + storage_file_read(file, &buf, 4); + *(state->clk_timer_timestamp) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | + (buf[3] << 24); - storage_file_read(file, &buf, 4); - *(state->prog_timer_timestamp) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); + storage_file_read(file, &buf, 4); + *(state->prog_timer_timestamp) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | + (buf[3] << 24); - storage_file_read(file, &buf, 1); + storage_file_read(file, &buf, 1); *(state->prog_timer_enabled) = buf[0] & 0x1; - storage_file_read(file, &buf, 1); + storage_file_read(file, &buf, 1); *(state->prog_timer_data) = buf[0]; - storage_file_read(file, &buf, 1); + storage_file_read(file, &buf, 1); *(state->prog_timer_rld) = buf[0]; - storage_file_read(file, &buf, 4); + storage_file_read(file, &buf, 4); *(state->call_depth) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); FURI_LOG_D(TAG, "Restoring Interupts"); - for (uint32_t i = 0; i < INT_SLOT_NUM; i++) { - storage_file_read(file, &buf, 1); + for(uint32_t i = 0; i < INT_SLOT_NUM; i++) { + storage_file_read(file, &buf, 1); state->interrupts[i].factor_flag_reg = buf[0] & 0xF; - storage_file_read(file, &buf, 1); + storage_file_read(file, &buf, 1); state->interrupts[i].mask_reg = buf[0] & 0xF; - storage_file_read(file, &buf, 1); + storage_file_read(file, &buf, 1); state->interrupts[i].triggered = buf[0] & 0x1; } /* First 640 half bytes correspond to the RAM */ FURI_LOG_D(TAG, "Restoring RAM"); - for (uint32_t i = 0; i < MEM_RAM_SIZE; i++) { - storage_file_read(file, &buf, 1); + for(uint32_t i = 0; i < MEM_RAM_SIZE; i++) { + storage_file_read(file, &buf, 1); SET_RAM_MEMORY(state->memory, i + MEM_RAM_ADDR, buf[0] & 0xF); } /* I/Os are from 0xF00 to 0xF7F */ FURI_LOG_D(TAG, "Restoring I/O"); - for (uint32_t i = 0; i < MEM_IO_SIZE; i++) { - storage_file_read(file, &buf, 1); + for(uint32_t i = 0; i < MEM_IO_SIZE; i++) { + storage_file_read(file, &buf, 1); SET_IO_MEMORY(state->memory, i + MEM_IO_ADDR, buf[0] & 0xF); - } - FURI_LOG_D(TAG, "Refreshing Hardware"); - tamalib_refresh_hw(); - } + } + FURI_LOG_D(TAG, "Refreshing Hardware"); + tamalib_refresh_hw(); + } } - + storage_file_close(file); storage_file_free(file); - furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_STORAGE); } - static void tama_p1_save_state() { - // Saving state FURI_LOG_D(TAG, "Saving Gamestate"); uint8_t buf[4]; - state_t *state; + state_t* state; uint32_t offset = 0; state = tamalib_get_state(); - - Storage* storage = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(storage); + + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); if(storage_file_open(file, TAMA_SAVE_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { - buf[0] = (uint8_t) STATE_FILE_MAGIC[0]; - buf[1] = (uint8_t) STATE_FILE_MAGIC[1]; - buf[2] = (uint8_t) STATE_FILE_MAGIC[2]; - buf[3] = (uint8_t) STATE_FILE_MAGIC[3]; + buf[0] = (uint8_t)STATE_FILE_MAGIC[0]; + buf[1] = (uint8_t)STATE_FILE_MAGIC[1]; + buf[2] = (uint8_t)STATE_FILE_MAGIC[2]; + buf[3] = (uint8_t)STATE_FILE_MAGIC[3]; offset += storage_file_write(file, &buf, sizeof(buf)); - + buf[0] = STATE_FILE_VERSION & 0xFF; offset += storage_file_write(file, &buf, 1); - + buf[0] = *(state->pc) & 0xFF; buf[1] = (*(state->pc) >> 8) & 0x1F; offset += storage_file_write(file, &buf, 2); @@ -303,7 +301,7 @@ static void tama_p1_save_state() { buf[3] = (*(state->call_depth) >> 24) & 0xFF; offset += storage_file_write(file, &buf, sizeof(buf)); - for (uint32_t i = 0; i < INT_SLOT_NUM; i++) { + for(uint32_t i = 0; i < INT_SLOT_NUM; i++) { buf[0] = state->interrupts[i].factor_flag_reg & 0xF; offset += storage_file_write(file, &buf, 1); @@ -315,17 +313,17 @@ static void tama_p1_save_state() { } /* First 640 half bytes correspond to the RAM */ - for (uint32_t i = 0; i < MEM_RAM_SIZE; i++) { + for(uint32_t i = 0; i < MEM_RAM_SIZE; i++) { buf[0] = GET_RAM_MEMORY(state->memory, i + MEM_RAM_ADDR) & 0xF; offset += storage_file_write(file, &buf, 1); } /* I/Os are from 0xF00 to 0xF7F */ - for (uint32_t i = 0; i < MEM_IO_SIZE; i++) { + for(uint32_t i = 0; i < MEM_IO_SIZE; i++) { buf[0] = GET_IO_MEMORY(state->memory, i + MEM_IO_ADDR) & 0xF; offset += storage_file_write(file, &buf, 1); } - } + } storage_file_close(file); storage_file_free(file); furi_record_close(RECORD_STORAGE); @@ -333,7 +331,6 @@ static void tama_p1_save_state() { FURI_LOG_D(TAG, "Finished Writing %lu", offset); } - static int32_t tama_p1_worker(void* context) { bool running = true; FuriMutex* mutex = context; @@ -357,8 +354,6 @@ static int32_t tama_p1_worker(void* context) { furi_mutex_release(mutex); return 0; } - - static void tama_p1_init(TamaApp* const ctx) { g_ctx = ctx; @@ -485,9 +480,9 @@ int32_t tama_p1_app(void* p) { tamalib_set_button(BTN_MIDDLE, tama_btn_state); } else if(event.input.key == InputKeyRight) { tamalib_set_button(BTN_RIGHT, tama_btn_state); - } else if(event.input.key == InputKeyDown && event.input.type == InputTypeShort) { + } else if(event.input.key == InputKeyDown && event.input.type == InputTypeShort) { // TODO: pause or fast-forward tamagotchi - tama_p1_save_state(); + tama_p1_save_state(); } else if(event.input.key == InputKeyUp) { // mute tamagotchi tamalib_set_button(BTN_LEFT, tama_btn_state); tamalib_set_button(BTN_RIGHT, tama_btn_state); @@ -500,7 +495,7 @@ int32_t tama_p1_app(void* p) { furi_timer_stop(timer); running = false; - tama_p1_save_state(); + tama_p1_save_state(); } } diff --git a/applications/plugins/timelapse/application.fam b/applications/plugins/timelapse/application.fam index ee725fe52..f5eaae551 100644 --- a/applications/plugins/timelapse/application.fam +++ b/applications/plugins/timelapse/application.fam @@ -4,18 +4,13 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="zeitraffer_app", cdefines=["APP_ZEITRAFFER"], - requires=[ - "gui", - "input", - "notification", - "gpio" - ], + requires=["gui", "input", "notification", "gpio"], stack_size=2 * 1024, order=90, - fap_icon_assets="icons", - fap_icon="zeitraffer.png", + fap_icon_assets="icons", + fap_icon="zeitraffer.png", fap_category="GPIO", - fap_description="Simple intervalometer app", + fap_description="Simple intervalometer app", fap_author="Aurelius Rosenbaum", - fap_weburl="https://github.com/theageoflove/flipperzero-zeitraffer", -) \ No newline at end of file + fap_weburl="https://github.com/theageoflove/flipperzero-zeitraffer", +) diff --git a/applications/plugins/totp/application.fam b/applications/plugins/totp/application.fam index ffb6d6137..81b0e22c3 100644 --- a/applications/plugins/totp/application.fam +++ b/applications/plugins/totp/application.fam @@ -4,14 +4,7 @@ App( apptype=FlipperAppType.EXTERNAL, entry_point="totp_app", cdefines=["APP_TOTP"], - requires=[ - "gui", - "cli", - "dialogs", - "storage", - "input", - "notification" - ], + requires=["gui", "cli", "dialogs", "storage", "input", "notification"], stack_size=2 * 1024, order=20, fap_category="Misc", diff --git a/applications/plugins/totp/services/config/config.c b/applications/plugins/totp/services/config/config.c index cd19d19d4..c5193ac2e 100644 --- a/applications/plugins/totp/services/config/config.c +++ b/applications/plugins/totp/services/config/config.c @@ -132,7 +132,7 @@ static TotpConfigFileOpenResult totp_open_config_file(Storage* storage, FlipperF flipper_format_write_comment_cstr(fff_data_file, " "); flipper_format_write_comment_cstr( fff_data_file, - "How to notify user when new token is generated or badusb mode is activated (possible values: 0 - do not notify, 1 - sound, 2 - vibro, 3 sound and vibro)"); + "How to notify user when new token is generated or badkb mode is activated (possible values: 0 - do not notify, 1 - sound, 2 - vibro, 3 sound and vibro)"); flipper_format_write_uint32( fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1); @@ -769,4 +769,4 @@ void totp_config_file_reset() { Storage* storage = totp_open_storage(); storage_simply_remove(storage, CONFIG_FILE_PATH); totp_close_storage(); -} \ No newline at end of file +} diff --git a/applications/plugins/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/plugins/totp/ui/scenes/generate_token/totp_scene_generate_token.c index 41c52b435..18d1791f4 100644 --- a/applications/plugins/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/plugins/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -24,7 +24,7 @@ typedef struct { uint32_t last_token_gen_time; TotpTypeCodeWorkerContext* type_code_worker_context; NotificationMessage const** notification_sequence_new_token; - NotificationMessage const** notification_sequence_badusb; + NotificationMessage const** notification_sequence_badkb; } SceneState; static const NotificationSequence* @@ -69,8 +69,8 @@ static const NotificationSequence* } static const NotificationSequence* - get_notification_sequence_badusb(const PluginState* plugin_state, SceneState* scene_state) { - if(scene_state->notification_sequence_badusb == NULL) { + get_notification_sequence_badkb(const PluginState* plugin_state, SceneState* scene_state) { + if(scene_state->notification_sequence_badkb == NULL) { uint8_t i = 0; uint8_t length = 3; if(plugin_state->notification_method & NotificationMethodVibro) { @@ -81,36 +81,36 @@ static const NotificationSequence* length += 6; } - scene_state->notification_sequence_badusb = malloc(sizeof(void*) * length); - furi_check(scene_state->notification_sequence_badusb != NULL); + scene_state->notification_sequence_badkb = malloc(sizeof(void*) * length); + furi_check(scene_state->notification_sequence_badkb != NULL); - scene_state->notification_sequence_badusb[i++] = &message_blue_255; + scene_state->notification_sequence_badkb[i++] = &message_blue_255; if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_badusb[i++] = &message_vibro_on; + scene_state->notification_sequence_badkb[i++] = &message_vibro_on; } if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_badusb[i++] = &message_note_d5; //-V525 - scene_state->notification_sequence_badusb[i++] = &message_delay_50; - scene_state->notification_sequence_badusb[i++] = &message_note_e4; - scene_state->notification_sequence_badusb[i++] = &message_delay_50; - scene_state->notification_sequence_badusb[i++] = &message_note_f3; + scene_state->notification_sequence_badkb[i++] = &message_note_d5; //-V525 + scene_state->notification_sequence_badkb[i++] = &message_delay_50; + scene_state->notification_sequence_badkb[i++] = &message_note_e4; + scene_state->notification_sequence_badkb[i++] = &message_delay_50; + scene_state->notification_sequence_badkb[i++] = &message_note_f3; } - scene_state->notification_sequence_badusb[i++] = &message_delay_50; + scene_state->notification_sequence_badkb[i++] = &message_delay_50; if(plugin_state->notification_method & NotificationMethodVibro) { - scene_state->notification_sequence_badusb[i++] = &message_vibro_off; + scene_state->notification_sequence_badkb[i++] = &message_vibro_off; } if(plugin_state->notification_method & NotificationMethodSound) { - scene_state->notification_sequence_badusb[i++] = &message_sound_off; + scene_state->notification_sequence_badkb[i++] = &message_sound_off; } - scene_state->notification_sequence_badusb[i++] = NULL; + scene_state->notification_sequence_badkb[i++] = NULL; } - return (NotificationSequence*)scene_state->notification_sequence_badusb; + return (NotificationSequence*)scene_state->notification_sequence_badkb; } static void int_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) { @@ -340,7 +340,7 @@ bool totp_scene_generate_token_handle_event( scene_state->type_code_worker_context, TotpTypeCodeWorkerEventType); notification_message( plugin_state->notification_app, - get_notification_sequence_badusb(plugin_state, scene_state)); + get_notification_sequence_badkb(plugin_state, scene_state)); return true; } @@ -399,8 +399,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) { free(scene_state->notification_sequence_new_token); } - if(scene_state->notification_sequence_badusb != NULL) { - free(scene_state->notification_sequence_badusb); + if(scene_state->notification_sequence_badkb != NULL) { + free(scene_state->notification_sequence_badkb); } free(scene_state); diff --git a/applications/plugins/unitemp/README.md b/applications/plugins/unitemp/README.md index 2f753faea..436f3600e 100644 --- a/applications/plugins/unitemp/README.md +++ b/applications/plugins/unitemp/README.md @@ -1,10 +1,24 @@ -![Flipper usage](https://user-images.githubusercontent.com/10090793/206618263-c1e212e4-58dc-432e-87a8-5c19fd835b35.png) +![Flipper usage](https://user-images.githubusercontent.com/10090793/211182642-e41919c5-3091-4125-815a-2d6a77a859f6.png) # Unitemp - Universal temperature sensor reader [![GitHub release](https://img.shields.io/github/release/quen0n/unitemp-flipperzero?include_prereleases=&sort=semver&color=blue)](https://github.com/quen0n/unitemp-flipperzero/releases/) -[![GitHub all releases](https://img.shields.io/github/downloads/quen0n/unitemp-flipperzero/total)]() -[![GitHub](https://img.shields.io/github/license/quen0n/unitemp-flipperzero)](https://github.com/quen0n/unitemp-flipperzero/blob/dev/LICENSE.md) -[Flipper Zero](https://flipperzero.one/) application for reading temperature, humidity and pressure sensors using Onewire, Singlewire, I2C protocols. -## List of supported sensors (supplemented) -![image](https://user-images.githubusercontent.com/10090793/208480561-e98a6192-d44d-4ad9-8692-a91ccaae47c7.png) +[![GitHub](https://img.shields.io/github/license/quen0n/unitemp-flipperzero)](https://github.com/quen0n/unitemp-flipperzero/blob/dev/LICENSE.md) +[![Build dev](https://github.com/quen0n/unitemp-flipperzero/actions/workflows/build_dev.yml/badge.svg?branch=dev)](https://github.com/quen0n/unitemp-flipperzero/actions/workflows/build_dev.yml) +[Flipper Zero](https://flipperzero.one/) application for reading temperature, humidity and pressure sensors like a DHT11/22, DS18B20, BMP280, HTU21 and more. +## List of supported sensors +![image](https://user-images.githubusercontent.com/10090793/215605424-54b1c08c-e41b-4fb4-b966-dd959507200b.png) + ## Installation -Copy the contents of the repository to the `applications/plugins/unitemp` folder and build the project. Flash FZ along with resources. [More...](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/fbt.md) +1) Download [latest version](https://cloud.quenon.ru/index.php/s/h98rT9UnaOL4wxR/download?path=%2F&files=unitemp-latest.fap) +2) Copy `unitemp-latest.fap` to `SD card/apps/GPIO` with qFlipper or mobile application +3) Open application on your Flipper: `Applications->GPIO->Temp sensors reader` +Note: If you get the message "API version mismatch" after updating the firmware, download and install Unitemp again +## Need help? Discussions? +Join the discussion, ask a question or just send a photo of the flipper with sensors to [Discord](https://discord.com/channels/740930220399525928/1056727938747351060) +## Gratitudes +Thanks to [@Svaarich](https://github.com/Svaarich) for the UI design and to the Unleashed firmware community for sensors testing and feedbacks. + +## Some community photos +![image](https://user-images.githubusercontent.com/10090793/210120132-7ddbc937-0a6b-4472-bd1c-7fbc3ecdf2ad.png) +![image](https://user-images.githubusercontent.com/10090793/210120135-12fc5810-77ff-49db-b799-e9479e1f57a7.png) +![image](https://user-images.githubusercontent.com/10090793/210120143-a2bae3ce-4190-421f-8c4f-c7c744903bd6.png) +![image](https://user-images.githubusercontent.com/10090793/215224085-8099408e-b3de-4a0c-854e-fe4e4faa8ea3.png) \ No newline at end of file diff --git a/applications/plugins/unitemp/Sensors.c b/applications/plugins/unitemp/Sensors.c index d35e31931..d9304ab32 100644 --- a/applications/plugins/unitemp/Sensors.c +++ b/applications/plugins/unitemp/Sensors.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -17,7 +17,6 @@ */ #include "Sensors.h" #include -#include //Порты ввода/вывода, которые не были обозначены в общем списке const GpioPin SWC_10 = {.pin = LL_GPIO_PIN_14, .port = GPIOA}; @@ -67,12 +66,19 @@ const Interface ONE_WIRE = { .allocator = unitemp_onewire_sensor_alloc, .mem_releaser = unitemp_onewire_sensor_free, .updater = unitemp_onewire_sensor_update}; +const Interface SPI = { + .name = "SPI", + .allocator = unitemp_spi_sensor_alloc, + .mem_releaser = unitemp_spi_sensor_free, + .updater = unitemp_spi_sensor_update}; //Перечень интерфейсов подключения -//static const Interface* interfaces[] = {&SINGLE_WIRE, &I2C, &ONE_WIRE}; +//static const Interface* interfaces[] = {&SINGLE_WIRE, &I2C, &ONE_WIRE, &SPI}; //Перечень датчиков -static const SensorType* sensorTypes[] = - {&DHT11, &DHT12_SW, &DHT21, &DHT22, &AM2320_SW, &AM2320_I2C, &LM75, &BMP280, &BME280, &Dallas}; +static const SensorType* sensorTypes[] = {&DHT11, &DHT12_SW, &DHT20, &DHT21, &DHT22, + &Dallas, &AM2320_SW, &AM2320_I2C, &HTU21x, &AHT10, + &SHT30, &GXHT30, &LM75, &HDC1080, &BMP180, + &BMP280, &BME280, &BME680, &MAX31855, &MAX6675}; const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) { if(index > SENSOR_TYPES_COUNT) return NULL; @@ -151,7 +157,7 @@ uint8_t unitemp_gpio_getAviablePortsCount(const Interface* interface, const GPIO } //Проверка для single wire - if(interface == &SINGLE_WIRE) { + if(interface == &SINGLE_WIRE || interface == &SPI) { if(gpio_interfaces_list[i] == NULL || (unitemp_gpio_getFromIndex(i) == extraport)) { aviable_ports_count++; } @@ -190,6 +196,13 @@ const GPIO* return NULL; } } + if(interface == &SPI) { + if(!((gpio_interfaces_list[0] == NULL || gpio_interfaces_list[0] == &SPI) && + (gpio_interfaces_list[1] == NULL || gpio_interfaces_list[1] == &SPI) && + (gpio_interfaces_list[3] == NULL || gpio_interfaces_list[3] == &SPI))) { + return NULL; + } + } uint8_t aviable_index = 0; for(uint8_t i = 0; i < GPIO_ITEMS; i++) { @@ -207,7 +220,7 @@ const GPIO* } } //Проверка для single wire - if(interface == &SINGLE_WIRE) { + if(interface == &SINGLE_WIRE || interface == &SPI) { if(gpio_interfaces_list[i] == NULL || unitemp_gpio_getFromIndex(i) == extraport) { if(aviable_index == index) { return unitemp_gpio_getFromIndex(i); @@ -268,9 +281,7 @@ void unitemp_sensors_add(Sensor* sensor) { } bool unitemp_sensors_load(void) { -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "Loading sensors..."); -#endif + UNITEMP_DEBUG("Loading sensors..."); //Выделение памяти на поток app->file_stream = file_stream_alloc(app->storage); @@ -331,7 +342,7 @@ bool unitemp_sensors_load(void) { //Сколько байт до конца строки size_t line_end = 0; - while(line_end != STRING_FAILURE && line_end != (size_t)(file_size - 1)) { + while(line_end != ((size_t)-1) && line_end != (size_t)(file_size - 1)) { //Имя датчика char name[11] = {0}; //Тип датчика @@ -379,9 +390,7 @@ bool unitemp_sensors_load(void) { } bool unitemp_sensors_save(void) { -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "Saving sensors..."); -#endif + UNITEMP_DEBUG("Saving sensors..."); //Выделение памяти для потока app->file_stream = file_stream_alloc(app->storage); @@ -424,6 +433,11 @@ bool unitemp_sensors_save(void) { stream_write_format( app->file_stream, "%d\n", unitemp_singlewire_sensorGetGPIO(sensor)->num); } + if(sensor->type->interface == &SPI) { + uint8_t gpio_num = ((SPISensor*)sensor->instance)->CS_pin->num; + stream_write_format(app->file_stream, "%d\n", gpio_num); + } + if(sensor->type->interface == &I2C) { stream_write_format( app->file_stream, "%X\n", ((I2CSensor*)sensor->instance)->currentI2CAdr); @@ -501,7 +515,7 @@ Sensor* unitemp_sensor_alloc(char* name, const SensorType* type, char* args) { //Выход если датчик успешно развёрнут if(status) { - FURI_LOG_I(APP_NAME, "Sensor %s allocated", name); + UNITEMP_DEBUG("Sensor %s allocated", name); return sensor; } //Выход с очисткой если память для датчика не была выделена @@ -527,17 +541,13 @@ void unitemp_sensor_free(Sensor* sensor) { bool status = false; //Высвобождение памяти под инстанс status = sensor->type->interface->mem_releaser(sensor); - UNUSED(status); -#ifdef UNITEMP_DEBUG if(status) { - FURI_LOG_D(APP_NAME, "Sensor %s memory successfully released", sensor->name); + UNITEMP_DEBUG("Sensor %s memory successfully released", sensor->name); } else { FURI_LOG_E(APP_NAME, "Sensor %s memory is not released", sensor->name); } -#endif free(sensor->name); - //free(sensor); } void unitemp_sensors_free(void) { @@ -556,9 +566,7 @@ bool unitemp_sensors_init(void) { //Может пропасть при отключении USB if(furi_hal_power_is_otg_enabled() != true) { furi_hal_power_enable_otg(); -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "OTG enabled"); -#endif + UNITEMP_DEBUG("OTG enabled"); } if(!(*app->sensors[i]->type->initializer)(app->sensors[i])) { FURI_LOG_E( @@ -567,9 +575,7 @@ bool unitemp_sensors_init(void) { app->sensors[i]->name); result = false; } -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "Sensor %s successfully initialized", app->sensors[i]->name); -#endif + FURI_LOG_I(APP_NAME, "Sensor %s successfully initialized", app->sensors[i]->name); } app->sensors_ready = true; return result; @@ -580,9 +586,7 @@ bool unitemp_sensors_deInit(void) { //Выключение 5 В если до этого оно не было включено if(app->settings.lastOTGState != true) { furi_hal_power_disable_otg(); -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "OTG disabled"); -#endif + UNITEMP_DEBUG("OTG disabled"); } //Перебор датчиков из списка @@ -618,13 +622,14 @@ UnitempStatus unitemp_sensor_updateData(Sensor* sensor) { sensor->status = sensor->type->interface->updater(sensor); -#ifdef UNITEMP_DEBUG - if(sensor->status != UT_SENSORSTATUS_OK && sensor->status != UT_SENSORSTATUS_POLLING) - FURI_LOG_D(APP_NAME, "Sensor %s update status %d", sensor->name, sensor->status); -#endif + if(sensor->status != UT_SENSORSTATUS_OK && sensor->status != UT_SENSORSTATUS_POLLING) { + UNITEMP_DEBUG("Sensor %s update status %d", sensor->name, sensor->status); + } - if(app->settings.temp_unit == UT_TEMP_FAHRENHEIT && sensor->status == UT_SENSORSTATUS_OK) + if(app->settings.temp_unit == UT_TEMP_FAHRENHEIT && sensor->status == UT_SENSORSTATUS_OK) { uintemp_celsiumToFarengate(sensor); + } + if(sensor->status == UT_SENSORSTATUS_OK) { sensor->temp += sensor->temp_offset / 10.f; if(app->settings.pressure_unit == UT_PRESSURE_MM_HG) { diff --git a/applications/plugins/unitemp/Sensors.h b/applications/plugins/unitemp/Sensors.h index 52e6165f5..d2b7c07af 100644 --- a/applications/plugins/unitemp/Sensors.h +++ b/applications/plugins/unitemp/Sensors.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -136,7 +136,7 @@ typedef struct Sensor { extern const Interface SINGLE_WIRE; //Собственный однопроводной протокол датчиков DHTXX и AM23XX extern const Interface ONE_WIRE; //Однопроводной протокол Dallas extern const Interface I2C; //I2C_2 (PC0, PC1) -//extern const Interface SPI; +extern const Interface SPI; //SPI_1 (MOSI - 2, MISO - 3, CS - 4, SCK - 5) /* ============================= Датчик(и) ============================= */ /** @@ -318,7 +318,15 @@ const GPIO* //DS18x2x #include "./interfaces/OneWireSensor.h" #include "./sensors/LM75.h" -//BMP280, BME280 +//BMP280, BME280, BME680 #include "./sensors/BMx280.h" +#include "./sensors/BME680.h" #include "./sensors/AM2320.h" +#include "./sensors/DHT20.h" +#include "./sensors/SHT30.h" +#include "./sensors/BMP180.h" +#include "./sensors/HTU21x.h" +#include "./sensors/HDC1080.h" +#include "./sensors/MAX31855.h" +#include "./sensors/MAX6675.h" #endif diff --git a/applications/plugins/unitemp/application.fam b/applications/plugins/unitemp/application.fam index 3ac128eef..d975da5ff 100644 --- a/applications/plugins/unitemp/application.fam +++ b/applications/plugins/unitemp/application.fam @@ -9,11 +9,11 @@ App( ], stack_size=2 * 1024, order=100, - fap_description = "Universal temperature sensors reader", - fap_author = "Quenon", - fap_weburl = "https://github.com/quen0n/Unitemp-Flipper-Zero-Plugin", + fap_description="Universal temperature sensors reader", + fap_author="Quenon", + fap_weburl="https://github.com/quen0n/Unitemp-Flipper-Zero-Plugin", fap_category="GPIO", fap_icon="icon.png", fap_icon_assets="assets", fap_libs=["assets"], -) \ No newline at end of file +) diff --git a/applications/plugins/unitemp/interfaces/I2CSensor.c b/applications/plugins/unitemp/interfaces/I2CSensor.c index 72d959e27..e5901c282 100644 --- a/applications/plugins/unitemp/interfaces/I2CSensor.c +++ b/applications/plugins/unitemp/interfaces/I2CSensor.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/interfaces/I2CSensor.h b/applications/plugins/unitemp/interfaces/I2CSensor.h index 3df709d9a..4d468aae1 100644 --- a/applications/plugins/unitemp/interfaces/I2CSensor.h +++ b/applications/plugins/unitemp/interfaces/I2CSensor.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/interfaces/OneWireSensor.c b/applications/plugins/unitemp/interfaces/OneWireSensor.c index 740ba3365..f4f3ebcdc 100644 --- a/applications/plugins/unitemp/interfaces/OneWireSensor.c +++ b/applications/plugins/unitemp/interfaces/OneWireSensor.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -58,9 +58,7 @@ OneWireBus* uintemp_onewire_bus_alloc(const GPIO* gpio) { bus->device_count = 0; bus->gpio = gpio; bus->powerMode = PWR_PASSIVE; -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "one wire bus (port %d) allocated", gpio->num); -#endif + UNITEMP_DEBUG("one wire bus (port %d) allocated", gpio->num); return bus; } @@ -84,9 +82,7 @@ bool unitemp_onewire_bus_init(OneWireBus* bus) { return true; } bool unitemp_onewire_bus_deinit(OneWireBus* bus) { -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "devices on wire %d: %d", bus->gpio->num, bus->device_count); -#endif + UNITEMP_DEBUG("devices on wire %d: %d", bus->gpio->num, bus->device_count); bus->device_count--; if(bus->device_count <= 0) { bus->device_count = 0; @@ -236,15 +232,11 @@ void unitemp_onewire_bus_enum_init(void) { uint8_t* unitemp_onewire_bus_enum_next(OneWireBus* bus) { furi_delay_ms(10); if(!onewire_enum_fork_bit) { // Если на предыдущем шаге уже не было разногласий -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "All devices on wire %d is found", unitemp_gpio_toInt(bus->gpio)); -#endif + UNITEMP_DEBUG("All devices on wire %d is found", unitemp_gpio_toInt(bus->gpio)); return 0; // то просто выходим ничего не возвращая } if(!unitemp_onewire_bus_start(bus)) { -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "Wire %d is empty", unitemp_gpio_toInt(bus->gpio)); -#endif + UNITEMP_DEBUG("Wire %d is empty", unitemp_gpio_toInt(bus->gpio)); return 0; } uint8_t bp = 8; @@ -278,9 +270,8 @@ uint8_t* unitemp_onewire_bus_enum_next(OneWireBus* bus) { if(!not1) { // Присутствует единица next |= 0x80; } else { // Нет ни нулей ни единиц - ошибочная ситуация -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "Wrong wire %d situation", unitemp_gpio_toInt(bus->gpio)); -#endif + + UNITEMP_DEBUG("Wrong wire %d situation", unitemp_gpio_toInt(bus->gpio)); return 0; } } @@ -421,9 +412,7 @@ UnitempStatus unitemp_onewire_sensor_update(Sensor* sensor) { unitemp_onewire_bus_send_byte(instance->bus, 0xBE); // Read Scratch-pad unitemp_onewire_bus_read_byteArray(instance->bus, buff, 9); if(!unitemp_onewire_CRC_check(buff, 9)) { -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "Sensor %s is not found", sensor->name); -#endif + UNITEMP_DEBUG("Sensor %s is not found", sensor->name); return UT_SENSORSTATUS_TIMEOUT; } } @@ -462,9 +451,7 @@ UnitempStatus unitemp_onewire_sensor_update(Sensor* sensor) { unitemp_onewire_bus_send_byte(instance->bus, 0xBE); // Read Scratch-pad unitemp_onewire_bus_read_byteArray(instance->bus, buff, 9); if(!unitemp_onewire_CRC_check(buff, 9)) { -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "Failed CRC check: %s", sensor->name); -#endif + UNITEMP_DEBUG("Failed CRC check: %s", sensor->name); return UT_SENSORSTATUS_BADCRC; } int16_t raw = buff[0] | ((int16_t)buff[1] << 8); diff --git a/applications/plugins/unitemp/interfaces/OneWireSensor.h b/applications/plugins/unitemp/interfaces/OneWireSensor.h index f2b148535..ef94db820 100644 --- a/applications/plugins/unitemp/interfaces/OneWireSensor.h +++ b/applications/plugins/unitemp/interfaces/OneWireSensor.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/interfaces/SPISensor.c b/applications/plugins/unitemp/interfaces/SPISensor.c new file mode 100644 index 000000000..b53aed28d --- /dev/null +++ b/applications/plugins/unitemp/interfaces/SPISensor.c @@ -0,0 +1,89 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ + +#include +#include +#include "SPISensor.h" + +static uint8_t sensors_count = 0; + +bool unitemp_spi_sensor_alloc(Sensor* sensor, char* args) { + if(args == NULL) return false; + + //Создание инстанса датчика SPI + SPISensor* instance = malloc(sizeof(SPISensor)); + if(instance == NULL) { + FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); + return false; + } + sensor->instance = instance; + + //Определение GPIO chip select + int gpio = 255; + sscanf(args, "%d", &gpio); + instance->CS_pin = unitemp_gpio_getFromInt(gpio); + if(instance->CS_pin == NULL) { + FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name); + free(instance); + return false; + } + + instance->spi = malloc(sizeof(FuriHalSpiBusHandle)); + memcpy(instance->spi, &furi_hal_spi_bus_handle_external, sizeof(FuriHalSpiBusHandle)); + + instance->spi->cs = instance->CS_pin->pin; + + bool status = sensor->type->allocator(sensor, args); + + //Блокировка портов GPIO + sensors_count++; + unitemp_gpio_lock(unitemp_gpio_getFromInt(2), &SPI); + unitemp_gpio_lock(unitemp_gpio_getFromInt(3), &SPI); + unitemp_gpio_lock(unitemp_gpio_getFromInt(5), &SPI); + unitemp_gpio_lock(instance->CS_pin, &SPI); + return status; +} + +bool unitemp_spi_sensor_free(Sensor* sensor) { + bool status = sensor->type->mem_releaser(sensor); + unitemp_gpio_unlock(((SPISensor*)sensor->instance)->CS_pin); + free(((SPISensor*)(sensor->instance))->spi); + free(sensor->instance); + + if(--sensors_count == 0) { + unitemp_gpio_unlock(unitemp_gpio_getFromInt(2)); + unitemp_gpio_unlock(unitemp_gpio_getFromInt(3)); + unitemp_gpio_unlock(unitemp_gpio_getFromInt(5)); + } + + return status; +} + +bool unitemp_spi_sensor_init(Sensor* sensor) { + return sensor->type->initializer(sensor); +} + +bool unitemp_spi_sensor_deinit(Sensor* sensor) { + UNUSED(sensor); + + return true; +} + +UnitempStatus unitemp_spi_sensor_update(Sensor* sensor) { + return sensor->type->updater(sensor); +} \ No newline at end of file diff --git a/applications/plugins/unitemp/interfaces/SPISensor.h b/applications/plugins/unitemp/interfaces/SPISensor.h new file mode 100644 index 000000000..40f284b04 --- /dev/null +++ b/applications/plugins/unitemp/interfaces/SPISensor.h @@ -0,0 +1,66 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_SPI +#define UNITEMP_SPI + +#include "../unitemp.h" +#include + +//Структура SPI датчика +typedef struct SPISensor { + //Указатель на интерфейс SPI + FuriHalSpiBusHandle* spi; + //Порт подключения CS + const GPIO* CS_pin; +} SPISensor; + +/** + * @brief Выделение памяти для датчика с интерфейсом SPI + * @param sensor Указатель на датчик + * @param args Указатель на массив аргументов с параметрами датчика + * @return Истина если всё ок + */ +bool unitemp_spi_sensor_alloc(Sensor* sensor, char* args); + +/** + * @brief Высвобождение памяти инстанса датчика + * @param sensor Указатель на датчик + */ +bool unitemp_spi_sensor_free(Sensor* sensor); + +/** + * @brief Инициализации датчика с интерфейсом one wire + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_spi_sensor_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * @param sensor Указатель на датчик + */ +bool unitemp_spi_sensor_deinit(Sensor* sensor); + +/** + * @brief Обновить значение с датчка + * @param sensor Указатель на датчик + * @return Статус обновления + */ +UnitempStatus unitemp_spi_sensor_update(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/interfaces/SingleWireSensor.c b/applications/plugins/unitemp/interfaces/SingleWireSensor.c index 183bfc872..d6d1b092b 100644 --- a/applications/plugins/unitemp/interfaces/SingleWireSensor.c +++ b/applications/plugins/unitemp/interfaces/SingleWireSensor.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -43,7 +43,7 @@ const SensorType DHT12_SW = { .updater = unitemp_singlewire_update}; const SensorType DHT21 = { .typename = "DHT21", - .altname = "DHT21 (AM2301)", + .altname = "DHT21/AM2301", .interface = &SINGLE_WIRE, .datatype = UT_DATA_TYPE_TEMP_HUM, .pollingInterval = 1000, @@ -54,7 +54,7 @@ const SensorType DHT21 = { .updater = unitemp_singlewire_update}; const SensorType DHT22 = { .typename = "DHT22", - .altname = "DHT22 (AM2302)", + .altname = "DHT22/AM2302", .interface = &SINGLE_WIRE, .datatype = UT_DATA_TYPE_TEMP_HUM, .pollingInterval = 2000, @@ -262,7 +262,7 @@ UnitempStatus unitemp_singlewire_update(Sensor* sensor) { //Проверка на отрицательность температуры if(READ_BIT(raw, 1 << 15)) { //Проверка на способ кодирования данных - if(READ_BIT(raw, 0x60)) { + if(READ_BIT(raw, 0x6000)) { //Не оригинал sensor->temp = (float)((int16_t)raw) / 10; } else { diff --git a/applications/plugins/unitemp/interfaces/SingleWireSensor.h b/applications/plugins/unitemp/interfaces/SingleWireSensor.h index f5bc74734..c762ff0aa 100644 --- a/applications/plugins/unitemp/interfaces/SingleWireSensor.h +++ b/applications/plugins/unitemp/interfaces/SingleWireSensor.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/sensors/AM2320.c b/applications/plugins/unitemp/sensors/AM2320.c index e77707005..29b255e1d 100644 --- a/applications/plugins/unitemp/sensors/AM2320.c +++ b/applications/plugins/unitemp/sensors/AM2320.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/sensors/AM2320.h b/applications/plugins/unitemp/sensors/AM2320.h index f13105470..fa5f502d4 100644 --- a/applications/plugins/unitemp/sensors/AM2320.h +++ b/applications/plugins/unitemp/sensors/AM2320.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/sensors/BME680.c b/applications/plugins/unitemp/sensors/BME680.c new file mode 100644 index 000000000..397e702cb --- /dev/null +++ b/applications/plugins/unitemp/sensors/BME680.c @@ -0,0 +1,431 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + Contributed by g0gg0 (https://github.com/g3gg0) + + 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 3 of the License, 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. If not, see . +*/ +#include "BME680.h" + +const SensorType BME680 = { + .typename = "BME680", + .interface = &I2C, + .datatype = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, + .pollingInterval = 500, + .allocator = unitemp_BME680_alloc, + .mem_releaser = unitemp_BME680_free, + .initializer = unitemp_BME680_init, + .deinitializer = unitemp_BME680_deinit, + .updater = unitemp_BME680_update}; + +//Интервал обновления калибровочных значений +#define BOSCH_CAL_UPDATE_INTERVAL 60000 + +#define BME680_ID 0x61 + +#define BME680_I2C_ADDR_MIN (0x76 << 1) +#define BME680_I2C_ADDR_MAX (0x77 << 1) + +#define BME680_REG_STATUS 0x1D +#define BME680_REG_CTRL_MEAS 0x74 +#define BME680_REG_CONFIG 0x75 +#define BME680_REG_CTRL_HUM 0x72 +//Преддескретизация температуры +#define BME680_TEMP_OVERSAMPLING_SKIP 0b00000000 +#define BME680_TEMP_OVERSAMPLING_1 0b00100000 +#define BME680_TEMP_OVERSAMPLING_2 0b01000000 +#define BME680_TEMP_OVERSAMPLING_4 0b01100000 +#define BME680_TEMP_OVERSAMPLING_8 0b10000000 +#define BME680_TEMP_OVERSAMPLING_16 0b10100000 +//Преддескретизация давления +#define BME680_PRESS_OVERSAMPLING_SKIP 0b00000000 +#define BME680_PRESS_OVERSAMPLING_1 0b00000100 +#define BME680_PRESS_OVERSAMPLING_2 0b00001000 +#define BME680_PRESS_OVERSAMPLING_4 0b00001100 +#define BME680_PRESS_OVERSAMPLING_8 0b00010000 +#define BME680_PRESS_OVERSAMPLING_16 0b00010100 +//Преддескретизация влажности +#define BME680_HUM_OVERSAMPLING_SKIP 0b00000000 +#define BME680_HUM_OVERSAMPLING_1 0b00000001 +#define BME680_HUM_OVERSAMPLING_2 0b00000010 +#define BME680_HUM_OVERSAMPLING_4 0b00000011 +#define BME680_HUM_OVERSAMPLING_8 0b00000100 +#define BME680_HUM_OVERSAMPLING_16 0b00000101 +//Режимы работы датчика +#define BME680_MODE_SLEEP 0b00000000 //Наелся и спит +#define BME680_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон +//Коэффициент фильтрации значений +#define BME680_FILTER_COEFF_1 0b00000000 +#define BME680_FILTER_COEFF_2 0b00000100 +#define BME680_FILTER_COEFF_4 0b00001000 +#define BME680_FILTER_COEFF_8 0b00001100 +#define BME680_FILTER_COEFF_16 0b00010000 +//Разрешить работу по SPI +#define BME680_SPI_3W_ENABLE 0b00000001 +#define BME680_SPI_3W_DISABLE 0b00000000 + +/* https://github.com/boschsensortec/BME680_driver/blob/master/bme680.c or + https://github.com/boschsensortec/BME68x-Sensor-API */ +static float BME680_compensate_temperature(I2CSensor* i2c_sensor, int32_t temp_adc) { + BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; + float var1 = 0; + float var2 = 0; + float calc_temp = 0; + + /* calculate var1 data */ + var1 = + ((((float)temp_adc / 16384.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 1024.0f)) * + ((float)bme680_instance->temp_cal.dig_T2)); + + /* calculate var2 data */ + var2 = + (((((float)temp_adc / 131072.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 8192.0f)) * + (((float)temp_adc / 131072.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 8192.0f))) * + ((float)bme680_instance->temp_cal.dig_T3 * 16.0f)); + + /* t_fine value*/ + bme680_instance->t_fine = (var1 + var2); + + /* compensated temperature data*/ + calc_temp = ((bme680_instance->t_fine) / 5120.0f); + + return calc_temp; +} + +static float BME680_compensate_pressure(I2CSensor* i2c_sensor, int32_t pres_adc) { + BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; + + float var1; + float var2; + float var3; + float calc_pres; + + var1 = (((float)bme680_instance->t_fine / 2.0f) - 64000.0f); + var2 = var1 * var1 * (((float)bme680_instance->press_cal.dig_P6) / (131072.0f)); + var2 = var2 + (var1 * ((float)bme680_instance->press_cal.dig_P5) * 2.0f); + var2 = (var2 / 4.0f) + (((float)bme680_instance->press_cal.dig_P4) * 65536.0f); + var1 = + (((((float)bme680_instance->press_cal.dig_P3 * var1 * var1) / 16384.0f) + + ((float)bme680_instance->press_cal.dig_P2 * var1)) / + 524288.0f); + var1 = ((1.0f + (var1 / 32768.0f)) * ((float)bme680_instance->press_cal.dig_P1)); + calc_pres = (1048576.0f - ((float)pres_adc)); + + /* Avoid exception caused by division by zero */ + if((int)var1 != 0) { + calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1); + var1 = + (((float)bme680_instance->press_cal.dig_P9) * calc_pres * calc_pres) / 2147483648.0f; + var2 = calc_pres * (((float)bme680_instance->press_cal.dig_P8) / 32768.0f); + var3 = + ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f) * + (bme680_instance->press_cal.dig_P10 / 131072.0f)); + calc_pres = + (calc_pres + + (var1 + var2 + var3 + ((float)bme680_instance->press_cal.dig_P7 * 128.0f)) / 16.0f); + } else { + calc_pres = 0; + } + + return calc_pres; +} + +static float BME680_compensate_humidity(I2CSensor* i2c_sensor, int32_t hum_adc) { + BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; + float calc_hum; + float var1; + float var2; + float var3; + float var4; + float temp_comp; + + /* compensated temperature data*/ + temp_comp = ((bme680_instance->t_fine) / 5120.0f); + var1 = + (float)((float)hum_adc) - (((float)bme680_instance->hum_cal.dig_H1 * 16.0f) + + (((float)bme680_instance->hum_cal.dig_H3 / 2.0f) * temp_comp)); + var2 = var1 * + ((float)(((float)bme680_instance->hum_cal.dig_H2 / 262144.0f) * + (1.0f + (((float)bme680_instance->hum_cal.dig_H4 / 16384.0f) * temp_comp) + + (((float)bme680_instance->hum_cal.dig_H5 / 1048576.0f) * temp_comp * temp_comp)))); + var3 = (float)bme680_instance->hum_cal.dig_H6 / 16384.0f; + var4 = (float)bme680_instance->hum_cal.dig_H7 / 2097152.0f; + calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2); + if(calc_hum > 100.0f) { + calc_hum = 100.0f; + } else if(calc_hum < 0.0f) { + calc_hum = 0.0f; + } + + return calc_hum; +} + +/* https://github.com/boschsensortec/BME680_driver/blob/master/bme680_defs.h */ +#define BME680_COEFF_SIZE UINT8_C(41) +#define BME680_COEFF_ADDR1_LEN UINT8_C(25) +#define BME680_COEFF_ADDR2_LEN UINT8_C(16) +#define BME680_COEFF_ADDR1 UINT8_C(0x89) +#define BME680_COEFF_ADDR2 UINT8_C(0xe1) +#define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) +#define BME680_T2_LSB_REG (1) +#define BME680_T2_MSB_REG (2) +#define BME680_T3_REG (3) +#define BME680_P1_LSB_REG (5) +#define BME680_P1_MSB_REG (6) +#define BME680_P2_LSB_REG (7) +#define BME680_P2_MSB_REG (8) +#define BME680_P3_REG (9) +#define BME680_P4_LSB_REG (11) +#define BME680_P4_MSB_REG (12) +#define BME680_P5_LSB_REG (13) +#define BME680_P5_MSB_REG (14) +#define BME680_P7_REG (15) +#define BME680_P6_REG (16) +#define BME680_P8_LSB_REG (19) +#define BME680_P8_MSB_REG (20) +#define BME680_P9_LSB_REG (21) +#define BME680_P9_MSB_REG (22) +#define BME680_P10_REG (23) +#define BME680_H2_MSB_REG (25) +#define BME680_H2_LSB_REG (26) +#define BME680_H1_LSB_REG (26) +#define BME680_H1_MSB_REG (27) +#define BME680_H3_REG (28) +#define BME680_H4_REG (29) +#define BME680_H5_REG (30) +#define BME680_H6_REG (31) +#define BME680_H7_REG (32) +#define BME680_T1_LSB_REG (33) +#define BME680_T1_MSB_REG (34) +#define BME680_GH2_LSB_REG (35) +#define BME680_GH2_MSB_REG (36) +#define BME680_GH1_REG (37) +#define BME680_GH3_REG (38) +#define BME680_HUM_REG_SHIFT_VAL UINT8_C(4) +#define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F) + +static bool BME680_readCalValues(I2CSensor* i2c_sensor) { + BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; + uint8_t coeff_array[BME680_COEFF_SIZE] = {0}; + + if(!unitemp_i2c_readRegArray( + i2c_sensor, BME680_COEFF_ADDR1, BME680_COEFF_ADDR1_LEN, &coeff_array[0])) + return false; + if(!unitemp_i2c_readRegArray( + i2c_sensor, + BME680_COEFF_ADDR2, + BME680_COEFF_ADDR2_LEN, + &coeff_array[BME680_COEFF_ADDR1_LEN])) + return false; + + /* Temperature related coefficients */ + bme680_instance->temp_cal.dig_T1 = (uint16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_T1_MSB_REG], coeff_array[BME680_T1_LSB_REG])); + bme680_instance->temp_cal.dig_T2 = (int16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_T2_MSB_REG], coeff_array[BME680_T2_LSB_REG])); + bme680_instance->temp_cal.dig_T3 = (int8_t)(coeff_array[BME680_T3_REG]); + + /* Pressure related coefficients */ + bme680_instance->press_cal.dig_P1 = (uint16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_P1_MSB_REG], coeff_array[BME680_P1_LSB_REG])); + bme680_instance->press_cal.dig_P2 = (int16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_P2_MSB_REG], coeff_array[BME680_P2_LSB_REG])); + bme680_instance->press_cal.dig_P3 = (int8_t)coeff_array[BME680_P3_REG]; + bme680_instance->press_cal.dig_P4 = (int16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_P4_MSB_REG], coeff_array[BME680_P4_LSB_REG])); + bme680_instance->press_cal.dig_P5 = (int16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_P5_MSB_REG], coeff_array[BME680_P5_LSB_REG])); + bme680_instance->press_cal.dig_P6 = (int8_t)(coeff_array[BME680_P6_REG]); + bme680_instance->press_cal.dig_P7 = (int8_t)(coeff_array[BME680_P7_REG]); + bme680_instance->press_cal.dig_P8 = (int16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_P8_MSB_REG], coeff_array[BME680_P8_LSB_REG])); + bme680_instance->press_cal.dig_P9 = (int16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_P9_MSB_REG], coeff_array[BME680_P9_LSB_REG])); + bme680_instance->press_cal.dig_P10 = (uint8_t)(coeff_array[BME680_P10_REG]); + + /* Humidity related coefficients */ + bme680_instance->hum_cal.dig_H1 = + (uint16_t)(((uint16_t)coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK)); + bme680_instance->hum_cal.dig_H2 = + (uint16_t)(((uint16_t)coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL)); + bme680_instance->hum_cal.dig_H3 = (int8_t)coeff_array[BME680_H3_REG]; + bme680_instance->hum_cal.dig_H4 = (int8_t)coeff_array[BME680_H4_REG]; + bme680_instance->hum_cal.dig_H5 = (int8_t)coeff_array[BME680_H5_REG]; + bme680_instance->hum_cal.dig_H6 = (uint8_t)coeff_array[BME680_H6_REG]; + bme680_instance->hum_cal.dig_H7 = (int8_t)coeff_array[BME680_H7_REG]; + + /* Gas heater related coefficients */ + bme680_instance->gas_cal.dig_GH1 = (int8_t)coeff_array[BME680_GH1_REG]; + bme680_instance->gas_cal.dig_GH2 = (int16_t)(BME680_CONCAT_BYTES( + coeff_array[BME680_GH2_MSB_REG], coeff_array[BME680_GH2_LSB_REG])); + bme680_instance->gas_cal.dig_GH3 = (int8_t)coeff_array[BME680_GH3_REG]; + +#ifdef UNITEMP_DEBUG + FURI_LOG_D( + APP_NAME, + "Sensor BME680 T1-T3: %d, %d, %d", + bme680_instance->temp_cal.dig_T1, + bme680_instance->temp_cal.dig_T2, + bme680_instance->temp_cal.dig_T3); + + FURI_LOG_D( + APP_NAME, + "Sensor BME680: P1-P10: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", + bme680_instance->press_cal.dig_P1, + bme680_instance->press_cal.dig_P2, + bme680_instance->press_cal.dig_P3, + bme680_instance->press_cal.dig_P4, + bme680_instance->press_cal.dig_P5, + bme680_instance->press_cal.dig_P6, + bme680_instance->press_cal.dig_P7, + bme680_instance->press_cal.dig_P8, + bme680_instance->press_cal.dig_P9, + bme680_instance->press_cal.dig_P10); + + FURI_LOG_D( + APP_NAME, + "Sensor BME680: H1-H7: %d, %d, %d, %d, %d, %d, %d", + bme680_instance->hum_cal.dig_H1, + bme680_instance->hum_cal.dig_H2, + bme680_instance->hum_cal.dig_H3, + bme680_instance->hum_cal.dig_H4, + bme680_instance->hum_cal.dig_H5, + bme680_instance->hum_cal.dig_H6, + bme680_instance->hum_cal.dig_H7); + + FURI_LOG_D( + APP_NAME, + "Sensor BME680 GH1-GH3: %d, %d, %d", + bme680_instance->gas_cal.dig_GH1, + bme680_instance->gas_cal.dig_GH2, + bme680_instance->gas_cal.dig_GH3); + +#endif + + bme680_instance->last_cal_update_time = furi_get_tick(); + return true; +} +static bool BME680_isMeasuring(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + return (bool)(unitemp_i2c_readReg(i2c_sensor, BME680_REG_STATUS) & 0x20); +} + +bool unitemp_BME680_alloc(Sensor* sensor, char* args) { + UNUSED(args); + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + BME680_instance* bme680_instance = malloc(sizeof(BME680_instance)); + if(bme680_instance == NULL) { + FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name); + return false; + } + + if(sensor->type == &BME680) bme680_instance->chip_id = BME680_ID; + + i2c_sensor->sensorInstance = bme680_instance; + + i2c_sensor->minI2CAdr = BME680_I2C_ADDR_MIN; + i2c_sensor->maxI2CAdr = BME680_I2C_ADDR_MAX; + return true; +} + +bool unitemp_BME680_init(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + //Перезагрузка + unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6); + //Чтение ID датчика + uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); + if(id != BME680_ID) { + FURI_LOG_E( + APP_NAME, + "Sensor %s returned wrong ID 0x%02X, expected 0x%02X", + sensor->name, + id, + BME680_ID); + return false; + } + + unitemp_i2c_writeReg( + i2c_sensor, + BME680_REG_CTRL_HUM, + (unitemp_i2c_readReg(i2c_sensor, BME680_REG_CTRL_HUM) & ~7) | BME680_HUM_OVERSAMPLING_1); + unitemp_i2c_writeReg( + i2c_sensor, + BME680_REG_CTRL_MEAS, + BME680_TEMP_OVERSAMPLING_2 | BME680_PRESS_OVERSAMPLING_4 | BME680_MODE_FORCED); + //Настройка периода опроса и фильтрации значений + unitemp_i2c_writeReg( + i2c_sensor, BME680_REG_CONFIG, BME680_FILTER_COEFF_16 | BME680_SPI_3W_DISABLE); + //Чтение калибровочных значений + if(!BME680_readCalValues(i2c_sensor)) { + FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name); + return false; + } + return true; +} + +bool unitemp_BME680_deinit(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + //Перевод в сон + unitemp_i2c_writeReg(i2c_sensor, BME680_REG_CTRL_MEAS, BME680_MODE_SLEEP); + return true; +} + +UnitempStatus unitemp_BME680_update(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + BME680_instance* instance = i2c_sensor->sensorInstance; + + uint32_t t = furi_get_tick(); + + uint8_t buff[3]; + //Проверка инициализированности датчика + unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff); + if(buff[0] == 0) { + FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name); + return UT_SENSORSTATUS_ERROR; + } + + unitemp_i2c_writeReg( + i2c_sensor, + BME680_REG_CTRL_MEAS, + unitemp_i2c_readReg(i2c_sensor, BME680_REG_CTRL_MEAS) | 1); + + while(BME680_isMeasuring(sensor)) { + if(furi_get_tick() - t > 100) { + return UT_SENSORSTATUS_TIMEOUT; + } + } + + if(furi_get_tick() - instance->last_cal_update_time > BOSCH_CAL_UPDATE_INTERVAL) { + BME680_readCalValues(i2c_sensor); + } + + if(!unitemp_i2c_readRegArray(i2c_sensor, 0x1F, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; + int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); + if(!unitemp_i2c_readRegArray(i2c_sensor, 0x22, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; + int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); + if(!unitemp_i2c_readRegArray(i2c_sensor, 0x25, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; + int32_t adc_H = ((uint16_t)buff[0] << 8) | buff[1]; + + sensor->temp = BME680_compensate_temperature(i2c_sensor, adc_T); + sensor->pressure = BME680_compensate_pressure(i2c_sensor, adc_P); + sensor->hum = BME680_compensate_humidity(i2c_sensor, adc_H); + + return UT_SENSORSTATUS_OK; +} + +bool unitemp_BME680_free(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + free(i2c_sensor->sensorInstance); + return true; +} \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/BME680.h b/applications/plugins/unitemp/sensors/BME680.h new file mode 100644 index 000000000..b126c7c84 --- /dev/null +++ b/applications/plugins/unitemp/sensors/BME680.h @@ -0,0 +1,112 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + Contributed by g0gg0 (https://github.com/g3gg0) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_BME680 +#define UNITEMP_BME680 + +#include "../unitemp.h" +#include "../Sensors.h" +#include "../interfaces/I2CSensor.h" + +typedef struct { + uint16_t dig_T1; + int16_t dig_T2; + int16_t dig_T3; +} BME680_temp_cal; + +typedef struct { + uint16_t dig_GH1; + int16_t dig_GH2; + int16_t dig_GH3; +} BME680_gas_cal; + +typedef struct { + uint16_t dig_P1; + int16_t dig_P2; + int16_t dig_P3; + int16_t dig_P4; + int16_t dig_P5; + int16_t dig_P6; + int16_t dig_P7; + int16_t dig_P8; + int16_t dig_P9; + int16_t dig_P10; +} BME680_press_cal; + +typedef struct { + uint16_t dig_H1; + uint16_t dig_H2; + int8_t dig_H3; + int8_t dig_H4; + int8_t dig_H5; + uint8_t dig_H6; + int8_t dig_H7; +} BME680_hum_cal; + +typedef struct { + //Калибровочные значения температуры + BME680_temp_cal temp_cal; + //Калибровочные значения давления + BME680_press_cal press_cal; + //Калибровочные значения влажности воздуха + BME680_hum_cal hum_cal; + BME680_gas_cal gas_cal; + //Время последнего обновления калибровочных значений + uint32_t last_cal_update_time; + //Индификатор датчика + uint8_t chip_id; + //Корректировочное значение температуры + int32_t t_fine; +} BME680_instance; + +extern const SensorType BMP280; +extern const SensorType BME680; +/** + * @brief Выделение памяти и установка начальных значений датчика BMP280 + * @param sensor Указатель на создаваемый датчик + * @return Истина при успехе + */ +bool unitemp_BME680_alloc(Sensor* sensor, char* args); + +/** + * @brief Инициализации датчика BMP280 + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_BME680_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * @param sensor Указатель на датчик + */ +bool unitemp_BME680_deinit(Sensor* sensor); + +/** + * @brief Обновление значений из датчика + * @param sensor Указатель на датчик + * @return Статус опроса датчика + */ +UnitempStatus unitemp_BME680_update(Sensor* sensor); + +/** + * @brief Высвободить память датчика + * @param sensor Указатель на датчик + */ +bool unitemp_BME680_free(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/BMP180.c b/applications/plugins/unitemp/sensors/BMP180.c new file mode 100644 index 000000000..aa0198289 --- /dev/null +++ b/applications/plugins/unitemp/sensors/BMP180.c @@ -0,0 +1,171 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#include "BMP180.h" +#include "../interfaces/I2CSensor.h" + +typedef struct { + int16_t AC1; + int16_t AC2; + int16_t AC3; + uint16_t AC4; + uint16_t AC5; + uint16_t AC6; + int16_t B1; + int16_t B2; + int16_t MB; + int16_t MC; + int16_t MD; +} BMP180_cal; + +typedef struct { + //Калибровочные значения + BMP180_cal bmp180_cal; +} BMP180_instance; + +const SensorType BMP180 = { + .typename = "BMP180", + .interface = &I2C, + .datatype = UT_TEMPERATURE | UT_PRESSURE, + .pollingInterval = 1000, + .allocator = unitemp_BMP180_I2C_alloc, + .mem_releaser = unitemp_BMP180_I2C_free, + .initializer = unitemp_BMP180_init, + .deinitializer = unitemp_BMP180_I2C_deinit, + .updater = unitemp_BMP180_I2C_update}; + +bool unitemp_BMP180_I2C_alloc(Sensor* sensor, char* args) { + UNUSED(args); + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + //Адреса на шине I2C (7 бит) + i2c_sensor->minI2CAdr = 0x77 << 1; + i2c_sensor->maxI2CAdr = 0x77 << 1; + + BMP180_instance* bmx280_instance = malloc(sizeof(BMP180_instance)); + i2c_sensor->sensorInstance = bmx280_instance; + return true; +} + +bool unitemp_BMP180_I2C_free(Sensor* sensor) { + UNUSED(sensor); + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + free(i2c_sensor->sensorInstance); + return true; +} + +bool unitemp_BMP180_init(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + //Перезагрузка + if(!unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6)) return false; + furi_delay_ms(100); + + //Проверка ID + uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); + if(id != 0x55) { + FURI_LOG_E( + APP_NAME, "Sensor %s returned wrong ID 0x%02X, expected 0x55", sensor->name, id); + return false; + } + + BMP180_instance* bmp180_instance = i2c_sensor->sensorInstance; + + uint8_t buff[22] = {0}; + + //Чтение калибровочных значений + if(!unitemp_i2c_readRegArray(i2c_sensor, 0xAA, 22, buff)) return false; + bmp180_instance->bmp180_cal.AC1 = (buff[0] << 8) | buff[1]; + bmp180_instance->bmp180_cal.AC2 = (buff[2] << 8) | buff[3]; + bmp180_instance->bmp180_cal.AC3 = (buff[4] << 8) | buff[5]; + bmp180_instance->bmp180_cal.AC4 = (buff[6] << 8) | buff[7]; + bmp180_instance->bmp180_cal.AC5 = (buff[8] << 8) | buff[9]; + bmp180_instance->bmp180_cal.AC6 = (buff[10] << 8) | buff[11]; + bmp180_instance->bmp180_cal.B1 = (buff[12] << 8) | buff[13]; + bmp180_instance->bmp180_cal.B2 = (buff[14] << 8) | buff[15]; + bmp180_instance->bmp180_cal.MB = (buff[16] << 8) | buff[17]; + bmp180_instance->bmp180_cal.MC = (buff[18] << 8) | buff[19]; + bmp180_instance->bmp180_cal.MD = (buff[20] << 8) | buff[21]; + + UNITEMP_DEBUG( + "Sensor BMP180 (0x%02X) calibration values: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", + i2c_sensor->currentI2CAdr, + bmp180_instance->bmp180_cal.AC1, + bmp180_instance->bmp180_cal.AC2, + bmp180_instance->bmp180_cal.AC3, + bmp180_instance->bmp180_cal.AC4, + bmp180_instance->bmp180_cal.AC5, + bmp180_instance->bmp180_cal.AC6, + bmp180_instance->bmp180_cal.B1, + bmp180_instance->bmp180_cal.B2, + bmp180_instance->bmp180_cal.MB, + bmp180_instance->bmp180_cal.MC, + bmp180_instance->bmp180_cal.MD); + return true; +} + +bool unitemp_BMP180_I2C_deinit(Sensor* sensor) { + //Нечего деинициализировать + UNUSED(sensor); + return true; +} + +UnitempStatus unitemp_BMP180_I2C_update(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + BMP180_instance* bmp180_instance = i2c_sensor->sensorInstance; + + //Чтение температуры + if(!unitemp_i2c_writeReg(i2c_sensor, 0xF4, 0x2E)) return UT_SENSORSTATUS_TIMEOUT; + furi_delay_ms(5); + uint8_t buff[3] = {0}; + if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF6, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; + int32_t UT = ((uint16_t)buff[0] << 8) + buff[1]; + int32_t X1 = (UT - bmp180_instance->bmp180_cal.AC6) * bmp180_instance->bmp180_cal.AC5 >> 15; + int32_t X2 = (bmp180_instance->bmp180_cal.MC << 11) / (X1 + bmp180_instance->bmp180_cal.MD); + int32_t B5 = X1 + X2; + sensor->temp = ((B5 + 8) / 16) * 0.1f; + + //Чтение давления + if(!unitemp_i2c_writeReg(i2c_sensor, 0xF4, 0x34 + (0b11 << 6))) return UT_SENSORSTATUS_TIMEOUT; + furi_delay_ms(26); + if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF6, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; + uint32_t UP = ((buff[0] << 16) + (buff[1] << 8) + buff[2]) >> (8 - 0b11); + + int32_t B6, X3, B3, P; + uint32_t B4, B7; + B6 = B5 - 4000; + X1 = (bmp180_instance->bmp180_cal.B2 * ((B6 * B6) >> 12)) >> 11; + X2 = (bmp180_instance->bmp180_cal.AC2 * B6) >> 11; + X3 = X1 + X2; + B3 = (((bmp180_instance->bmp180_cal.AC1 * 4 + X3) << 0b11) + 2) >> 2; + X1 = (bmp180_instance->bmp180_cal.AC3 * B6) >> 13; + X2 = (bmp180_instance->bmp180_cal.B1 * ((B6 * B6) >> 12)) >> 16; + X3 = ((X1 + X2) + 2) >> 2; + B4 = (bmp180_instance->bmp180_cal.AC4 * (unsigned long)(X3 + 32768)) >> 15; + B7 = ((unsigned long)UP - B3) * (50000 >> 0b11); + if(B7 < 0x80000000) + P = (B7 * 2) / B4; + else + P = (B7 / B4) * 2; + X1 = (P >> 8) * (P >> 8); + X1 = (X1 * 3038) >> 16; + X2 = (-7357 * (P)) >> 16; + P = P + ((X1 + X2 + 3791) >> 4); + sensor->pressure = P; + + return UT_SENSORSTATUS_OK; +} diff --git a/applications/plugins/unitemp/sensors/BMP180.h b/applications/plugins/unitemp/sensors/BMP180.h new file mode 100644 index 000000000..ce2569092 --- /dev/null +++ b/applications/plugins/unitemp/sensors/BMP180.h @@ -0,0 +1,62 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_BMP180 +#define UNITEMP_BMP180 + +#include "../unitemp.h" +#include "../Sensors.h" +extern const SensorType BMP180; +/** + * @brief Выделение памяти и установка начальных значений датчика BMP180 + * + * @param sensor Указатель на создаваемый датчик + * @return Истина при успехе + */ +bool unitemp_BMP180_I2C_alloc(Sensor* sensor, char* args); + +/** + * @brief Инициализации датчика BMP180 + * + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_BMP180_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_BMP180_I2C_deinit(Sensor* sensor); + +/** + * @brief Обновление значений из датчика + * + * @param sensor Указатель на датчик + * @return Статус обновления + */ +UnitempStatus unitemp_BMP180_I2C_update(Sensor* sensor); + +/** + * @brief Высвободить память датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_BMP180_I2C_free(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/BMx280.c b/applications/plugins/unitemp/sensors/BMx280.c index a64daaa1d..db445d330 100644 --- a/applications/plugins/unitemp/sensors/BMx280.c +++ b/applications/plugins/unitemp/sensors/BMx280.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -180,22 +180,19 @@ static bool bmx280_readCalValues(I2CSensor* i2c_sensor) { if(!unitemp_i2c_readRegArray( i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmx280_instance->temp_cal)) return false; -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, + + UNITEMP_DEBUG( "Sensor BMx280 (0x%02X) T1-T3: %d, %d, %d", i2c_sensor->currentI2CAdr, bmx280_instance->temp_cal.dig_T1, bmx280_instance->temp_cal.dig_T2, bmx280_instance->temp_cal.dig_T3); -#endif if(!unitemp_i2c_readRegArray( i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmx280_instance->press_cal)) return false; -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, + + UNITEMP_DEBUG( "Sensor BMx280 (0x%02X): P1-P9: %d, %d, %d, %d, %d, %d, %d, %d, %d", i2c_sensor->currentI2CAdr, bmx280_instance->press_cal.dig_P1, @@ -207,7 +204,6 @@ static bool bmx280_readCalValues(I2CSensor* i2c_sensor) { bmx280_instance->press_cal.dig_P7, bmx280_instance->press_cal.dig_P8, bmx280_instance->press_cal.dig_P9); -#endif if(bmx280_instance->chip_id == BME280_ID) { uint8_t buff[7] = {0}; @@ -221,9 +217,7 @@ static bool bmx280_readCalValues(I2CSensor* i2c_sensor) { bmx280_instance->hum_cal.dig_H5 = (buff[4] & 0x0F) | ((int16_t)buff[5] << 4); bmx280_instance->hum_cal.dig_H6 = buff[6]; -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, + UNITEMP_DEBUG( "Sensor BMx280 (0x%02X): H1-H6: %d, %d, %d, %d, %d, %d", i2c_sensor->currentI2CAdr, bmx280_instance->hum_cal.dig_H1, @@ -232,7 +226,6 @@ static bool bmx280_readCalValues(I2CSensor* i2c_sensor) { bmx280_instance->hum_cal.dig_H4, bmx280_instance->hum_cal.dig_H5, bmx280_instance->hum_cal.dig_H6); -#endif } bmx280_instance->last_cal_update_time = furi_get_tick(); diff --git a/applications/plugins/unitemp/sensors/BMx280.h b/applications/plugins/unitemp/sensors/BMx280.h index fe52a364e..32027f285 100644 --- a/applications/plugins/unitemp/sensors/BMx280.h +++ b/applications/plugins/unitemp/sensors/BMx280.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/sensors/DHT20.c b/applications/plugins/unitemp/sensors/DHT20.c new file mode 100644 index 000000000..ce11fe3d6 --- /dev/null +++ b/applications/plugins/unitemp/sensors/DHT20.c @@ -0,0 +1,154 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#include "DHT20.h" +#include "../interfaces/I2CSensor.h" + +const SensorType DHT20 = { + .typename = "DHT20", + .altname = "DHT20/AM2108/AHT20", + .interface = &I2C, + .datatype = UT_TEMPERATURE | UT_HUMIDITY, + .pollingInterval = 1000, + .allocator = unitemp_DHT20_I2C_alloc, + .mem_releaser = unitemp_DHT20_I2C_free, + .initializer = unitemp_DHT20_init, + .deinitializer = unitemp_DHT20_I2C_deinit, + .updater = unitemp_DHT20_I2C_update}; +const SensorType AHT10 = { + .typename = "AHT10", + .interface = &I2C, + .datatype = UT_TEMPERATURE | UT_HUMIDITY, + .pollingInterval = 1000, + .allocator = unitemp_DHT20_I2C_alloc, + .mem_releaser = unitemp_DHT20_I2C_free, + .initializer = unitemp_DHT20_init, + .deinitializer = unitemp_DHT20_I2C_deinit, + .updater = unitemp_DHT20_I2C_update}; + +static uint8_t DHT20_get_status(I2CSensor* i2c_sensor) { + uint8_t status[1] = {0}; + unitemp_i2c_readArray(i2c_sensor, 1, status); + return status[0]; +} + +static uint8_t DHT20_calc_CRC8(uint8_t* message, uint8_t Num) { + uint8_t i; + uint8_t byte; + uint8_t crc = 0xFF; + for(byte = 0; byte < Num; byte++) { + crc ^= (message[byte]); + for(i = 8; i > 0; --i) { + if(crc & 0x80) + crc = (crc << 1) ^ 0x31; + else + crc = (crc << 1); + } + } + return crc; +} + +static void DHT20_reset_reg(I2CSensor* i2c_sensor, uint8_t addr) { + uint8_t data[3] = {addr, 0x00, 0x00}; + + unitemp_i2c_writeArray(i2c_sensor, 3, data); + + furi_delay_ms(5); + + unitemp_i2c_readArray(i2c_sensor, 3, data); + + furi_delay_ms(10); + + data[0] = 0xB0 | addr; + unitemp_i2c_writeArray(i2c_sensor, 3, data); +} + +bool unitemp_DHT20_I2C_alloc(Sensor* sensor, char* args) { + UNUSED(args); + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + //Адреса на шине I2C (7 бит) + i2c_sensor->minI2CAdr = 0x38 << 1; + i2c_sensor->maxI2CAdr = (sensor->type == &DHT20) ? (0x38 << 1) : (0x39 << 1); + return true; +} + +bool unitemp_DHT20_I2C_free(Sensor* sensor) { + //Нечего высвобождать, так как ничего не было выделено + UNUSED(sensor); + return true; +} + +bool unitemp_DHT20_init(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + uint8_t data[3] = {0xA8, 0x00, 0x00}; + if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return false; + furi_delay_ms(10); + data[0] = (sensor->type == &DHT20) ? 0xBE : 0xE1; + data[1] = 0x08; + if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return false; + furi_delay_ms(10); + + return true; +} + +bool unitemp_DHT20_I2C_deinit(Sensor* sensor) { + //Нечего деинициализировать + UNUSED(sensor); + return true; +} + +UnitempStatus unitemp_DHT20_I2C_update(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + if(DHT20_get_status(i2c_sensor) != 0x18) { + DHT20_reset_reg(i2c_sensor, 0x1B); + DHT20_reset_reg(i2c_sensor, 0x1C); + DHT20_reset_reg(i2c_sensor, 0x1E); + } + furi_delay_ms(10); + + uint8_t data[7] = {0xAC, 0x33, 0x00}; + if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT; + furi_delay_ms(80); + uint32_t t = furi_get_tick(); + while(DHT20_get_status(i2c_sensor) == 0x80) { + if(furi_get_tick() - t > 10) return UT_SENSORSTATUS_TIMEOUT; + } + + if(!unitemp_i2c_readArray(i2c_sensor, 7, data)) return UT_SENSORSTATUS_TIMEOUT; + + if(DHT20_calc_CRC8(data, 6) != data[6]) { + return UT_SENSORSTATUS_BADCRC; + } + uint32_t RetuData = 0; + RetuData = (RetuData | data[1]) << 8; + RetuData = (RetuData | data[2]) << 8; + RetuData = (RetuData | data[3]); + RetuData = RetuData >> 4; + sensor->hum = RetuData * 100 * 10 / 1024.0f / 1024.0f / 10.0f; + + RetuData = 0; + RetuData = (RetuData | data[3]) << 8; + RetuData = (RetuData | data[4]) << 8; + RetuData = (RetuData | data[5]); + RetuData = RetuData & 0xfffff; + sensor->temp = (RetuData * 200 * 10.0f / 1024.0f / 1024.0f - 500) / 10.0f; + + return UT_SENSORSTATUS_OK; +} diff --git a/applications/plugins/unitemp/sensors/DHT20.h b/applications/plugins/unitemp/sensors/DHT20.h new file mode 100644 index 000000000..417b0ed1d --- /dev/null +++ b/applications/plugins/unitemp/sensors/DHT20.h @@ -0,0 +1,63 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_DHT20 +#define UNITEMP_DHT20 + +#include "../unitemp.h" +#include "../Sensors.h" +extern const SensorType DHT20; +extern const SensorType AHT10; +/** + * @brief Выделение памяти и установка начальных значений датчика DHT20 + * + * @param sensor Указатель на создаваемый датчик + * @return Истина при успехе + */ +bool unitemp_DHT20_I2C_alloc(Sensor* sensor, char* args); + +/** + * @brief Инициализации датчика DHT20 + * + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_DHT20_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_DHT20_I2C_deinit(Sensor* sensor); + +/** + * @brief Обновление значений из датчика + * + * @param sensor Указатель на датчик + * @return Статус обновления + */ +UnitempStatus unitemp_DHT20_I2C_update(Sensor* sensor); + +/** + * @brief Высвободить память датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_DHT20_I2C_free(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/HDC1080.c b/applications/plugins/unitemp/sensors/HDC1080.c new file mode 100644 index 000000000..5f2c59b24 --- /dev/null +++ b/applications/plugins/unitemp/sensors/HDC1080.c @@ -0,0 +1,94 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#include "HDC1080.h" +#include "../interfaces/I2CSensor.h" + +const SensorType HDC1080 = { + .typename = "HDC1080", + .interface = &I2C, + .datatype = UT_DATA_TYPE_TEMP_HUM, + .pollingInterval = 250, + .allocator = unitemp_HDC1080_alloc, + .mem_releaser = unitemp_HDC1080_free, + .initializer = unitemp_HDC1080_init, + .deinitializer = unitemp_HDC1080_deinit, + .updater = unitemp_HDC1080_update}; + +bool unitemp_HDC1080_alloc(Sensor* sensor, char* args) { + UNUSED(args); + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + //Адреса на шине I2C (7 бит) + i2c_sensor->minI2CAdr = 0x40 << 1; + i2c_sensor->maxI2CAdr = 0x40 << 1; + return true; +} + +bool unitemp_HDC1080_free(Sensor* sensor) { + //Нечего высвобождать, так как ничего не было выделено + UNUSED(sensor); + return true; +} + +bool unitemp_HDC1080_init(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + uint8_t data[2]; + if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFF, 2, data)) return UT_SENSORSTATUS_TIMEOUT; + uint16_t device_id = ((uint16_t)data[0] << 8) | data[1]; + if(device_id != 0x1050) { + FURI_LOG_E( + APP_NAME, + "Sensor %s returned wrong ID 0x%02X, expected 0x1050", + sensor->name, + device_id); + return false; + } + data[0] = 0b0001000; + data[1] = 0; + //Установка режима работы и разрядности измерений + if(!unitemp_i2c_writeRegArray(i2c_sensor, 0x02, 2, data)) return UT_SENSORSTATUS_TIMEOUT; + + return true; +} + +bool unitemp_HDC1080_deinit(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + UNUSED(i2c_sensor); + return true; +} + +UnitempStatus unitemp_HDC1080_update(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + uint8_t data[2] = {0}; + //Запуск измерения + if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; + furi_delay_ms(10); + if(!unitemp_i2c_readArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; + + sensor->temp = ((float)(((uint16_t)data[0] << 8) | data[1]) / 65536) * 165 - 40; + + data[0] = 1; + if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; + furi_delay_ms(10); + if(!unitemp_i2c_readArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; + sensor->hum = ((float)(((uint16_t)data[0] << 8) | data[1]) / 65536) * 100; + + return UT_SENSORSTATUS_OK; +} diff --git a/applications/plugins/unitemp/sensors/HDC1080.h b/applications/plugins/unitemp/sensors/HDC1080.h new file mode 100644 index 000000000..59ba0673c --- /dev/null +++ b/applications/plugins/unitemp/sensors/HDC1080.h @@ -0,0 +1,62 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_HDC1080 +#define UNITEMP_HDC1080 + +#include "../unitemp.h" +#include "../Sensors.h" +extern const SensorType HDC1080; +/** + * @brief Выделение памяти и установка начальных значений датчика HDC1080 + * + * @param sensor Указатель на создаваемый датчик + * @return Истина при успехе + */ +bool unitemp_HDC1080_alloc(Sensor* sensor, char* args); + +/** + * @brief Инициализации датчика HDC1080 + * + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_HDC1080_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_HDC1080_deinit(Sensor* sensor); + +/** + * @brief Обновление значений из датчика + * + * @param sensor Указатель на датчик + * @return Статус обновления + */ +UnitempStatus unitemp_HDC1080_update(Sensor* sensor); + +/** + * @brief Высвободить память датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_HDC1080_free(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/HTU21x.c b/applications/plugins/unitemp/sensors/HTU21x.c new file mode 100644 index 000000000..2e7222bc4 --- /dev/null +++ b/applications/plugins/unitemp/sensors/HTU21x.c @@ -0,0 +1,107 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#include "HTU21x.h" +#include "../interfaces/I2CSensor.h" + +const SensorType HTU21x = { + .typename = "HTU21x", + .altname = "HTU21x/SI70xx/SHT2x", + .interface = &I2C, + .datatype = UT_DATA_TYPE_TEMP_HUM, + .pollingInterval = 250, + .allocator = unitemp_HTU21x_alloc, + .mem_releaser = unitemp_HTU21x_free, + .initializer = unitemp_HTU21x_init, + .deinitializer = unitemp_HTU21x_deinit, + .updater = unitemp_HTU21x_update}; + +static uint8_t checkCRC(uint16_t data) { + for(uint8_t i = 0; i < 16; i++) { + if(data & 0x8000) + data = (data << 1) ^ 0x13100; + else + data <<= 1; + } + return (data >> 8); +} + +bool unitemp_HTU21x_alloc(Sensor* sensor, char* args) { + UNUSED(args); + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + //Адреса на шине I2C (7 бит) + i2c_sensor->minI2CAdr = 0x40 << 1; + i2c_sensor->maxI2CAdr = 0x41 << 1; + return true; +} + +bool unitemp_HTU21x_free(Sensor* sensor) { + //Нечего высвобождать, так как ничего не было выделено + UNUSED(sensor); + return true; +} + +bool unitemp_HTU21x_init(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + UNUSED(i2c_sensor); + return true; +} + +bool unitemp_HTU21x_deinit(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + UNUSED(i2c_sensor); + return true; +} + +UnitempStatus unitemp_HTU21x_update(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + //Датчик может быть всего один, так что норм + static bool temp_hum = false; + + uint8_t data[3]; + + if(sensor->status == UT_SENSORSTATUS_POLLING) { + if(!unitemp_i2c_readArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT; + + uint16_t raw = ((uint16_t)data[0] << 8) | data[1]; + if(checkCRC(raw) != data[2]) return UT_SENSORSTATUS_BADCRC; + + if(temp_hum) { + sensor->temp = (0.002681f * raw - 46.85f); + } else { + sensor->hum = ((0.001907 * (raw ^ 0x02)) - 6); + } + temp_hum = !temp_hum; + if(temp_hum) return UT_SENSORSTATUS_EARLYPOOL; + return UT_SENSORSTATUS_OK; + } + + if(temp_hum) { + //Запрос температуры + data[0] = 0xF3; + if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; + } else { + //Запрос влажности + data[0] = 0xF5; + if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; + } + + return UT_SENSORSTATUS_POLLING; +} diff --git a/applications/plugins/unitemp/sensors/HTU21x.h b/applications/plugins/unitemp/sensors/HTU21x.h new file mode 100644 index 000000000..ffe062a24 --- /dev/null +++ b/applications/plugins/unitemp/sensors/HTU21x.h @@ -0,0 +1,62 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_HTU21x +#define UNITEMP_HTU21x + +#include "../unitemp.h" +#include "../Sensors.h" +extern const SensorType HTU21x; +/** + * @brief Выделение памяти и установка начальных значений датчика HTU21x + * + * @param sensor Указатель на создаваемый датчик + * @return Истина при успехе + */ +bool unitemp_HTU21x_alloc(Sensor* sensor, char* args); + +/** + * @brief Инициализации датчика HTU21x + * + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_HTU21x_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_HTU21x_deinit(Sensor* sensor); + +/** + * @brief Обновление значений из датчика + * + * @param sensor Указатель на датчик + * @return Статус обновления + */ +UnitempStatus unitemp_HTU21x_update(Sensor* sensor); + +/** + * @brief Высвободить память датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_HTU21x_free(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/LM75.c b/applications/plugins/unitemp/sensors/LM75.c index e71376404..a9c8df84e 100644 --- a/applications/plugins/unitemp/sensors/LM75.c +++ b/applications/plugins/unitemp/sensors/LM75.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/sensors/LM75.h b/applications/plugins/unitemp/sensors/LM75.h index dc1fb791c..d5397b178 100644 --- a/applications/plugins/unitemp/sensors/LM75.h +++ b/applications/plugins/unitemp/sensors/LM75.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/sensors/MAX31855.c b/applications/plugins/unitemp/sensors/MAX31855.c new file mode 100644 index 000000000..2411eb09e --- /dev/null +++ b/applications/plugins/unitemp/sensors/MAX31855.c @@ -0,0 +1,93 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#include "MAX31855.h" + +const SensorType MAX31855 = { + .typename = "MAX31855", + .altname = "MAX31855 (Thermocouple)", + .interface = &SPI, + .datatype = UT_TEMPERATURE, + .pollingInterval = 500, + .allocator = unitemp_MAX31855_alloc, + .mem_releaser = unitemp_MAX31855_free, + .initializer = unitemp_MAX31855_init, + .deinitializer = unitemp_MAX31855_deinit, + .updater = unitemp_MAX31855_update}; + +bool unitemp_MAX31855_alloc(Sensor* sensor, char* args) { + UNUSED(sensor); + UNUSED(args); + return true; +} + +bool unitemp_MAX31855_free(Sensor* sensor) { + UNUSED(sensor); + return true; +} + +bool unitemp_MAX31855_init(Sensor* sensor) { + SPISensor* instance = sensor->instance; + furi_hal_spi_bus_handle_init(instance->spi); + UNUSED(instance); + return true; +} + +bool unitemp_MAX31855_deinit(Sensor* sensor) { + UNUSED(sensor); + return true; +} + +UnitempStatus unitemp_MAX31855_update(Sensor* sensor) { + SPISensor* instance = sensor->instance; + + furi_hal_spi_acquire(instance->spi); + furi_hal_gpio_write(instance->CS_pin->pin, false); + + uint8_t buff[4] = {0}; + + furi_hal_spi_bus_rx(instance->spi, buff, 4, 0xFF); + furi_hal_spi_release(instance->spi); + + uint32_t raw = (buff[0] << 24) | (buff[1] << 16) | (buff[2] << 8) | buff[3]; + + if(raw == 0xFFFFFFFF || raw == 0) return UT_SENSORSTATUS_TIMEOUT; + + //Определение состояния термопары + uint8_t state = raw & 0b111; + //Обрыв + if(state == 0x01) { + UNITEMP_DEBUG("%s has thermocouple open circuit", sensor->name); + return UT_SENSORSTATUS_ERROR; + } + //Короткое замыкание к земле + if(state == 0x02) { + UNITEMP_DEBUG("%s has thermocouple short to GND", sensor->name); + return UT_SENSORSTATUS_ERROR; + } + //Короткое замыкание к питанию + if(state == 0x04) { + UNITEMP_DEBUG("%s has thermocouple short to VCC", sensor->name); + return UT_SENSORSTATUS_ERROR; + } + + raw = (raw >> 16) & 0xFFFC; + + sensor->temp = (int16_t)(raw) / 16.0f; + + return UT_SENSORSTATUS_OK; +} diff --git a/applications/plugins/unitemp/sensors/MAX31855.h b/applications/plugins/unitemp/sensors/MAX31855.h new file mode 100644 index 000000000..d63c39885 --- /dev/null +++ b/applications/plugins/unitemp/sensors/MAX31855.h @@ -0,0 +1,65 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_MAX31855 +#define UNITEMP_MAX31855 + +#include "../unitemp.h" +#include "../Sensors.h" +#include "../interfaces/SPISensor.h" + +extern const SensorType MAX31855; + +/** + * @brief Выделение памяти и установка начальных значений датчика MAX31855 + * + * @param sensor Указатель на создаваемый датчик + * @return Истина при успехе + */ +bool unitemp_MAX31855_alloc(Sensor* sensor, char* args); + +/** + * @brief Инициализации датчика MAX31855 + * + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_MAX31855_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_MAX31855_deinit(Sensor* sensor); + +/** + * @brief Обновление значений из датчика + * + * @param sensor Указатель на датчик + * @return Статус обновления + */ +UnitempStatus unitemp_MAX31855_update(Sensor* sensor); + +/** + * @brief Высвободить память датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_MAX31855_free(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/MAX6675.c b/applications/plugins/unitemp/sensors/MAX6675.c new file mode 100644 index 000000000..e97a96eb5 --- /dev/null +++ b/applications/plugins/unitemp/sensors/MAX6675.c @@ -0,0 +1,81 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#include "MAX6675.h" + +const SensorType MAX6675 = { + .typename = "MAX6675", + .altname = "MAX6675 (Thermocouple)", + .interface = &SPI, + .datatype = UT_TEMPERATURE, + .pollingInterval = 500, + .allocator = unitemp_MAX6675_alloc, + .mem_releaser = unitemp_MAX6675_free, + .initializer = unitemp_MAX6675_init, + .deinitializer = unitemp_MAX6675_deinit, + .updater = unitemp_MAX6675_update}; + +bool unitemp_MAX6675_alloc(Sensor* sensor, char* args) { + UNUSED(sensor); + UNUSED(args); + return true; +} + +bool unitemp_MAX6675_free(Sensor* sensor) { + UNUSED(sensor); + return true; +} + +bool unitemp_MAX6675_init(Sensor* sensor) { + SPISensor* instance = sensor->instance; + furi_hal_spi_bus_handle_init(instance->spi); + UNUSED(instance); + return true; +} + +bool unitemp_MAX6675_deinit(Sensor* sensor) { + UNUSED(sensor); + return true; +} + +UnitempStatus unitemp_MAX6675_update(Sensor* sensor) { + SPISensor* instance = sensor->instance; + + furi_hal_spi_acquire(instance->spi); + furi_hal_gpio_write(instance->CS_pin->pin, false); + + uint8_t buff[2] = {0}; + + furi_hal_spi_bus_rx(instance->spi, buff, 2, 0xFF); + furi_hal_spi_release(instance->spi); + + uint32_t raw = (buff[0] << 8) | buff[1]; + + if(raw == 0xFFFFFFFF || raw == 0) return UT_SENSORSTATUS_TIMEOUT; + + //Определение состояния термопары + uint8_t state = raw & 0b100; + //Обрыв + if(state == 0b100) { + UNITEMP_DEBUG("%s has thermocouple open circuit", sensor->name); + return UT_SENSORSTATUS_ERROR; + } + + sensor->temp = (int16_t)(raw) / 32.0f; + + return UT_SENSORSTATUS_OK; +} diff --git a/applications/plugins/unitemp/sensors/MAX6675.h b/applications/plugins/unitemp/sensors/MAX6675.h new file mode 100644 index 000000000..cce346590 --- /dev/null +++ b/applications/plugins/unitemp/sensors/MAX6675.h @@ -0,0 +1,65 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_MAX6675 +#define UNITEMP_MAX6675 + +#include "../unitemp.h" +#include "../Sensors.h" +#include "../interfaces/SPISensor.h" + +extern const SensorType MAX6675; + +/** + * @brief Выделение памяти и установка начальных значений датчика MAX6675 + * + * @param sensor Указатель на создаваемый датчик + * @return Истина при успехе + */ +bool unitemp_MAX6675_alloc(Sensor* sensor, char* args); + +/** + * @brief Инициализации датчика MAX6675 + * + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_MAX6675_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_MAX6675_deinit(Sensor* sensor); + +/** + * @brief Обновление значений из датчика + * + * @param sensor Указатель на датчик + * @return Статус обновления + */ +UnitempStatus unitemp_MAX6675_update(Sensor* sensor); + +/** + * @brief Высвободить память датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_MAX6675_free(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/SHT30.c b/applications/plugins/unitemp/sensors/SHT30.c new file mode 100644 index 000000000..dd43e80af --- /dev/null +++ b/applications/plugins/unitemp/sensors/SHT30.c @@ -0,0 +1,90 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#include "SHT30.h" +#include "../interfaces/I2CSensor.h" + +const SensorType SHT30 = { + .typename = "SHT30", + .altname = "SHT30/31/35", + .interface = &I2C, + .datatype = UT_TEMPERATURE | UT_HUMIDITY, + .pollingInterval = 1000, + .allocator = unitemp_SHT30_I2C_alloc, + .mem_releaser = unitemp_SHT30_I2C_free, + .initializer = unitemp_SHT30_init, + .deinitializer = unitemp_SHT30_I2C_deinit, + .updater = unitemp_SHT30_I2C_update}; +const SensorType GXHT30 = { + .typename = "GXHT30", + .altname = "GXHT30/31/35", + .interface = &I2C, + .datatype = UT_TEMPERATURE | UT_HUMIDITY, + .pollingInterval = 1000, + .allocator = unitemp_SHT30_I2C_alloc, + .mem_releaser = unitemp_SHT30_I2C_free, + .initializer = unitemp_GXHT30_init, + .deinitializer = unitemp_SHT30_I2C_deinit, + .updater = unitemp_SHT30_I2C_update}; + +bool unitemp_SHT30_I2C_alloc(Sensor* sensor, char* args) { + UNUSED(args); + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + + //Адреса на шине I2C (7 бит) + i2c_sensor->minI2CAdr = 0x44 << 1; + i2c_sensor->maxI2CAdr = 0x45 << 1; + return true; +} + +bool unitemp_SHT30_I2C_free(Sensor* sensor) { + //Нечего высвобождать, так как ничего не было выделено + UNUSED(sensor); + return true; +} + +bool unitemp_SHT30_init(Sensor* sensor) { + UNUSED(sensor); + return true; +} + +bool unitemp_GXHT30_init(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + //Включение режима автоматического преобразования 2 раза в сек + uint8_t data[2] = {0x22, 0x36}; + if(!unitemp_i2c_writeArray(i2c_sensor, 2, data)) return false; + return true; +} + +bool unitemp_SHT30_I2C_deinit(Sensor* sensor) { + //Нечего деинициализировать + UNUSED(sensor); + return true; +} + +UnitempStatus unitemp_SHT30_I2C_update(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + //Получение данных + uint8_t data[6] = {0xE0, 0x00}; + if(!unitemp_i2c_writeArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; + if(!unitemp_i2c_readArray(i2c_sensor, 6, data)) return UT_SENSORSTATUS_TIMEOUT; + + sensor->temp = -45 + 175 * (((uint16_t)(data[0] << 8) | data[1]) / 65535.0f); + sensor->hum = 100 * (((uint16_t)(data[3] << 8) | data[4]) / 65535.0f); + + return UT_SENSORSTATUS_OK; +} diff --git a/applications/plugins/unitemp/sensors/SHT30.h b/applications/plugins/unitemp/sensors/SHT30.h new file mode 100644 index 000000000..4b5b74411 --- /dev/null +++ b/applications/plugins/unitemp/sensors/SHT30.h @@ -0,0 +1,70 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) + + 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 3 of the License, 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. If not, see . +*/ +#ifndef UNITEMP_SHT30 +#define UNITEMP_SHT30 + +#include "../unitemp.h" +#include "../Sensors.h" +extern const SensorType SHT30; +extern const SensorType GXHT30; +/** + * @brief Выделение памяти и установка начальных значений датчика SHT30 + * + * @param sensor Указатель на создаваемый датчик + * @return Истина при успехе + */ +bool unitemp_SHT30_I2C_alloc(Sensor* sensor, char* args); + +/** + * @brief Инициализации датчика SHT30 + * + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_SHT30_init(Sensor* sensor); +/** + * @brief Инициализации датчика GXHT30 + * + * @param sensor Указатель на датчик + * @return Истина если инициализация упспешная + */ +bool unitemp_GXHT30_init(Sensor* sensor); + +/** + * @brief Деинициализация датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_SHT30_I2C_deinit(Sensor* sensor); + +/** + * @brief Обновление значений из датчика + * + * @param sensor Указатель на датчик + * @return Статус обновления + */ +UnitempStatus unitemp_SHT30_I2C_update(Sensor* sensor); + +/** + * @brief Высвободить память датчика + * + * @param sensor Указатель на датчик + */ +bool unitemp_SHT30_I2C_free(Sensor* sensor); + +#endif \ No newline at end of file diff --git a/applications/plugins/unitemp/sensors/Sensors.xlsx b/applications/plugins/unitemp/sensors/Sensors.xlsx index 2b6578e0e..c314098a8 100644 Binary files a/applications/plugins/unitemp/sensors/Sensors.xlsx and b/applications/plugins/unitemp/sensors/Sensors.xlsx differ diff --git a/applications/plugins/unitemp/unitemp.c b/applications/plugins/unitemp/unitemp.c index ce1cd1dc9..181de0e78 100644 --- a/applications/plugins/unitemp/unitemp.c +++ b/applications/plugins/unitemp/unitemp.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -21,7 +21,6 @@ #include "./views/UnitempViews.h" #include -#include /* Переменные */ //Данные приложения @@ -79,9 +78,7 @@ bool unitemp_saveSettings(void) { } bool unitemp_loadSettings(void) { -#ifdef UNITEMP_DEBUG - FURI_LOG_D(APP_NAME, "Loading settings..."); -#endif + UNITEMP_DEBUG("Loading settings..."); //Выделение памяти на поток app->file_stream = file_stream_alloc(app->storage); @@ -147,7 +144,7 @@ bool unitemp_loadSettings(void) { //Сколько байт до конца строки size_t line_end = 0; - while(line_end != STRING_FAILURE && line_end != (size_t)(file_size - 1)) { + while(line_end != ((size_t)-1) && line_end != (size_t)(file_size - 1)) { char buff[20] = {0}; sscanf(((char*)(file_buf + line_end)), "%s", buff); @@ -236,6 +233,8 @@ static bool unitemp_alloc(void) { */ static void unitemp_free(void) { popup_free(app->popup); + //Удаление вида после обработки + view_dispatcher_remove_view(app->view_dispatcher, UnitempViewPopup); unitemp_widgets_free(); unitemp_SensorActions_free(); diff --git a/applications/plugins/unitemp/unitemp.h b/applications/plugins/unitemp/unitemp.h index 144780968..bde8b0c17 100644 --- a/applications/plugins/unitemp/unitemp.h +++ b/applications/plugins/unitemp/unitemp.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -39,19 +39,25 @@ /* Объявление макроподстановок */ //Имя приложения #define APP_NAME "Unitemp" +//Версия приложения +#define UNITEMP_APP_VER "1.2" //Путь хранения файлов плагина #define APP_PATH_FOLDER "/ext/unitemp" //Имя файла с настройками #define APP_FILENAME_SETTINGS "settings.cfg" //Имя файла с датчиками #define APP_FILENAME_SENSORS "sensors.cfg" -//Версия приложения -#define UNITEMP_APP_VER "1.0" //Размер буффера текста #define BUFF_SIZE 32 -#define UNITEMP_DEBUG +#define UNITEMP_D + +#ifdef FURI_DEBUG +#define UNITEMP_DEBUG(msg, ...) FURI_LOG_D(APP_NAME, msg, ##__VA_ARGS__) +#else +#define UNITEMP_DEBUG(msg, ...) +#endif /* Объявление перечислений */ //Единицы измерения температуры diff --git a/applications/plugins/unitemp/views/General_view.c b/applications/plugins/unitemp/views/General_view.c index e21b04de2..dcf8420d9 100644 --- a/applications/plugins/unitemp/views/General_view.c +++ b/applications/plugins/unitemp/views/General_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -18,7 +18,9 @@ #include "UnitempViews.h" #include "unitemp_icons.h" -#include +extern const Icon I_ButtonRight_4x7; +extern const Icon I_ButtonLeft_4x7; +extern const Icon I_Ok_btn_9x9; static View* view; @@ -74,7 +76,7 @@ static void _draw_temperature(Canvas* canvas, Sensor* sensor, uint8_t x, uint8_t app->buff[0] = '-'; offset = 1; } - snprintf((char*)(app->buff + offset), BUFF_SIZE, "%d", (int8_t)sensor->temp); + snprintf((char*)(app->buff + offset), BUFF_SIZE, "%d", (int16_t)sensor->temp); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned( canvas, @@ -235,6 +237,7 @@ static void _draw_carousel_values(Canvas* canvas) { canvas_draw_icon(canvas, 34, 23, frames[furi_get_tick() % 2250 / 750]); canvas_set_font(canvas, FontSecondary); + //TODO: Оптимизировать эту срань if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) { snprintf( app->buff, @@ -254,6 +257,9 @@ static void _draw_carousel_values(Canvas* canvas) { if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) { snprintf(app->buff, BUFF_SIZE, "Waiting for module on I2C pins"); } + if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) { + snprintf(app->buff, BUFF_SIZE, "Waiting for module on SPI pins"); + } canvas_draw_str_aligned(canvas, 64, 19, AlignCenter, AlignCenter, app->buff); return; } @@ -302,6 +308,8 @@ static void _draw_carousel_values(Canvas* canvas) { break; } } + +//TODO: Оптимизировать вывод информации static void _draw_carousel_info(Canvas* canvas) { canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 10, 23, "Type:"); @@ -349,6 +357,25 @@ static void _draw_carousel_info(Canvas* canvas) { ->gpio->name); } + if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 10, 35, "MISO pin:"); + canvas_draw_str(canvas, 10, 46, "CS pin:"); + canvas_draw_str(canvas, 10, 58, "SCK pin:"); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str( + canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename); + canvas_draw_str(canvas, 60, 35, unitemp_gpio_getFromInt(3)->name); + canvas_draw_str( + canvas, + 47, + 46, + ((SPISensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) + ->CS_pin->name); + canvas_draw_str(canvas, 54, 58, unitemp_gpio_getFromInt(5)->name); + } + if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) { canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 10, 35, "I2C addr:"); @@ -362,7 +389,8 @@ static void _draw_carousel_info(Canvas* canvas) { BUFF_SIZE, "0x%02X", ((I2CSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->currentI2CAdr); + ->currentI2CAdr >> + 1); canvas_draw_str(canvas, 57, 35, app->buff); canvas_draw_str(canvas, 54, 46, "15 (C0)"); canvas_draw_str(canvas, 54, 58, "16 (C1)"); @@ -539,6 +567,10 @@ static bool _input_callback(InputEvent* event, void* context) { return true; } } + //Обработка длинного нажатия "Ок" + if(event->key == InputKeyOk && event->type == InputTypeLong) { + app->settings.temp_unit = !app->settings.temp_unit; + } return true; } @@ -558,5 +590,6 @@ void unitemp_General_switch(void) { } void unitemp_General_free(void) { + view_dispatcher_remove_view(app->view_dispatcher, UnitempViewGeneral); view_free(view); } diff --git a/applications/plugins/unitemp/views/MainMenu_view.c b/applications/plugins/unitemp/views/MainMenu_view.c index 4b2820eee..bfd0cb0cf 100644 --- a/applications/plugins/unitemp/views/MainMenu_view.c +++ b/applications/plugins/unitemp/views/MainMenu_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/views/Popup_view.c b/applications/plugins/unitemp/views/Popup_view.c index d495462b2..efa7e7ffa 100644 --- a/applications/plugins/unitemp/views/Popup_view.c +++ b/applications/plugins/unitemp/views/Popup_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -18,7 +18,6 @@ #include "UnitempViews.h" #include #include -#include uint32_t _prev_view_id; diff --git a/applications/plugins/unitemp/views/SensorActions_view.c b/applications/plugins/unitemp/views/SensorActions_view.c index 6f375a50a..1d1a83076 100644 --- a/applications/plugins/unitemp/views/SensorActions_view.c +++ b/applications/plugins/unitemp/views/SensorActions_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/views/SensorEdit_view.c b/applications/plugins/unitemp/views/SensorEdit_view.c index 4d5bc17db..ccb07a48e 100644 --- a/applications/plugins/unitemp/views/SensorEdit_view.c +++ b/applications/plugins/unitemp/views/SensorEdit_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -63,13 +63,9 @@ bool _onewire_id_exist(uint8_t* id) { static void _onewire_scan(void) { OneWireSensor* ow_sensor = editable_sensor->instance; -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, - "devices on wire %d: %d", - ow_sensor->bus->gpio->num, - ow_sensor->bus->device_count); -#endif + + UNITEMP_DEBUG( + "devices on wire %d: %d", ow_sensor->bus->gpio->num, ow_sensor->bus->device_count); //Сканирование шины one wire unitemp_onewire_bus_init(ow_sensor->bus); @@ -101,9 +97,8 @@ static void _onewire_scan(void) { memcpy(ow_sensor->deviceID, id, 8); ow_sensor->familyCode = id[0]; -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, + + UNITEMP_DEBUG( "Found sensor's ID: %02X%02X%02X%02X%02X%02X%02X%02X", id[0], id[1], @@ -113,7 +108,6 @@ static void _onewire_scan(void) { id[5], id[6], id[7]); -#endif if(ow_sensor->familyCode != 0) { char id_buff[10]; @@ -199,6 +193,12 @@ static void _gpio_change_callback(VariableItem* item) { unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, initial_gpio); variable_item_set_current_value_text(item, instance->gpio->name); } + if(editable_sensor->type->interface == &SPI) { + SPISensor* instance = editable_sensor->instance; + instance->CS_pin = + unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, initial_gpio); + variable_item_set_current_value_text(item, instance->CS_pin->name); + } if(editable_sensor->type->interface == &ONE_WIRE) { OneWireSensor* instance = editable_sensor->instance; instance->bus->gpio = @@ -214,9 +214,9 @@ static void _gpio_change_callback(VariableItem* item) { static void _i2caddr_change_callback(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); ((I2CSensor*)editable_sensor->instance)->currentI2CAdr = - ((I2CSensor*)editable_sensor->instance)->minI2CAdr + index; + ((I2CSensor*)editable_sensor->instance)->minI2CAdr + index * 2; char buff[5]; - snprintf(buff, 5, "0x%2X", ((I2CSensor*)editable_sensor->instance)->currentI2CAdr); + snprintf(buff, 5, "0x%2X", ((I2CSensor*)editable_sensor->instance)->currentI2CAdr >> 1); variable_item_set_current_value_text(item, buff); } /** @@ -302,12 +302,15 @@ void unitemp_SensorEdit_switch(Sensor* sensor) { offset_buff, OFFSET_BUFF_SIZE, "%+1.1f", (double)(editable_sensor->temp_offset / 10.0)); variable_item_set_current_value_text(temp_offset_item, offset_buff); - //Порт подключения датчка (для one wire и single wire) - if(sensor->type->interface == &ONE_WIRE || sensor->type->interface == &SINGLE_WIRE) { + //Порт подключения датчка (для one wire, SPI и single wire) + if(sensor->type->interface == &ONE_WIRE || sensor->type->interface == &SINGLE_WIRE || + sensor->type->interface == &SPI) { if(sensor->type->interface == &ONE_WIRE) { initial_gpio = ((OneWireSensor*)editable_sensor->instance)->bus->gpio; - } else { + } else if(sensor->type->interface == &SINGLE_WIRE) { initial_gpio = ((SingleWireSensor*)editable_sensor->instance)->gpio; + } else if(sensor->type->interface == &SPI) { + initial_gpio = ((SPISensor*)editable_sensor->instance)->CS_pin; } uint8_t aviable_gpio_count = @@ -335,11 +338,15 @@ void unitemp_SensorEdit_switch(Sensor* sensor) { VariableItem* item = variable_item_list_add( variable_item_list, "I2C address", - ((I2CSensor*)sensor->instance)->maxI2CAdr - ((I2CSensor*)sensor->instance)->minI2CAdr + - 1, + (((I2CSensor*)sensor->instance)->maxI2CAdr >> 1) - + (((I2CSensor*)sensor->instance)->minI2CAdr >> 1) + 1, _i2caddr_change_callback, app); - snprintf(app->buff, 5, "0x%2X", ((I2CSensor*)sensor->instance)->currentI2CAdr); + snprintf(app->buff, 5, "0x%2X", ((I2CSensor*)sensor->instance)->currentI2CAdr >> 1); + variable_item_set_current_value_index( + item, + (((I2CSensor*)sensor->instance)->currentI2CAdr >> 1) - + (((I2CSensor*)sensor->instance)->minI2CAdr >> 1)); variable_item_set_current_value_text(item, app->buff); } diff --git a/applications/plugins/unitemp/views/SensorNameEdit_view.c b/applications/plugins/unitemp/views/SensorNameEdit_view.c index 1d36ac142..19df76edf 100644 --- a/applications/plugins/unitemp/views/SensorNameEdit_view.c +++ b/applications/plugins/unitemp/views/SensorNameEdit_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -42,5 +42,6 @@ void unitemp_SensorNameEdit_switch(Sensor* sensor) { view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); } void unitemp_SensorNameEdit_free(void) { + view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); text_input_free(text_input); } \ No newline at end of file diff --git a/applications/plugins/unitemp/views/SensorsList_view.c b/applications/plugins/unitemp/views/SensorsList_view.c index a7d3d5556..716ec260b 100644 --- a/applications/plugins/unitemp/views/SensorsList_view.c +++ b/applications/plugins/unitemp/views/SensorsList_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -18,7 +18,8 @@ #include "UnitempViews.h" #include #include -#include + +extern const Icon I_Cry_dolph_55x52; //Текущий вид static View* view; @@ -85,8 +86,8 @@ static void _enter_callback(void* context, uint32_t index) { return; } - //Выбор первого доступного порта для датчика single wire - if(type->interface == &SINGLE_WIRE) { + //Выбор первого доступного порта для датчика single wire и SPI + if(type->interface == &SINGLE_WIRE || type->interface == &SPI) { snprintf( args, 4, diff --git a/applications/plugins/unitemp/views/Settings_view.c b/applications/plugins/unitemp/views/Settings_view.c index c3f82c14e..bff169129 100644 --- a/applications/plugins/unitemp/views/Settings_view.c +++ b/applications/plugins/unitemp/views/Settings_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/views/UnitempViews.h b/applications/plugins/unitemp/views/UnitempViews.h index b7c2467e0..b78cf2b28 100644 --- a/applications/plugins/unitemp/views/UnitempViews.h +++ b/applications/plugins/unitemp/views/UnitempViews.h @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 diff --git a/applications/plugins/unitemp/views/Widgets_view.c b/applications/plugins/unitemp/views/Widgets_view.c index 6d8702ca1..97505d925 100644 --- a/applications/plugins/unitemp/views/Widgets_view.c +++ b/applications/plugins/unitemp/views/Widgets_view.c @@ -1,6 +1,6 @@ /* Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) 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 @@ -18,7 +18,7 @@ #include "UnitempViews.h" #include "unitemp_icons.h" -#include +extern const Icon I_DolphinCommon_56x48; void unitemp_widgets_alloc(void) { app->widget = widget_alloc(); @@ -27,6 +27,7 @@ void unitemp_widgets_alloc(void) { } void unitemp_widgets_free(void) { + view_dispatcher_remove_view(app->view_dispatcher, UnitempViewWidget); widget_free(app->widget); } @@ -132,7 +133,7 @@ void unitemp_widget_delete_switch(Sensor* sensor) { app->buff, BUFF_SIZE, "\e#I2C addr:\e# 0x%02X", - ((I2CSensor*)current_sensor->instance)->currentI2CAdr); + ((I2CSensor*)current_sensor->instance)->currentI2CAdr >> 1); widget_add_text_box_element( app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false); } diff --git a/applications/plugins/weather_station/application.fam b/applications/plugins/weather_station/application.fam index 7505900e5..d826f51ea 100644 --- a/applications/plugins/weather_station/application.fam +++ b/applications/plugins/weather_station/application.fam @@ -1,7 +1,8 @@ App( appid="Weather_Station", name="Weather Station", - apptype=FlipperAppType.EXTERNAL, + apptype=FlipperAppType.PLUGIN, + targets=["f7"], entry_point="weather_station_app", cdefines=["APP_WEATHER_STATION"], requires=["gui"], diff --git a/applications/plugins/weather_station/helpers/weather_station_types.h b/applications/plugins/weather_station/helpers/weather_station_types.h index d512251f1..1f5612e2e 100644 --- a/applications/plugins/weather_station/helpers/weather_station_types.h +++ b/applications/plugins/weather_station/helpers/weather_station_types.h @@ -3,7 +3,7 @@ #include #include -#define WS_VERSION_APP "0.6.1" +#define WS_VERSION_APP "0.7" #define WS_DEVELOPED "SkorP" #define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" diff --git a/applications/plugins/weather_station/protocols/lacrosse_tx.c b/applications/plugins/weather_station/protocols/lacrosse_tx.c new file mode 100644 index 000000000..8d8a24e24 --- /dev/null +++ b/applications/plugins/weather_station/protocols/lacrosse_tx.c @@ -0,0 +1,329 @@ +#include "lacrosse_tx.h" + +#define TAG "WSProtocolLaCrosse_TX" + +/* + * Help + * https://github.com/merbanan/rtl_433/blob/master/src/devices/lacrosse.c + * + * + * LaCrosse TX 433 Mhz Temperature and Humidity Sensors. + * - Tested: TX-7U and TX-6U (Temperature only) + * - Not Tested but should work: TX-3, TX-4 + * - also TFA Dostmann 30.3120.90 sensor (for e.g. 35.1018.06 (WS-9015) station) + * - also TFA Dostmann 30.3121 sensor + * Protocol Documentation: http://www.f6fbb.org/domo/sensors/tx3_th.php + * Message is 44 bits, 11 x 4 bit nybbles: + * [00] [cnt = 10] [type] [addr] [addr + parity] [v1] [v2] [v3] [iv1] [iv2] [check] + * Notes: + * - Zero Pulses are longer (1,400 uS High, 1,000 uS Low) = 2,400 uS + * - One Pulses are shorter ( 550 uS High, 1,000 uS Low) = 1,600 uS + * - Sensor id changes when the battery is changed + * - Primary Value are BCD with one decimal place: vvv = 12.3 + * - Secondary value is integer only intval = 12, seems to be a repeat of primary + * This may actually be an additional data check because the 4 bit checksum + * and parity bit is pretty week at detecting errors. + * - Temperature is in Celsius with 50.0 added (to handle negative values) + * - Humidity values appear to be integer precision, decimal always 0. + * - There is a 4 bit checksum and a parity bit covering the three digit value + * - Parity check for TX-3 and TX-4 might be different. + * - Msg sent with one repeat after 30 mS + * - Temperature and humidity are sent as separate messages + * - Frequency for each sensor may be could be off by as much as 50-75 khz + * - LaCrosse Sensors in other frequency ranges (915 Mhz) use FSK not OOK + * so they can't be decoded by rtl_433 currently. + * - Temperature and Humidity are sent in different messages bursts. +*/ + +#define LACROSSE_TX_GAP 1000 +#define LACROSSE_TX_BIT_SIZE 44 +#define LACROSSE_TX_SUNC_PATTERN 0x0A000000000 +#define LACROSSE_TX_SUNC_MASK 0x0F000000000 +#define LACROSSE_TX_MSG_TYPE_TEMP 0x00 +#define LACROSSE_TX_MSG_TYPE_HUM 0x0E + +static const SubGhzBlockConst ws_protocol_lacrosse_tx_const = { + .te_short = 550, + .te_long = 1300, + .te_delta = 120, + .min_count_bit_for_found = 40, +}; + +struct WSProtocolDecoderLaCrosse_TX { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; + + uint16_t header_count; +}; + +struct WSProtocolEncoderLaCrosse_TX { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + WSBlockGeneric generic; +}; + +typedef enum { + LaCrosse_TXDecoderStepReset = 0, + LaCrosse_TXDecoderStepCheckPreambule, + LaCrosse_TXDecoderStepSaveDuration, + LaCrosse_TXDecoderStepCheckDuration, +} LaCrosse_TXDecoderStep; + +const SubGhzProtocolDecoder ws_protocol_lacrosse_tx_decoder = { + .alloc = ws_protocol_decoder_lacrosse_tx_alloc, + .free = ws_protocol_decoder_lacrosse_tx_free, + + .feed = ws_protocol_decoder_lacrosse_tx_feed, + .reset = ws_protocol_decoder_lacrosse_tx_reset, + + .get_hash_data = ws_protocol_decoder_lacrosse_tx_get_hash_data, + .serialize = ws_protocol_decoder_lacrosse_tx_serialize, + .deserialize = ws_protocol_decoder_lacrosse_tx_deserialize, + .get_string = ws_protocol_decoder_lacrosse_tx_get_string, +}; + +const SubGhzProtocolEncoder ws_protocol_lacrosse_tx_encoder = { + .alloc = NULL, + .free = NULL, + + .deserialize = NULL, + .stop = NULL, + .yield = NULL, +}; + +const SubGhzProtocol ws_protocol_lacrosse_tx = { + .name = WS_PROTOCOL_LACROSSE_TX_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_lacrosse_tx_decoder, + .encoder = &ws_protocol_lacrosse_tx_encoder, +}; + +void* ws_protocol_decoder_lacrosse_tx_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderLaCrosse_TX* instance = malloc(sizeof(WSProtocolDecoderLaCrosse_TX)); + instance->base.protocol = &ws_protocol_lacrosse_tx; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void ws_protocol_decoder_lacrosse_tx_free(void* context) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + free(instance); +} + +void ws_protocol_decoder_lacrosse_tx_reset(void* context) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + instance->header_count = 0; + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; +} + +static bool ws_protocol_lacrosse_tx_check_crc(WSProtocolDecoderLaCrosse_TX* instance) { + if(!instance->decoder.decode_data) return false; + uint8_t msg[] = { + (instance->decoder.decode_data >> 36) & 0x0F, + (instance->decoder.decode_data >> 32) & 0x0F, + (instance->decoder.decode_data >> 28) & 0x0F, + (instance->decoder.decode_data >> 24) & 0x0F, + (instance->decoder.decode_data >> 20) & 0x0F, + (instance->decoder.decode_data >> 16) & 0x0F, + (instance->decoder.decode_data >> 12) & 0x0F, + (instance->decoder.decode_data >> 8) & 0x0F, + (instance->decoder.decode_data >> 4) & 0x0F}; + + uint8_t crc = subghz_protocol_blocks_add_bytes(msg, 9); + return ((crc & 0x0F) == ((instance->decoder.decode_data) & 0x0F)); +} + +/** + * Analysis of received data + * @param instance Pointer to a WSBlockGeneric* instance + */ +static void ws_protocol_lacrosse_tx_remote_controller(WSBlockGeneric* instance) { + uint8_t msg_type = (instance->data >> 32) & 0x0F; + instance->id = (((instance->data >> 28) & 0x0F) << 3) | (((instance->data >> 24) & 0x0F) >> 1); + + float msg_value = (float)((instance->data >> 20) & 0x0F) * 10.0f + + (float)((instance->data >> 16) & 0x0F) + + (float)((instance->data >> 12) & 0x0F) * 0.1f; + + if(msg_type == LACROSSE_TX_MSG_TYPE_TEMP) { //-V1051 + instance->temp = msg_value - 50.0f; + instance->humidity = WS_NO_HUMIDITY; + } else if(msg_type == LACROSSE_TX_MSG_TYPE_HUM) { + //ToDo for verification, records are needed with sensors maintaining temperature and temperature for this standard + instance->humidity = (uint8_t)msg_value; + } else { + furi_crash("WS: WSProtocolLaCrosse_TX incorrect msg_type."); + } + + instance->btn = WS_NO_BTN; + instance->battery_low = WS_NO_BATT; + instance->channel = WS_NO_CHANNEL; +} + +void ws_protocol_decoder_lacrosse_tx_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + + switch(instance->decoder.parser_step) { + case LaCrosse_TXDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, LACROSSE_TX_GAP) < + ws_protocol_lacrosse_tx_const.te_delta * 2)) { + instance->decoder.parser_step = LaCrosse_TXDecoderStepCheckPreambule; + instance->header_count = 0; + } + break; + + case LaCrosse_TXDecoderStepCheckPreambule: + + if(level) { + if((DURATION_DIFF(duration, ws_protocol_lacrosse_tx_const.te_short) < + ws_protocol_lacrosse_tx_const.te_delta) && + (instance->header_count > 1)) { + instance->decoder.parser_step = LaCrosse_TXDecoderStepCheckDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.te_last = duration; + } else if(duration > (ws_protocol_lacrosse_tx_const.te_long * 2)) { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + } else { + if(DURATION_DIFF(duration, LACROSSE_TX_GAP) < + ws_protocol_lacrosse_tx_const.te_delta * 2) { + instance->decoder.te_last = duration; + instance->header_count++; + } else { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + } + + break; + + case LaCrosse_TXDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = LaCrosse_TXDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + break; + + case LaCrosse_TXDecoderStepCheckDuration: + + if(!level) { + if(duration > LACROSSE_TX_GAP * 3) { + if(DURATION_DIFF( + instance->decoder.te_last, ws_protocol_lacrosse_tx_const.te_short) < + ws_protocol_lacrosse_tx_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = LaCrosse_TXDecoderStepSaveDuration; + } else if( + DURATION_DIFF( + instance->decoder.te_last, ws_protocol_lacrosse_tx_const.te_long) < + ws_protocol_lacrosse_tx_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = LaCrosse_TXDecoderStepSaveDuration; + } + if((instance->decoder.decode_data & LACROSSE_TX_SUNC_MASK) == + LACROSSE_TX_SUNC_PATTERN) { + if(ws_protocol_lacrosse_tx_check_crc(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = LACROSSE_TX_BIT_SIZE; + ws_protocol_lacrosse_tx_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + } + + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->header_count = 0; + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + break; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_lacrosse_tx_const.te_short) < + ws_protocol_lacrosse_tx_const.te_delta) && + (DURATION_DIFF(duration, LACROSSE_TX_GAP) < + ws_protocol_lacrosse_tx_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = LaCrosse_TXDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_lacrosse_tx_const.te_long) < + ws_protocol_lacrosse_tx_const.te_delta) && + (DURATION_DIFF(duration, LACROSSE_TX_GAP) < + ws_protocol_lacrosse_tx_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = LaCrosse_TXDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + + } else { + instance->decoder.parser_step = LaCrosse_TXDecoderStepReset; + } + + break; + } +} + +uint8_t ws_protocol_decoder_lacrosse_tx_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool ws_protocol_decoder_lacrosse_tx_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + return ws_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool ws_protocol_decoder_lacrosse_tx_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + bool ret = false; + do { + if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + ws_protocol_lacrosse_tx_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void ws_protocol_decoder_lacrosse_tx_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderLaCrosse_TX* instance = context; + furi_string_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%lX Ch:%d Bat:%d\r\n" + "Temp:%3.1f C Hum:%d%%", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (double)instance->generic.temp, + instance->generic.humidity); +} diff --git a/applications/plugins/weather_station/protocols/lacrosse_tx.h b/applications/plugins/weather_station/protocols/lacrosse_tx.h new file mode 100644 index 000000000..e88455689 --- /dev/null +++ b/applications/plugins/weather_station/protocols/lacrosse_tx.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include +#include +#include +#include "ws_generic.h" +#include + +#define WS_PROTOCOL_LACROSSE_TX_NAME "LaCrosse_TX" + +typedef struct WSProtocolDecoderLaCrosse_TX WSProtocolDecoderLaCrosse_TX; +typedef struct WSProtocolEncoderLaCrosse_TX WSProtocolEncoderLaCrosse_TX; + +extern const SubGhzProtocolDecoder ws_protocol_lacrosse_tx_decoder; +extern const SubGhzProtocolEncoder ws_protocol_lacrosse_tx_encoder; +extern const SubGhzProtocol ws_protocol_lacrosse_tx; + +/** + * Allocate WSProtocolDecoderLaCrosse_TX. + * @param environment Pointer to a SubGhzEnvironment instance + * @return WSProtocolDecoderLaCrosse_TX* pointer to a WSProtocolDecoderLaCrosse_TX instance + */ +void* ws_protocol_decoder_lacrosse_tx_alloc(SubGhzEnvironment* environment); + +/** + * Free WSProtocolDecoderLaCrosse_TX. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + */ +void ws_protocol_decoder_lacrosse_tx_free(void* context); + +/** + * Reset decoder WSProtocolDecoderLaCrosse_TX. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + */ +void ws_protocol_decoder_lacrosse_tx_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void ws_protocol_decoder_lacrosse_tx_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @return hash Hash sum + */ +uint8_t ws_protocol_decoder_lacrosse_tx_get_hash_data(void* context); + +/** + * Serialize data WSProtocolDecoderLaCrosse_TX. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool ws_protocol_decoder_lacrosse_tx_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data WSProtocolDecoderLaCrosse_TX. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool ws_protocol_decoder_lacrosse_tx_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a WSProtocolDecoderLaCrosse_TX instance + * @param output Resulting text + */ +void ws_protocol_decoder_lacrosse_tx_get_string(void* context, FuriString* output); diff --git a/applications/plugins/weather_station/protocols/protocol_items.c b/applications/plugins/weather_station/protocols/protocol_items.c index 99c8344f4..2c9d751c7 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.c +++ b/applications/plugins/weather_station/protocols/protocol_items.c @@ -8,6 +8,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_gt_wt_03, &ws_protocol_acurite_606tx, &ws_protocol_acurite_609txc, + &ws_protocol_lacrosse_tx, &ws_protocol_lacrosse_tx141thbv2, &ws_protocol_oregon2, &ws_protocol_acurite_592txr, diff --git a/applications/plugins/weather_station/protocols/protocol_items.h b/applications/plugins/weather_station/protocols/protocol_items.h index 9d5d096f8..f9e443abc 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.h +++ b/applications/plugins/weather_station/protocols/protocol_items.h @@ -8,6 +8,7 @@ #include "gt_wt_03.h" #include "acurite_606tx.h" #include "acurite_609txc.h" +#include "lacrosse_tx.h" #include "lacrosse_tx141thbv2.h" #include "oregon2.h" #include "acurite_592txr.h" diff --git a/applications/plugins/weather_station/protocols/ws_generic.h b/applications/plugins/weather_station/protocols/ws_generic.h index 8e6e061ad..47cfa74b3 100644 --- a/applications/plugins/weather_station/protocols/ws_generic.h +++ b/applications/plugins/weather_station/protocols/ws_generic.h @@ -6,7 +6,7 @@ #include #include "furi.h" -#include "furi_hal.h" +#include #include #include diff --git a/applications/plugins/wii_ec_anal/application.fam b/applications/plugins/wii_ec_anal/application.fam index 655b5f938..4dc251713 100644 --- a/applications/plugins/wii_ec_anal/application.fam +++ b/applications/plugins/wii_ec_anal/application.fam @@ -1,36 +1,28 @@ # qv. https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppManifests.md App( - # --- App Info - appid="wii_ec_anal", - name="Wii EC Analyser", - - # --- Entry point - apptype=FlipperAppType.EXTERNAL, - entry_point="wii_ec_anal", - - # --- Interaction - cdefines=["APP_WII_EC_ANAL"], - requires=[ - "gui", - ], - -# conflicts="", -# sdk_headers="", - - # --- Run-time info - stack_size=2 * 1024, - order=20, - - # --- FAP details - sources=["wii_*.c", "gfx/*.c"], - -# fap_weburl="https://github.com/csBlueChip/FlipperZero_plugin_WiiChuck/", -# fap_author="BlueChip", - -# fap_description="Wii Extension Controller Protocol Analyser", -# fap_version=(1,0), - - fap_icon="WiiEC.png", - fap_category="GPIO", + # --- App Info + appid="wii_ec_anal", + name="Wii EC Analyser", + # --- Entry point + apptype=FlipperAppType.EXTERNAL, + entry_point="wii_ec_anal", + # --- Interaction + cdefines=["APP_WII_EC_ANAL"], + requires=[ + "gui", + ], + # conflicts="", + # sdk_headers="", + # --- Run-time info + stack_size=2 * 1024, + order=20, + # --- FAP details + sources=["wii_*.c", "gfx/*.c"], + # fap_weburl="https://github.com/csBlueChip/FlipperZero_plugin_WiiChuck/", + # fap_author="BlueChip", + # fap_description="Wii Extension Controller Protocol Analyser", + # fap_version=(1,0), + fap_icon="WiiEC.png", + fap_category="GPIO", ) diff --git a/applications/plugins/yatzee/application.fam b/applications/plugins/yatzee/application.fam index 183021854..b30e90d23 100644 --- a/applications/plugins/yatzee/application.fam +++ b/applications/plugins/yatzee/application.fam @@ -9,5 +9,4 @@ App( fap_icon="images/yatzee_icon_10px.png", fap_category="Games", fap_icon_assets="images", - ) diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index 1ca6a2775..7abef0e68 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -5,7 +5,7 @@ #include #include #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define TAG "BtSrv" @@ -77,6 +77,8 @@ static void bt_pin_code_hide(Bt* bt) { static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) { furi_assert(bt); + if(bt_get_profile_pairing_method(bt) == GapPairingNone) return true; + notification_message(bt->notification, &sequence_display_backlight_on); FuriString* pin_str; dialog_message_set_icon(bt->dialog_message, XTREME_ASSETS()->I_BLE_Pairing_128x64, 0, 0); @@ -86,6 +88,7 @@ static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) { dialog_message_set_buttons(bt->dialog_message, "Cancel", "OK", NULL); DialogMessageButton button = dialog_message_show(bt->dialogs, bt->dialog_message); furi_string_free(pin_str); + return button == DialogMessageButtonCenter; } @@ -370,6 +373,87 @@ static void bt_close_connection(Bt* bt) { furi_event_flag_set(bt->api_event, BT_API_UNLOCK_EVENT); } +static inline FuriHalBtProfile get_hal_bt_profile(BtProfile profile) { + if(profile == BtProfileHidKeyboard) { + return FuriHalBtProfileHidKeyboard; + } else { + return FuriHalBtProfileSerial; + } +} + +static void bt_restart(Bt* bt) { + furi_hal_bt_change_app(get_hal_bt_profile(bt->profile), bt_on_gap_event_callback, bt); + furi_hal_bt_start_advertising(); +} + +void bt_set_profile_adv_name(Bt* bt, const char* fmt, ...) { + furi_assert(bt); + furi_assert(fmt); + + char name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH]; + va_list args; + va_start(args, fmt); + vsnprintf(name, sizeof(name), fmt, args); + va_end(args); + furi_hal_bt_set_profile_adv_name(get_hal_bt_profile(bt->profile), name); + + bt_restart(bt); +} + +const char* bt_get_profile_adv_name(Bt* bt) { + furi_assert(bt); + return furi_hal_bt_get_profile_adv_name(get_hal_bt_profile(bt->profile)); +} + +void bt_set_profile_mac_address(Bt* bt, const uint8_t mac[6]) { + furi_assert(bt); + furi_assert(mac); + + furi_hal_bt_set_profile_mac_addr(get_hal_bt_profile(bt->profile), mac); + + bt_restart(bt); +} + +const uint8_t* bt_get_profile_mac_address(Bt* bt) { + furi_assert(bt); + return furi_hal_bt_get_profile_mac_addr(get_hal_bt_profile(bt->profile)); +} + +bool bt_remote_rssi(Bt* bt, BtRssi* rssi) { + furi_assert(bt); + UNUSED(rssi); + + uint8_t rssi_val; + uint32_t since = furi_hal_bt_get_conn_rssi(&rssi_val); + + if(since == 0) return false; + + rssi->rssi = rssi_val; + rssi->since = since; + + return true; +} + +void bt_set_profile_pairing_method(Bt* bt, GapPairing pairing_method) { + furi_assert(bt); + furi_hal_bt_set_profile_pairing_method(get_hal_bt_profile(bt->profile), pairing_method); + bt_restart(bt); +} + +GapPairing bt_get_profile_pairing_method(Bt* bt) { + furi_assert(bt); + return furi_hal_bt_get_profile_pairing_method(get_hal_bt_profile(bt->profile)); +} + +void bt_disable_peer_key_update(Bt* bt) { + UNUSED(bt); + furi_hal_bt_set_key_storage_change_callback(NULL, NULL); +} + +void bt_enable_peer_key_update(Bt* bt) { + furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); +} + int32_t bt_srv(void* p) { UNUSED(p); Bt* bt = bt_alloc(); diff --git a/applications/services/bt/bt_service/bt.h b/applications/services/bt/bt_service/bt.h index ca47936db..a79c227f7 100644 --- a/applications/services/bt/bt_service/bt.h +++ b/applications/services/bt/bt_service/bt.h @@ -2,6 +2,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -23,6 +24,11 @@ typedef enum { BtProfileHidKeyboard, } BtProfile; +typedef struct { + uint8_t rssi; + uint32_t since; +} BtRssi; + typedef void (*BtStatusChangedCallback)(BtStatus status, void* context); /** Change BLE Profile @@ -35,6 +41,28 @@ typedef void (*BtStatusChangedCallback)(BtStatus status, void* context); */ bool bt_set_profile(Bt* bt, BtProfile profile); +void bt_set_profile_adv_name(Bt* bt, const char* fmt, ...); +const char* bt_get_profile_adv_name(Bt* bt); + +void bt_set_profile_mac_address(Bt* bt, const uint8_t mac[6]); +const uint8_t* bt_get_profile_mac_address(Bt* bt); + +bool bt_remote_rssi(Bt* bt, BtRssi* rssi); + +void bt_set_profile_pairing_method(Bt* bt, GapPairing pairing_method); +GapPairing bt_get_profile_pairing_method(Bt* bt); + +/** Stop saving new peer key to flash (in .bt.keys file) + * +*/ +void bt_disable_peer_key_update(Bt* bt); + +/** Enable saving peer key to internal flash (enable by default) + * + * @note This function should be called if bt_disable_peer_key_update was called before +*/ +void bt_enable_peer_key_update(Bt* bt); + /** Disconnect from Central * * @param bt Bt instance diff --git a/applications/services/bt/bt_settings.h b/applications/services/bt/bt_settings.h index 260d9c0e0..9ed8be89c 100644 --- a/applications/services/bt/bt_settings.h +++ b/applications/services/bt/bt_settings.h @@ -5,6 +5,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { bool enabled; } BtSettings; @@ -12,3 +16,7 @@ typedef struct { bool bt_settings_load(BtSettings* bt_settings); bool bt_settings_save(BtSettings* bt_settings); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/services/cli/cli_command_gpio.c b/applications/services/cli/cli_command_gpio.c index f0d487bec..d02462734 100644 --- a/applications/services/cli/cli_command_gpio.c +++ b/applications/services/cli/cli_command_gpio.c @@ -5,28 +5,6 @@ #include #include -typedef struct { - const GpioPin* pin; - const char* name; - const bool debug; -} CliCommandGpio; - -const CliCommandGpio cli_command_gpio_pins[] = { - {.pin = &gpio_ext_pc0, .name = "PC0", .debug = false}, - {.pin = &gpio_ext_pc1, .name = "PC1", .debug = false}, - {.pin = &gpio_ext_pc3, .name = "PC3", .debug = false}, - {.pin = &gpio_ext_pb2, .name = "PB2", .debug = false}, - {.pin = &gpio_ext_pb3, .name = "PB3", .debug = false}, - {.pin = &gpio_ext_pa4, .name = "PA4", .debug = false}, - {.pin = &gpio_ext_pa6, .name = "PA6", .debug = false}, - {.pin = &gpio_ext_pa7, .name = "PA7", .debug = false}, - /* Dangerous pins, may damage hardware */ - {.pin = &gpio_infrared_rx, .name = "PA0", .debug = true}, - {.pin = &gpio_usart_rx, .name = "PB7", .debug = true}, - {.pin = &gpio_speaker, .name = "PB8", .debug = true}, - {.pin = &gpio_infrared_tx, .name = "PB9", .debug = true}, -}; - void cli_command_gpio_print_usage() { printf("Usage:\r\n"); printf("gpio \r\n"); @@ -38,9 +16,9 @@ void cli_command_gpio_print_usage() { static bool pin_name_to_int(FuriString* pin_name, size_t* result) { bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); - for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) { - if(furi_string_equal(pin_name, cli_command_gpio_pins[i].name)) { - if(!cli_command_gpio_pins[i].debug || is_debug_mode) { + for(size_t i = 0; i < gpio_pins_count; i++) { + if(furi_string_equal(pin_name, gpio_pins[i].name)) { + if(!gpio_pins[i].debug || is_debug_mode) { *result = i; return true; } @@ -53,9 +31,9 @@ static bool pin_name_to_int(FuriString* pin_name, size_t* result) { static void gpio_print_pins(void) { printf("Wrong pin name. Available pins: "); bool is_debug_mode = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug); - for(size_t i = 0; i < COUNT_OF(cli_command_gpio_pins); i++) { - if(!cli_command_gpio_pins[i].debug || is_debug_mode) { - printf("%s ", cli_command_gpio_pins[i].name); + for(size_t i = 0; i < gpio_pins_count; i++) { + if(!gpio_pins[i].debug || is_debug_mode) { + printf("%s ", gpio_pins[i].name); } } } @@ -113,7 +91,7 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) { return; } - if(cli_command_gpio_pins[num].debug) { //-V779 + if(gpio_pins[num].debug) { //-V779 printf( "Changing this pin mode may damage hardware. Are you sure you want to continue? (y/n)?\r\n"); char c = cli_getc(cli); @@ -124,12 +102,12 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) { } if(value == 1) { // output - furi_hal_gpio_write(cli_command_gpio_pins[num].pin, false); - furi_hal_gpio_init_simple(cli_command_gpio_pins[num].pin, GpioModeOutputPushPull); - printf("Pin %s is now an output (low)", cli_command_gpio_pins[num].name); + furi_hal_gpio_write(gpio_pins[num].pin, false); + furi_hal_gpio_init_simple(gpio_pins[num].pin, GpioModeOutputPushPull); + printf("Pin %s is now an output (low)", gpio_pins[num].name); } else { // input - furi_hal_gpio_init_simple(cli_command_gpio_pins[num].pin, GpioModeInput); - printf("Pin %s is now an input", cli_command_gpio_pins[num].name); + furi_hal_gpio_init_simple(gpio_pins[num].pin, GpioModeInput); + printf("Pin %s is now an input", gpio_pins[num].name); } } @@ -144,15 +122,14 @@ void cli_command_gpio_read(Cli* cli, FuriString* args, void* context) { } if(LL_GPIO_MODE_INPUT != //-V779 - LL_GPIO_GetPinMode( - cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) { - printf("Err: pin %s is not set as an input.", cli_command_gpio_pins[num].name); + LL_GPIO_GetPinMode(gpio_pins[num].pin->port, gpio_pins[num].pin->pin)) { + printf("Err: pin %s is not set as an input.", gpio_pins[num].name); return; } - uint8_t val = !!furi_hal_gpio_read(cli_command_gpio_pins[num].pin); + uint8_t val = !!furi_hal_gpio_read(gpio_pins[num].pin); - printf("Pin %s <= %u", cli_command_gpio_pins[num].name, val); + printf("Pin %s <= %u", gpio_pins[num].name, val); } void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) { @@ -174,14 +151,13 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) { } if(LL_GPIO_MODE_OUTPUT != //-V779 - LL_GPIO_GetPinMode( - cli_command_gpio_pins[num].pin->port, cli_command_gpio_pins[num].pin->pin)) { - printf("Err: pin %s is not set as an output.", cli_command_gpio_pins[num].name); + LL_GPIO_GetPinMode(gpio_pins[num].pin->port, gpio_pins[num].pin->pin)) { + printf("Err: pin %s is not set as an output.", gpio_pins[num].name); return; } // Extra check if debug pins used - if(cli_command_gpio_pins[num].debug) { + if(gpio_pins[num].debug) { printf( "Setting this pin may damage hardware. Are you sure you want to continue? (y/n)?\r\n"); char c = cli_getc(cli); @@ -191,8 +167,8 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) { } } - furi_hal_gpio_write(cli_command_gpio_pins[num].pin, !!value); - printf("Pin %s => %u", cli_command_gpio_pins[num].name, !!value); + furi_hal_gpio_write(gpio_pins[num].pin, !!value); + printf("Pin %s => %u", gpio_pins[num].name, !!value); } void cli_command_gpio(Cli* cli, FuriString* args, void* context) { diff --git a/applications/services/desktop/animations/animation_manager.c b/applications/services/desktop/animations/animation_manager.c index c1eb50d59..2d100b2e1 100644 --- a/applications/services/desktop/animations/animation_manager.c +++ b/applications/services/desktop/animations/animation_manager.c @@ -13,7 +13,7 @@ #include "animation_storage.h" #include "animation_manager.h" -#include "../../../settings/xtreme_settings/xtreme_settings.h" +#include "xtreme/assets.h" #define TAG "AnimationManager" @@ -145,7 +145,8 @@ void animation_manager_check_blocking_process(AnimationManager* animation_manage const StorageAnimationManifestInfo* manifest_info = animation_storage_get_meta(animation_manager->current_animation); - bool valid = animation_manager_is_valid_idle_animation(manifest_info, &stats, XTREME_SETTINGS()->unlock_anims); + bool valid = animation_manager_is_valid_idle_animation( + manifest_info, &stats, XTREME_SETTINGS()->unlock_anims); if(!valid) { animation_manager_start_new_idle(animation_manager); @@ -201,8 +202,10 @@ static void animation_manager_start_new_idle(AnimationManager* animation_manager animation_storage_get_bubble_animation(animation_manager->current_animation); animation_manager->state = AnimationManagerStateIdle; XtremeSettings* xtreme_settings = XTREME_SETTINGS(); - int32_t duration = (xtreme_settings->cycle_anims == 0) ? (bubble_animation->duration) : (xtreme_settings->cycle_anims); - furi_timer_start(animation_manager->idle_animation_timer, (duration > 0) ? (duration * 1000) : 0); + int32_t duration = (xtreme_settings->cycle_anims == 0) ? (bubble_animation->duration) : + (xtreme_settings->cycle_anims); + furi_timer_start( + animation_manager->idle_animation_timer, (duration > 0) ? (duration * 1000) : 0); } static bool animation_manager_check_blocking(AnimationManager* animation_manager) { @@ -355,7 +358,7 @@ static bool animation_manager_is_valid_idle_animation( result = (sd_status == FSE_NOT_READY); } - if (!unlock) { + if(!unlock) { if((stats->butthurt < info->min_butthurt) || (stats->butthurt > info->max_butthurt)) { result = false; } @@ -369,10 +372,11 @@ static bool animation_manager_is_valid_idle_animation( static StorageAnimation* animation_manager_select_idle_animation(AnimationManager* animation_manager) { - const char* old_animation_name = NULL; - if (animation_manager->current_animation) { - old_animation_name = animation_storage_get_meta(animation_manager->current_animation)->name; - } + // const char* avoid_animation = NULL; + // if(animation_manager->current_animation) { + // avoid_animation = animation_storage_get_meta(animation_manager->current_animation)->name; + // } + UNUSED(animation_manager); StorageAnimationList_t animation_list; StorageAnimationList_init(animation_list); @@ -381,6 +385,7 @@ static StorageAnimation* Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); DolphinStats stats = dolphin_stats(dolphin); furi_record_close(RECORD_DOLPHIN); + // avoid_animation = StorageAnimationList_size(animation_list) > 1 ? avoid_animation : NULL; uint32_t whole_weight = 0; StorageAnimationList_it_t it; @@ -391,11 +396,14 @@ static StorageAnimation* animation_storage_get_meta(storage_animation); bool valid = animation_manager_is_valid_idle_animation(manifest_info, &stats, unlock); - if (old_animation_name != NULL) { - if (strcmp(manifest_info->name, old_animation_name) == 0) { - valid = false; - } - } + // Avoid repeating animation + // Bad / empty manifests can crash flipper and (very rarely) require DFU + // Need better solution, disabled for now + // if(avoid_animation != NULL) { + // if(strcmp(manifest_info->name, avoid_animation) == 0) { + // valid = false; + // } + // } if(valid) { whole_weight += manifest_info->weight; @@ -512,7 +520,8 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m furi_record_close(RECORD_DOLPHIN); const StorageAnimationManifestInfo* manifest_info = animation_storage_get_meta(restore_animation); - bool valid = animation_manager_is_valid_idle_animation(manifest_info, &stats, XTREME_SETTINGS()->unlock_anims); + bool valid = animation_manager_is_valid_idle_animation( + manifest_info, &stats, XTREME_SETTINGS()->unlock_anims); if(valid) { animation_manager_replace_current_animation( animation_manager, restore_animation); @@ -523,12 +532,16 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m animation_manager->idle_animation_timer, animation_manager->freezed_animation_time_left); } else { - const BubbleAnimation* bubble_animation = animation_storage_get_bubble_animation( - animation_manager->current_animation); + const BubbleAnimation* bubble_animation = + animation_storage_get_bubble_animation( + animation_manager->current_animation); XtremeSettings* xtreme_settings = XTREME_SETTINGS(); - int32_t duration = (xtreme_settings->cycle_anims == 0) ? (bubble_animation->duration) : (xtreme_settings->cycle_anims); + int32_t duration = (xtreme_settings->cycle_anims == 0) ? + (bubble_animation->duration) : + (xtreme_settings->cycle_anims); furi_timer_start( - animation_manager->idle_animation_timer, (duration > 0) ? (duration * 1000) : 0); + animation_manager->idle_animation_timer, + (duration > 0) ? (duration * 1000) : 0); } } } else { @@ -560,9 +573,6 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m static void animation_manager_switch_to_one_shot_view(AnimationManager* animation_manager) { furi_assert(animation_manager); furi_assert(!animation_manager->one_shot_view); - Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); - DolphinStats stats = dolphin_stats(dolphin); - furi_record_close(RECORD_DOLPHIN); animation_manager->one_shot_view = one_shot_view_alloc(); one_shot_view_set_interact_callback( @@ -571,19 +581,8 @@ static void animation_manager_switch_to_one_shot_view(AnimationManager* animatio View* next_view = one_shot_view_get_view(animation_manager->one_shot_view); view_stack_remove_view(animation_manager->view_stack, prev_view); view_stack_add_view(animation_manager->view_stack, next_view); - if(XTREME_SETTINGS()->nsfw_mode) { - one_shot_view_start_animation(animation_manager->one_shot_view, &A_Levelup1_128x64); - } else { - if(stats.level <= 20) { - one_shot_view_start_animation( - animation_manager->one_shot_view, &A_Levelup1_128x64_sfw); - } else if(stats.level >= 21) { - one_shot_view_start_animation( - animation_manager->one_shot_view, &A_Levelup2_128x64_sfw); - } else { - furi_assert(0); - } - } + one_shot_view_start_animation( + animation_manager->one_shot_view, XTREME_ASSETS()->A_Levelup_128x64); } static void animation_manager_switch_to_animation_view(AnimationManager* animation_manager) { diff --git a/applications/services/desktop/animations/animation_storage.c b/applications/services/desktop/animations/animation_storage.c index 28cdfe810..0d09f18dd 100644 --- a/applications/services/desktop/animations/animation_storage.c +++ b/applications/services/desktop/animations/animation_storage.c @@ -11,7 +11,7 @@ #include "animation_storage_i.h" #include #include -#include "../../../settings/xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define ANIMATION_META_FILE "meta.txt" #define BASE_ANIMATION_DIR EXT_PATH("dolphin") #define TAG "AnimationStorage" @@ -35,30 +35,25 @@ void animation_handler_select_manifest() { FuriString* anim_dir = furi_string_alloc(); FuriString* manifest = furi_string_alloc(); bool use_asset_pack = xtreme_settings->asset_pack[0] != '\0'; - if (use_asset_pack) { + if(use_asset_pack) { furi_string_printf(anim_dir, "%s/%s/Anims", PACKS_DIR, xtreme_settings->asset_pack); furi_string_printf(manifest, "%s/manifest.txt", furi_string_get_cstr(anim_dir)); Storage* storage = furi_record_open(RECORD_STORAGE); - if (storage_common_stat(storage, furi_string_get_cstr(manifest), NULL) == FSE_OK) { - FURI_LOG_I(TAG, "Custom Manifest selected"); + if(storage_common_stat(storage, furi_string_get_cstr(manifest), NULL) == FSE_OK) { + FURI_LOG_I(TAG, "Custom manifest selected"); } else { use_asset_pack = false; } furi_record_close(RECORD_STORAGE); } - if (!use_asset_pack) { + if(!use_asset_pack) { furi_string_set(anim_dir, BASE_ANIMATION_DIR); - if(xtreme_settings->nsfw_mode) { - furi_string_cat_str(anim_dir, "/nsfw"); - FURI_LOG_I(TAG, "NSFW Manifest selected"); - } else { - furi_string_cat_str(anim_dir, "/sfw"); - FURI_LOG_I(TAG, "SFW Manifest selected"); - } furi_string_printf(manifest, "%s/manifest.txt", furi_string_get_cstr(anim_dir)); + FURI_LOG_I(TAG, "Base manifest selected"); } strlcpy(ANIMATION_DIR, furi_string_get_cstr(anim_dir), sizeof(ANIMATION_DIR)); - strlcpy(ANIMATION_MANIFEST_FILE, furi_string_get_cstr(manifest), sizeof(ANIMATION_MANIFEST_FILE)); + strlcpy( + ANIMATION_MANIFEST_FILE, furi_string_get_cstr(manifest), sizeof(ANIMATION_MANIFEST_FILE)); furi_string_free(manifest); furi_string_free(anim_dir); } @@ -330,42 +325,49 @@ static bool animation_storage_load_frames( FURI_CONST_ASSIGN(icon->width, width); icon->frames = malloc(sizeof(const uint8_t*) * icon->frame_count); - bool frames_ok = false; + bool frames_ok = true; File* file = storage_file_alloc(storage); FileInfo file_info; FuriString* filename; filename = furi_string_alloc(); - size_t max_filesize = ROUND_UP_TO(width, 8) * height + 1; + size_t max_filesize = ROUND_UP_TO(width, 8) * height + 2; for(int i = 0; i < icon->frame_count; ++i) { - frames_ok = false; - furi_string_printf(filename, "%s/%s/frame_%d.bm", ANIMATION_DIR, name, i); + FURI_CONST_ASSIGN_PTR(icon->frames[i], 0); + if(frames_ok) { + frames_ok = false; + furi_string_printf(filename, "%s/%s/frame_%d.bm", ANIMATION_DIR, name, i); + do { + if(storage_common_stat(storage, furi_string_get_cstr(filename), &file_info) != + FSE_OK) + break; + if(file_info.size > max_filesize) { + FURI_LOG_E( + TAG, + "Filesize %lld, max: %d (width %d, height %d)", + file_info.size, + max_filesize, + width, + height); + break; + } + if(!storage_file_open( + file, furi_string_get_cstr(filename), FSAM_READ, FSOM_OPEN_EXISTING)) { + FURI_LOG_E(TAG, "Can't open file \'%s\'", furi_string_get_cstr(filename)); + break; + } - if(storage_common_stat(storage, furi_string_get_cstr(filename), &file_info) != FSE_OK) - break; - if(file_info.size > max_filesize) { - FURI_LOG_E( - TAG, - "Filesize %lld, max: %d (width %d, height %d)", - file_info.size, - max_filesize, - width, - height); - break; + FURI_CONST_ASSIGN_PTR(icon->frames[i], malloc(file_info.size)); + if(storage_file_read(file, (void*)icon->frames[i], file_info.size) != + file_info.size) { + FURI_LOG_E(TAG, "Read failed: \'%s\'", furi_string_get_cstr(filename)); + break; + } else { + frames_ok = true; + } + storage_file_close(file); + } while(0); } - if(!storage_file_open( - file, furi_string_get_cstr(filename), FSAM_READ, FSOM_OPEN_EXISTING)) { - FURI_LOG_E(TAG, "Can't open file \'%s\'", furi_string_get_cstr(filename)); - break; - } - - FURI_CONST_ASSIGN_PTR(icon->frames[i], malloc(file_info.size)); - if(storage_file_read(file, (void*)icon->frames[i], file_info.size) != file_info.size) { - FURI_LOG_E(TAG, "Read failed: \'%s\'", furi_string_get_cstr(filename)); - break; - } - storage_file_close(file); - frames_ok = true; } if(!frames_ok) { @@ -528,9 +530,7 @@ static BubbleAnimation* animation_storage_load_animation(const char* name) { uint16_t anim_speed = XTREME_SETTINGS()->anim_speed; anim_speed = (anim_speed == 0 ? 100 : anim_speed); u32value = (u32value * anim_speed) / 100; - u32value = u32value < 1 ? 1 : u32value; - u32value = u32value > 10 ? 10 : u32value; - FURI_CONST_ASSIGN(animation->icon_animation.frame_rate, u32value); + FURI_CONST_ASSIGN(animation->icon_animation.frame_rate, u32value < 1 ? 1 : u32value); if(!flipper_format_read_uint32(ff, "Duration", &u32value, 1)) break; animation->duration = u32value; if(!flipper_format_read_uint32(ff, "Active cooldown", &u32value, 1)) break; diff --git a/applications/services/desktop/scenes/desktop_scene_fault.c b/applications/services/desktop/scenes/desktop_scene_fault.c index e4f5e788f..b3801d78d 100644 --- a/applications/services/desktop/scenes/desktop_scene_fault.c +++ b/applications/services/desktop/scenes/desktop_scene_fault.c @@ -1,7 +1,7 @@ #include #include "../desktop_i.h" -#include "../../../settings/xtreme_settings/xtreme_settings.h" +#include "xtreme/assets.h" #define DesktopFaultEventExit 0x00FF00FF @@ -15,7 +15,7 @@ void desktop_scene_fault_on_enter(void* context) { Popup* popup = desktop->hw_mismatch_popup; popup_set_context(popup, desktop); - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { popup_set_header( popup, "Slut passed out\n but is now back", diff --git a/applications/services/desktop/scenes/desktop_scene_lock_menu.c b/applications/services/desktop/scenes/desktop_scene_lock_menu.c index e55fe252e..a0a2c08e9 100644 --- a/applications/services/desktop/scenes/desktop_scene_lock_menu.c +++ b/applications/services/desktop/scenes/desktop_scene_lock_menu.c @@ -36,13 +36,21 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeTick) { - bool check_pin_changed = + int check_pin_changed = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu); if(check_pin_changed) { DESKTOP_SETTINGS_LOAD(&desktop->settings); if(desktop->settings.pin_code.length > 0) { desktop_lock_menu_set_pin_state(desktop->lock_menu, true); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); + if(check_pin_changed == 2) { + desktop_pin_lock(&desktop->settings); + desktop_lock(desktop); + Power* power = furi_record_open(RECORD_POWER); + furi_delay_ms(666); + power_off(power); + furi_record_close(RECORD_POWER); + } } } } else if(event.type == SceneManagerEventTypeCustom) { @@ -73,20 +81,20 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { if(desktop->settings.pin_code.length > 0) { desktop_pin_lock(&desktop->settings); desktop_lock(desktop); + Power* power = furi_record_open(RECORD_POWER); + furi_delay_ms(666); + power_off(power); + furi_record_close(RECORD_POWER); } else { LoaderStatus status = loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG); if(status == LoaderStatusOk) { - scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1); + scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 2); } else { FURI_LOG_E(TAG, "Unable to start desktop settings"); } } consumed = true; - Power* power = furi_record_open(RECORD_POWER); - furi_delay_ms(666); - power_off(power); - furi_record_close(RECORD_POWER); break; case DesktopLockMenuEventXtremeSettings: diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 343ecac18..d7fc63578 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -207,7 +207,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; } case DesktopMainEventOpenClock: { - desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Tools/Clock.fap")); + desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Misc/Nightstand.fap")); break; } case DesktopLockedEventUpdate: diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 4cdfa54da..9e02f2bdf 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -5,7 +5,7 @@ #include "../desktop_i.h" #include "desktop_view_lock_menu.h" -#include "../../../settings/xtreme_settings/xtreme_settings.h" +#include "xtreme/settings.h" #define LOCK_MENU_ITEMS_NB 5 @@ -68,7 +68,7 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { str = "Set PIN + Off"; } } else if(i == DesktopLockMenuIndexXtremeSettings) { - str = "Xtreme Settings"; + str = "Xtreme Settings"; } if(str) //-V547 diff --git a/applications/services/dialogs/dialogs_api.c b/applications/services/dialogs/dialogs_api.c index 5e2b0683e..ca2435b9b 100644 --- a/applications/services/dialogs/dialogs_api.c +++ b/applications/services/dialogs/dialogs_api.c @@ -1,4 +1,4 @@ -#include "dialogs/dialogs_message.h" +#include "dialogs_message.h" #include "dialogs_i.h" #include #include diff --git a/applications/services/dialogs/dialogs_module_file_browser.c b/applications/services/dialogs/dialogs_module_file_browser.c index 8d486dbaf..79d151c59 100644 --- a/applications/services/dialogs/dialogs_module_file_browser.c +++ b/applications/services/dialogs/dialogs_module_file_browser.c @@ -1,6 +1,7 @@ #include "dialogs_i.h" + +#include #include -#include "gui/modules/file_browser.h" typedef struct { FuriApiLock lock; diff --git a/applications/services/dolphin/dolphin.h b/applications/services/dolphin/dolphin.h index 4371729e1..e8fc12dd3 100644 --- a/applications/services/dolphin/dolphin.h +++ b/applications/services/dolphin/dolphin.h @@ -1,8 +1,9 @@ #pragma once -#include -#include "gui/view.h" #include "helpers/dolphin_deed.h" + +#include +#include #include #ifdef __cplusplus diff --git a/applications/services/dolphin/helpers/dolphin_deed.c b/applications/services/dolphin/helpers/dolphin_deed.c index 51db56fdf..4b9f11599 100644 --- a/applications/services/dolphin/helpers/dolphin_deed.c +++ b/applications/services/dolphin/helpers/dolphin_deed.c @@ -34,7 +34,7 @@ static const DolphinDeedWeight dolphin_deed_weights[] = { {2, DolphinAppIbutton}, // DolphinDeedIbuttonEmulate {2, DolphinAppIbutton}, // DolphinDeedIbuttonAdd - {3, DolphinAppBadusb}, // DolphinDeedBadUsbPlayScript + {3, DolphinAppBadKb}, // DolphinDeedBadKbPlayScript {3, DolphinAppPlugin}, // DolphinDeedU2fAuthorized {1, DolphinAppPlugin}, // DolphinDeedGpioUartBridge @@ -50,7 +50,7 @@ static uint8_t dolphin_deed_limits[] = { 20, // DolphinAppNfc 20, // DolphinAppIr 20, // DolphinAppIbutton - 20, // DolphinAppBadusb + 20, // DolphinAppBadKb 20, // DolphinAppPlugin }; diff --git a/applications/services/dolphin/helpers/dolphin_deed.h b/applications/services/dolphin/helpers/dolphin_deed.h index c9cd18f31..51adf6b20 100644 --- a/applications/services/dolphin/helpers/dolphin_deed.h +++ b/applications/services/dolphin/helpers/dolphin_deed.h @@ -12,7 +12,7 @@ typedef enum { DolphinAppNfc, DolphinAppIr, DolphinAppIbutton, - DolphinAppBadusb, + DolphinAppBadKb, DolphinAppPlugin, DolphinAppMAX, } DolphinApp; @@ -50,7 +50,7 @@ typedef enum { DolphinDeedIbuttonEmulate, DolphinDeedIbuttonAdd, - DolphinDeedBadUsbPlayScript, + DolphinDeedBadKbPlayScript, DolphinDeedU2fAuthorized, DolphinDeedGpioUartBridge, diff --git a/applications/services/dolphin/helpers/dolphin_state.c b/applications/services/dolphin/helpers/dolphin_state.c index 72fa75ac0..419245a7c 100644 --- a/applications/services/dolphin/helpers/dolphin_state.c +++ b/applications/services/dolphin/helpers/dolphin_state.c @@ -15,9 +15,10 @@ #define DOLPHIN_STATE_HEADER_MAGIC 0xD0 #define DOLPHIN_STATE_HEADER_VERSION 0x01 -const int DOLPHIN_LEVELS[DOLPHIN_LEVEL_COUNT] = {100, 200, 300, 450, 600, 750, 950, 1150, 1350, 1600, - 1850, 2100, 2400, 2700, 3000, 3350, 3700, 4050, 4450, 4850, - 5250, 5700, 6150, 6600, 7100, 7600, 8100, 8650, 9200}; +const int DOLPHIN_LEVELS[DOLPHIN_LEVEL_COUNT] = {100, 200, 300, 450, 600, 750, 950, 1150, + 1350, 1600, 1850, 2100, 2400, 2700, 3000, 3350, + 3700, 4050, 4450, 4850, 5250, 5700, 6150, 6600, + 7100, 7600, 8100, 8650, 9200}; #define BUTTHURT_MAX 14 #define BUTTHURT_MIN 0 diff --git a/applications/services/gui/application.fam b/applications/services/gui/application.fam index 193b9dfd3..7981a4fcb 100644 --- a/applications/services/gui/application.fam +++ b/applications/services/gui/application.fam @@ -7,6 +7,7 @@ App( requires=[ "input", "notification", + "xtreme", ], stack_size=2 * 1024, order=70, diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 6a2bd3537..ee472138e 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -140,6 +140,12 @@ void canvas_set_font(Canvas* canvas, Font font) { } } +void canvas_set_custom_u8g2_font(Canvas* canvas, const uint8_t* font) { + furi_assert(canvas); + u8g2_SetFontMode(&canvas->fb, 1); + u8g2_SetFont(&canvas->fb, font); +} + void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) { furi_assert(canvas); if(!str) return; diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index 9c03ef59a..9fb554be2 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -147,6 +147,13 @@ void canvas_invert_color(Canvas* canvas); */ void canvas_set_font(Canvas* canvas, Font font); +/** Set custom drawing font + * + * @param canvas Canvas instance + * @param font Pointer to u8g2 const uint8_t* font array + */ +void canvas_set_custom_u8g2_font(Canvas* canvas, const uint8_t* font); + /** Draw string at position of baseline defined by x, y. * * @param canvas Canvas instance diff --git a/applications/services/gui/elements.c b/applications/services/gui/elements.c index e22889bf9..54c36af76 100644 --- a/applications/services/gui/elements.c +++ b/applications/services/gui/elements.c @@ -1,16 +1,17 @@ #include "elements.h" -#include "m-core.h" +#include #include -#include "furi_hal_resources.h" +#include #include -#include "gui/canvas.h" +#include #include #include #include #include "canvas_i.h" +#include #include #include #include diff --git a/applications/services/gui/gui.c b/applications/services/gui/gui.c index e1b5f0200..3eadb41f9 100644 --- a/applications/services/gui/gui.c +++ b/applications/services/gui/gui.c @@ -1,4 +1,4 @@ -#include "gui/canvas.h" +#include "xtreme/settings.h" #include "gui_i.h" #include @@ -55,30 +55,128 @@ static void gui_redraw_status_bar(Gui* gui, bool need_attention) { canvas_frame_set( gui->canvas, GUI_STATUS_BAR_X, GUI_STATUS_BAR_Y, GUI_DISPLAY_WIDTH, GUI_STATUS_BAR_HEIGHT); + XtremeSettings* xtreme_settings = XTREME_SETTINGS(); + /* for support black theme - paint white area and * draw icon with transparent white color */ - canvas_set_color(gui->canvas, ColorWhite); - // canvas_draw_box(gui->canvas, 1, 1, 9, 7); - // canvas_draw_box(gui->canvas, 7, 3, 58, 6); - // canvas_draw_box(gui->canvas, 61, 1, 32, 7); - // canvas_draw_box(gui->canvas, 89, 3, 38, 6); - canvas_set_color(gui->canvas, ColorBlack); - canvas_set_bitmap_mode(gui->canvas, 1); - // canvas_draw_icon(gui->canvas, 0, 0, &I_Background_128x11); + if(xtreme_settings->bar_background) { + canvas_set_color(gui->canvas, ColorWhite); + canvas_draw_box(gui->canvas, 1, 1, 9, 7); + canvas_draw_box(gui->canvas, 7, 3, 58, 6); + canvas_draw_box(gui->canvas, 61, 1, 32, 7); + canvas_draw_box(gui->canvas, 89, 3, 38, 6); + canvas_set_color(gui->canvas, ColorBlack); + canvas_set_bitmap_mode(gui->canvas, 1); + canvas_draw_icon(gui->canvas, 0, 0, &I_Background_128x11); + } else { + canvas_set_color(gui->canvas, ColorBlack); + } canvas_set_bitmap_mode(gui->canvas, 0); + uint8_t x; + // Right side - uint8_t x = GUI_DISPLAY_WIDTH - 1; - ViewPortArray_it(it, gui->layers[GuiLayerStatusBarRight]); - while(!ViewPortArray_end_p(it) && right_used < GUI_STATUS_BAR_WIDTH) { - ViewPort* view_port = *ViewPortArray_ref(it); - if(view_port_is_enabled(view_port)) { - width = view_port_get_width(view_port); - if(!width) width = 8; - // Recalculate next position - right_used += (width + 2); - x -= (width + 2); + if(xtreme_settings->battery_icon != BatteryIconOff) { + x = GUI_DISPLAY_WIDTH - 1; + ViewPortArray_it(it, gui->layers[GuiLayerStatusBarRight]); + while(!ViewPortArray_end_p(it) && right_used < GUI_STATUS_BAR_WIDTH) { + ViewPort* view_port = *ViewPortArray_ref(it); + if(view_port_is_enabled(view_port)) { + width = view_port_get_width(view_port); + if(!width) width = 8; + // Recalculate next position + right_used += (width + 2); + x -= (width + 2); + // Prepare work area background + canvas_frame_set( + gui->canvas, + x - 1, + GUI_STATUS_BAR_Y + 1, + width + 2, + GUI_STATUS_BAR_WORKAREA_HEIGHT + 2); + // Hide battery background + if(xtreme_settings->bar_borders) { + canvas_set_color(gui->canvas, ColorWhite); + canvas_draw_box( + gui->canvas, -1, 0, canvas_width(gui->canvas) + 1, canvas_height(gui->canvas)); + } + canvas_set_color(gui->canvas, ColorBlack); + // ViewPort draw + canvas_frame_set( + gui->canvas, + x - xtreme_settings->bar_borders, + GUI_STATUS_BAR_Y + 2, + width, + GUI_STATUS_BAR_WORKAREA_HEIGHT); + view_port_draw(view_port, gui->canvas); + } + ViewPortArray_next(it); + } + // Draw frame around icons on the right + if(right_used) { + canvas_frame_set( + gui->canvas, + GUI_DISPLAY_WIDTH - 4 - right_used, + GUI_STATUS_BAR_Y, + right_used + 4, + GUI_STATUS_BAR_HEIGHT); + // Disable battery border + if(xtreme_settings->bar_borders) { + canvas_set_color(gui->canvas, ColorBlack); + canvas_draw_rframe( + gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas), 1); + canvas_draw_line( + gui->canvas, + canvas_width(gui->canvas) - 2, + 1, + canvas_width(gui->canvas) - 2, + canvas_height(gui->canvas) - 2); + canvas_draw_line( + gui->canvas, + 1, + canvas_height(gui->canvas) - 2, + canvas_width(gui->canvas) - 2, + canvas_height(gui->canvas) - 2); + } + } + } + + // Left side + if(xtreme_settings->status_icons) { + x = 2; + ViewPortArray_it(it, gui->layers[GuiLayerStatusBarLeft]); + while(!ViewPortArray_end_p(it) && (right_used + left_used) < GUI_STATUS_BAR_WIDTH) { + ViewPort* view_port = *ViewPortArray_ref(it); + if(view_port_is_enabled(view_port)) { + width = view_port_get_width(view_port); + if(!width) width = 8; + // Prepare work area background + canvas_frame_set( + gui->canvas, + x - 1, + GUI_STATUS_BAR_Y + 1, + width + 2, + GUI_STATUS_BAR_WORKAREA_HEIGHT + 2); + if(xtreme_settings->bar_borders) { + canvas_set_color(gui->canvas, ColorWhite); + canvas_draw_box( + gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas)); + } + canvas_set_color(gui->canvas, ColorBlack); + // ViewPort draw + canvas_frame_set( + gui->canvas, x, GUI_STATUS_BAR_Y + 2, width, GUI_STATUS_BAR_WORKAREA_HEIGHT); + view_port_draw(view_port, gui->canvas); + // Recalculate next position + left_used += (width + 2); + x += (width + 2); + } + ViewPortArray_next(it); + } + // Extra notification + if(need_attention) { + width = icon_get_width(&I_Hidden_window_9x8); // Prepare work area background canvas_frame_set( gui->canvas, @@ -86,56 +184,40 @@ static void gui_redraw_status_bar(Gui* gui, bool need_attention) { GUI_STATUS_BAR_Y + 1, width + 2, GUI_STATUS_BAR_WORKAREA_HEIGHT + 2); - // canvas_set_color(gui->canvas, ColorWhite); - // canvas_draw_box( - // gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas)); + if(xtreme_settings->bar_borders) { + canvas_set_color(gui->canvas, ColorWhite); + canvas_draw_box( + gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas)); + } canvas_set_color(gui->canvas, ColorBlack); - // ViewPort draw + // Draw Icon canvas_frame_set( gui->canvas, x, GUI_STATUS_BAR_Y + 2, width, GUI_STATUS_BAR_WORKAREA_HEIGHT); - view_port_draw(view_port, gui->canvas); + canvas_draw_icon(gui->canvas, 0, 0, &I_Hidden_window_9x8); + // Recalculate next position + left_used += (width + 2); + x += (width + 2); + } + // Draw frame around icons on the left + if(left_used) { + canvas_frame_set(gui->canvas, 0, 0, left_used + 3, GUI_STATUS_BAR_HEIGHT); + if(xtreme_settings->bar_borders) { + canvas_draw_rframe( + gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas), 1); + canvas_draw_line( + gui->canvas, + canvas_width(gui->canvas) - 2, + 1, + canvas_width(gui->canvas) - 2, + canvas_height(gui->canvas) - 2); + canvas_draw_line( + gui->canvas, + 1, + canvas_height(gui->canvas) - 2, + canvas_width(gui->canvas) - 2, + canvas_height(gui->canvas) - 2); + } } - ViewPortArray_next(it); - } - // Draw frame around icons on the right - if(right_used) { - canvas_frame_set( - gui->canvas, - GUI_DISPLAY_WIDTH - 3 - right_used, - GUI_STATUS_BAR_Y, - right_used + 2, - GUI_STATUS_BAR_HEIGHT); - // canvas_set_color(gui->canvas, ColorBlack); - // canvas_draw_rframe( - // gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas) - 1, 1); - // canvas_draw_line( - // gui->canvas, - // canvas_width(gui->canvas) - 1, - // 2, - // canvas_width(gui->canvas) - 1, - // canvas_height(gui->canvas) - 4); - } - - // Extra notification - if(need_attention) { - width = icon_get_width(&I_Hidden_window_9x8); - // Prepare work area background - canvas_frame_set( - gui->canvas, - x - 1, - GUI_STATUS_BAR_Y + 1, - width + 2, - GUI_STATUS_BAR_WORKAREA_HEIGHT + 2); - canvas_set_color(gui->canvas, ColorWhite); - canvas_draw_box(gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas)); - canvas_set_color(gui->canvas, ColorBlack); - // Draw Icon - canvas_frame_set( - gui->canvas, x, GUI_STATUS_BAR_Y + 2, width, GUI_STATUS_BAR_WORKAREA_HEIGHT); - canvas_draw_icon(gui->canvas, 0, 0, &I_Hidden_window_9x8); - // Recalculate next position - left_used += (width + 2); - x += (width + 2); } } diff --git a/applications/services/gui/modules/button_menu.c b/applications/services/gui/modules/button_menu.c index 427a3e1ae..6ac786c92 100644 --- a/applications/services/gui/modules/button_menu.c +++ b/applications/services/gui/modules/button_menu.c @@ -1,12 +1,15 @@ #include "button_menu.h" -#include "gui/canvas.h" -#include "gui/elements.h" -#include "input/input.h" -#include + +#include +#include +#include + #include -#include #include +#include +#include + #define ITEM_FIRST_OFFSET 17 #define ITEM_NEXT_OFFSET 4 #define ITEM_HEIGHT 14 diff --git a/applications/services/gui/modules/button_panel.c b/applications/services/gui/modules/button_panel.c index 9248ac0fa..6276c6a82 100644 --- a/applications/services/gui/modules/button_panel.c +++ b/applications/services/gui/modules/button_panel.c @@ -1,12 +1,15 @@ #include "button_panel.h" -#include "furi_hal_resources.h" -#include "gui/canvas.h" + +#include +#include + +#include +#include +#include + #include #include #include -#include -#include -#include typedef struct { // uint16_t to support multi-screen, wide button panel diff --git a/applications/services/gui/modules/byte_input.c b/applications/services/gui/modules/byte_input.c index 82de129f5..b2d21f7ae 100644 --- a/applications/services/gui/modules/byte_input.c +++ b/applications/services/gui/modules/byte_input.c @@ -1,8 +1,9 @@ -#include -#include -#include #include "byte_input.h" +#include +#include +#include + struct ByteInput { View* view; }; diff --git a/applications/services/gui/modules/file_browser.c b/applications/services/gui/modules/file_browser.c index 9d65df46b..5477192a0 100644 --- a/applications/services/gui/modules/file_browser.c +++ b/applications/services/gui/modules/file_browser.c @@ -1,16 +1,19 @@ #include "file_browser.h" -#include "assets_icons.h" #include "file_browser_worker.h" + +#include +#include +#include + +#include +#include + #include #include #include -#include "furi_hal_resources.h" -#include "m-string.h" #include "m-algo.h" #include -#include -#include -#include "toolbox/path.h" +#include "xtreme/settings.h" #define LIST_ITEMS 5u #define MAX_LEN_PX 110 @@ -32,6 +35,7 @@ typedef enum { } BrowserItemType; typedef struct { + uint32_t unsorted_idx; FuriString* path; BrowserItemType type; uint8_t* custom_icon_data; @@ -39,6 +43,7 @@ typedef struct { } BrowserItem_t; static void BrowserItem_t_init(BrowserItem_t* obj) { + obj->unsorted_idx = 0; obj->type = BrowserItemTypeLoading; obj->path = furi_string_alloc(); obj->display_name = furi_string_alloc(); @@ -46,6 +51,7 @@ static void BrowserItem_t_init(BrowserItem_t* obj) { } static void BrowserItem_t_init_set(BrowserItem_t* obj, const BrowserItem_t* src) { + obj->unsorted_idx = src->unsorted_idx; obj->type = src->type; obj->path = furi_string_alloc_set(src->path); obj->display_name = furi_string_alloc_set(src->display_name); @@ -58,6 +64,7 @@ static void BrowserItem_t_init_set(BrowserItem_t* obj, const BrowserItem_t* src) } static void BrowserItem_t_set(BrowserItem_t* obj, const BrowserItem_t* src) { + obj->unsorted_idx = src->unsorted_idx; obj->type = src->type; furi_string_set(obj->path, src->path); furi_string_set(obj->display_name, src->display_name); @@ -78,13 +85,22 @@ static void BrowserItem_t_clear(BrowserItem_t* obj) { static int BrowserItem_t_cmp(const BrowserItem_t* a, const BrowserItem_t* b) { // Back indicator comes before everything, then folders, then all other files. - if((a->type == BrowserItemTypeBack) || - (a->type == BrowserItemTypeFolder && b->type != BrowserItemTypeFolder && - b->type != BrowserItemTypeBack)) { + if(a->type == BrowserItemTypeBack) { return -1; } + if(b->type == BrowserItemTypeBack) { + return 1; + } + if(!XTREME_SETTINGS()->sort_ignore_dirs) { + if(a->type == BrowserItemTypeFolder && b->type != BrowserItemTypeFolder) { + return -1; + } + if(a->type != BrowserItemTypeFolder && b->type == BrowserItemTypeFolder) { + return 1; + } + } - return furi_string_cmp(a->path, b->path); + return furi_string_cmpi(a->path, b->path); } #define M_OPL_BrowserItem_t() \ @@ -148,8 +164,12 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context); static void browser_folder_open_cb(void* context, uint32_t item_cnt, int32_t file_idx, bool is_root); static void browser_list_load_cb(void* context, uint32_t list_load_offset); -static void - browser_list_item_cb(void* context, FuriString* item_path, bool is_folder, bool is_last); +static void browser_list_item_cb( + void* context, + FuriString* item_path, + uint32_t idx, + bool is_folder, + bool is_last); static void browser_long_load_cb(void* context); static void file_browser_scroll_timer_callback(void* context) { @@ -338,7 +358,7 @@ static void browser_update_offset(FileBrowser* browser) { CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0); } }, - false); + true); } static void @@ -370,7 +390,7 @@ static void model->list_loading = true; model->folder_loading = false; }, - true); + false); browser_update_offset(browser); file_browser_worker_load(browser->worker, load_offset, ITEM_LIST_LEN_MAX); @@ -403,13 +423,18 @@ static void browser_list_load_cb(void* context, uint32_t list_load_offset) { BrowserItem_t_clear(&back_item); } -static void - browser_list_item_cb(void* context, FuriString* item_path, bool is_folder, bool is_last) { +static void browser_list_item_cb( + void* context, + FuriString* item_path, + uint32_t idx, + bool is_folder, + bool is_last) { furi_assert(context); FileBrowser* browser = (FileBrowser*)context; BrowserItem_t item; item.custom_icon_data = NULL; + item.unsorted_idx = idx; if(!is_last) { item.path = furi_string_alloc_set(item_path); @@ -445,7 +470,7 @@ static void items_array_push_back(model->items, item); // TODO: calculate if element is visible }, - true); + false); furi_string_free(item.display_name); furi_string_free(item.path); if(item.custom_icon_data) { @@ -456,10 +481,28 @@ static void browser->view, FileBrowserModel * model, { - items_array_sort(model->items); + if(model->item_cnt <= BROWSER_SORT_THRESHOLD) { + FuriString* selected = NULL; + if(model->item_idx > 0) { + selected = furi_string_alloc_set( + items_array_get(model->items, model->item_idx)->path); + } + + items_array_sort(model->items); + + if(selected != NULL) { + for(uint32_t i = 0; i < model->item_cnt; i++) { + if(!furi_string_cmp(items_array_get(model->items, i)->path, selected)) { + model->item_idx = i; + break; + } + } + } + } model->list_loading = false; }, - true); + false); + browser_update_offset(browser); } } @@ -506,19 +549,25 @@ static void browser_draw_list(Canvas* canvas, FileBrowserModel* model) { for(uint32_t i = 0; i < MIN(model->item_cnt, LIST_ITEMS); i++) { int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u); - BrowserItemType item_type = BrowserItemTypeLoading; + BrowserItemType item_type; uint8_t* custom_icon_data = NULL; if(browser_is_item_in_array(model, idx)) { BrowserItem_t* item = items_array_get( model->items, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0)); item_type = item->type; - furi_string_set(filename, item->display_name); - if(item_type == BrowserItemTypeFile) { - custom_icon_data = item->custom_icon_data; + if(model->list_loading && item_type != BrowserItemTypeBack) { + furi_string_set(filename, "---"); + item_type = BrowserItemTypeLoading; + } else { + furi_string_set(filename, item->display_name); + if(item_type == BrowserItemTypeFile) { + custom_icon_data = item->custom_icon_data; + } } } else { furi_string_set(filename, "---"); + item_type = BrowserItemTypeLoading; } if(item_type == BrowserItemTypeBack) { @@ -600,7 +649,10 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { bool is_loading = false; with_view_model( - browser->view, FileBrowserModel * model, { is_loading = model->folder_loading; }, false); + browser->view, + FileBrowserModel * model, + { is_loading = model->folder_loading || model->list_loading; }, + false); if(is_loading) { return false; @@ -637,7 +689,7 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { model->scroll_counter = 0; } }, - true); + false); browser_update_offset(browser); consumed = true; } @@ -652,10 +704,7 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { if(browser_is_item_in_array(model, model->item_idx)) { selected_item = items_array_get(model->items, model->item_idx - model->array_offset); - select_index = model->item_idx; - if((!model->is_root) && (select_index > 0)) { - select_index -= 1; - } + select_index = selected_item->unsorted_idx; } }, false); diff --git a/applications/services/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c index 4386fdfd0..9d219429b 100644 --- a/applications/services/gui/modules/file_browser_worker.c +++ b/applications/services/gui/modules/file_browser_worker.c @@ -1,19 +1,20 @@ #include "file_browser_worker.h" + +#include +#include + +#include #include #include -#include "storage/filesystem_api_defines.h" +#include + #include #include -#include -#include #include -#include "toolbox/path.h" #define TAG "BrowserWorker" #define ASSETS_DIR "assets" -#define BADUSB_LAYOUTS_DIR "layouts" -#define SUBGHZ_TEMP_DIR "tmp_history" #define BROWSER_ROOT STORAGE_ANY_PATH_PREFIX #define FILE_NAME_LEN_MAX 256 #define LONG_LOAD_THRESHOLD 100 @@ -89,9 +90,7 @@ static bool browser_filter_by_name(BrowserWorker* browser, FuriString* name, boo if(is_folder) { // Skip assets folders (if enabled) if(browser->skip_assets) { - return ((furi_string_cmp_str(name, ASSETS_DIR) == 0) ? (false) : (true)) && - ((furi_string_cmp_str(name, BADUSB_LAYOUTS_DIR) == 0) ? (false) : (true)) && - ((furi_string_cmp_str(name, SUBGHZ_TEMP_DIR) == 0) ? (false) : (true)); + return ((furi_string_cmp_str(name, ASSETS_DIR) == 0) ? (false) : (true)); } else { return true; } @@ -190,8 +189,12 @@ static bool browser_folder_init( return state; } -static bool - browser_folder_load(BrowserWorker* browser, FuriString* path, uint32_t offset, uint32_t count) { +// Load files list by chunks, like it was originally, not compatible with sorting, sorting needs to be disabled to use this +static bool browser_folder_load_chunked( + BrowserWorker* browser, + FuriString* path, + uint32_t offset, + uint32_t count) { FileInfo file_info; Storage* storage = furi_record_open(RECORD_STORAGE); @@ -241,7 +244,11 @@ static bool furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp); if(browser->list_item_cb) { browser->list_item_cb( - browser->cb_ctx, name_str, (file_info.flags & FSF_DIRECTORY), false); + browser->cb_ctx, + name_str, + items_cnt, + (file_info.flags & FSF_DIRECTORY), + false); } items_cnt++; } @@ -250,7 +257,7 @@ static bool } } if(browser->list_item_cb) { - browser->list_item_cb(browser->cb_ctx, NULL, false, true); + browser->list_item_cb(browser->cb_ctx, NULL, 0, false, true); } } while(0); @@ -264,6 +271,59 @@ static bool return (items_cnt == count); } +// Load all files at once, may cause memory overflow so need to limit that to about 400 files +static bool browser_folder_load_full(BrowserWorker* browser, FuriString* path) { + FileInfo file_info; + + Storage* storage = furi_record_open(RECORD_STORAGE); + File* directory = storage_file_alloc(storage); + + char name_temp[FILE_NAME_LEN_MAX]; + FuriString* name_str; + name_str = furi_string_alloc(); + + uint32_t items_cnt = 0; + + bool ret = false; + do { + if(!storage_dir_open(directory, furi_string_get_cstr(path))) { + break; + } + if(browser->list_load_cb) { + browser->list_load_cb(browser->cb_ctx, 0); + } + while(storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX) && + storage_file_get_error(directory) == FSE_OK) { + furi_string_set(name_str, name_temp); + if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { + furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp); + if(browser->list_item_cb) { + browser->list_item_cb( + browser->cb_ctx, + name_str, + items_cnt, + (file_info.flags & FSF_DIRECTORY), + false); + } + items_cnt++; + } + } + if(browser->list_item_cb) { + browser->list_item_cb(browser->cb_ctx, NULL, 0, false, true); + } + ret = true; + } while(0); + + furi_string_free(name_str); + + storage_dir_close(directory); + storage_file_free(directory); + + furi_record_close(RECORD_STORAGE); + + return ret; +} + static int32_t browser_worker(void* context) { BrowserWorker* browser = (BrowserWorker*)context; furi_assert(browser); @@ -358,7 +418,12 @@ static int32_t browser_worker(void* context) { if(flags & WorkerEvtLoad) { FURI_LOG_D( TAG, "Load offset: %lu cnt: %lu", browser->load_offset, browser->load_count); - browser_folder_load(browser, path, browser->load_offset, browser->load_count); + if(items_cnt > BROWSER_SORT_THRESHOLD) { + browser_folder_load_chunked( + browser, path, browser->load_offset, browser->load_count); + } else { + browser_folder_load_full(browser, path); + } } if(flags & WorkerEvtStop) { diff --git a/applications/services/gui/modules/file_browser_worker.h b/applications/services/gui/modules/file_browser_worker.h index 3b4be6aa7..859b11be4 100644 --- a/applications/services/gui/modules/file_browser_worker.h +++ b/applications/services/gui/modules/file_browser_worker.h @@ -7,6 +7,8 @@ extern "C" { #endif +#define BROWSER_SORT_THRESHOLD 400 + typedef struct BrowserWorker BrowserWorker; typedef void (*BrowserWorkerFolderOpenCallback)( void* context, @@ -17,6 +19,7 @@ typedef void (*BrowserWorkerListLoadCallback)(void* context, uint32_t list_load_ typedef void (*BrowserWorkerListItemCallback)( void* context, FuriString* item_path, + uint32_t idx, bool is_folder, bool is_last); typedef void (*BrowserWorkerLongLoadCallback)(void* context); diff --git a/applications/services/gui/modules/loading.c b/applications/services/gui/modules/loading.c index 0fa2c1286..e64aeb78f 100644 --- a/applications/services/gui/modules/loading.c +++ b/applications/services/gui/modules/loading.c @@ -1,13 +1,14 @@ -#include -#include -#include +#include "loading.h" + #include #include #include #include #include -#include "loading.h" +#include +#include +#include struct Loading { View* view; diff --git a/applications/services/gui/modules/menu.c b/applications/services/gui/modules/menu.c index 6983e0108..3e3b6c2e4 100644 --- a/applications/services/gui/modules/menu.c +++ b/applications/services/gui/modules/menu.c @@ -1,9 +1,9 @@ #include "menu.h" -#include #include #include #include +#include struct Menu { View* view; diff --git a/applications/services/gui/modules/submenu.c b/applications/services/gui/modules/submenu.c index 88c1c55d4..17dc8aa29 100644 --- a/applications/services/gui/modules/submenu.c +++ b/applications/services/gui/modules/submenu.c @@ -1,9 +1,9 @@ #include "submenu.h" #include -#include #include #include +#include struct Submenu { View* view; diff --git a/applications/services/gui/modules/text_box.c b/applications/services/gui/modules/text_box.c index 079a1294d..01ccdbf52 100644 --- a/applications/services/gui/modules/text_box.c +++ b/applications/services/gui/modules/text_box.c @@ -1,7 +1,7 @@ #include "text_box.h" -#include "gui/canvas.h" -#include +#include #include +#include #include struct TextBox { diff --git a/applications/services/gui/modules/validators.c b/applications/services/gui/modules/validators.c index 9c5d0be84..a18cb925f 100644 --- a/applications/services/gui/modules/validators.c +++ b/applications/services/gui/modules/validators.c @@ -1,6 +1,6 @@ -#include #include "validators.h" #include +#include struct ValidatorIsFile { char* app_path_folder; diff --git a/applications/services/gui/modules/validators.h b/applications/services/gui/modules/validators.h index d9200b6db..e509fd833 100644 --- a/applications/services/gui/modules/validators.h +++ b/applications/services/gui/modules/validators.h @@ -1,6 +1,7 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { diff --git a/applications/services/gui/modules/variable_item_list.c b/applications/services/gui/modules/variable_item_list.c index 5060985e1..cf7f64ca3 100644 --- a/applications/services/gui/modules/variable_item_list.c +++ b/applications/services/gui/modules/variable_item_list.c @@ -1,8 +1,8 @@ #include "variable_item_list.h" -#include "gui/canvas.h" -#include -#include #include +#include +#include +#include #include struct VariableItem { diff --git a/applications/services/gui/modules/widget.c b/applications/services/gui/modules/widget.c index 6153b425b..21b8e5616 100644 --- a/applications/services/gui/modules/widget.c +++ b/applications/services/gui/modules/widget.c @@ -1,7 +1,7 @@ -#include #include "widget.h" -#include #include "widget_elements/widget_element_i.h" +#include +#include ARRAY_DEF(ElementArray, WidgetElement*, M_PTR_OPLIST); diff --git a/applications/services/gui/view_stack.c b/applications/services/gui/view_stack.c index 3bb00fbf2..0a106f1ba 100644 --- a/applications/services/gui/view_stack.c +++ b/applications/services/gui/view_stack.c @@ -1,8 +1,9 @@ -#include "gui/view.h" -#include #include "view_stack.h" #include "view_i.h" +#include +#include + #define MAX_VIEWS 3 typedef struct { diff --git a/applications/services/namechangersrv/application.fam b/applications/services/namechangersrv/application.fam index b4bace40d..3263a3708 100644 --- a/applications/services/namechangersrv/application.fam +++ b/applications/services/namechangersrv/application.fam @@ -4,4 +4,4 @@ App( entry_point="namechanger_on_system_start", requires=["storage"], order=1000, -) \ No newline at end of file +) diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index b6579f547..2e170f547 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -1,4 +1,4 @@ -#include "furi_hal_light.h" +#include #include #include #include diff --git a/applications/services/notification/notification_messages.c b/applications/services/notification/notification_messages.c index d795c55d9..51f3533c3 100644 --- a/applications/services/notification/notification_messages.c +++ b/applications/services/notification/notification_messages.c @@ -1,4 +1,4 @@ -#include "furi_hal_resources.h" +#include #include "notification.h" #include "notification_messages_notes.h" #include diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index f0f7735fb..aff3d946d 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -2,15 +2,15 @@ #include #include -#include "../../../settings/xtreme_settings/xtreme_settings.h" +#include "xtreme/settings.h" #define POWER_OFF_TIMEOUT 90 void power_draw_battery_callback(Canvas* canvas, void* context) { furi_assert(context); Power* power = context; - BatteryStyle battery_style = XTREME_SETTINGS()->battery_style; - if(battery_style == BatteryStyleOff) return; + BatteryIcon battery_icon = XTREME_SETTINGS()->battery_icon; + if(battery_icon == BatteryIconOff) return; canvas_draw_icon(canvas, 0, 0, &I_Battery_25x8); canvas_set_color(canvas, ColorWhite); @@ -25,8 +25,8 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { char batteryPercentile[4]; snprintf(batteryPercentile, sizeof(batteryPercentile), "%d", power->info.charge); - if((battery_style == BatteryStylePercent) && - (power->state != + if((battery_icon == BatteryIconPercent) && + (power->state != PowerStateCharging)) { //if display battery percentage, black background white text canvas_set_font(canvas, FontBatteryPercent); canvas_set_color(canvas, ColorBlack); @@ -34,14 +34,14 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_set_color(canvas, ColorWhite); canvas_draw_str_aligned(canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile); } else if( - (battery_style == BatteryStyleInvertedPercent) && + (battery_icon == BatteryIconInvertedPercent) && (power->state != - PowerStateCharging)) { //if display inverted percentage, white background black text + PowerStateCharging)) { //if display inverted percentage, white background black text canvas_set_font(canvas, FontBatteryPercent); canvas_set_color(canvas, ColorBlack); canvas_draw_str_aligned(canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile); } else if( - (battery_style == BatteryStyleRetro3) && + (battery_icon == BatteryIconRetro3) && (power->state != PowerStateCharging)) { //Retro style segmented display, 3 parts if(power->info.charge > 25) { canvas_draw_box(canvas, 2, 2, 6, 4); @@ -53,7 +53,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_draw_box(canvas, 16, 2, 6, 4); } } else if( - (battery_style == BatteryStyleRetro5) && + (battery_icon == BatteryIconRetro5) && (power->state != PowerStateCharging)) { //Retro style segmented display, 5 parts if(power->info.charge > 10) { canvas_draw_box(canvas, 2, 2, 3, 4); @@ -71,10 +71,10 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_draw_box(canvas, 18, 2, 3, 4); } } else if( - (battery_style == BatteryStyleBarPercent) && + (battery_icon == BatteryIconBarPercent) && (power->state != PowerStateCharging) && // Default bar display with percentage (power->info.voltage_battery_charging >= - 4.2)) { // not looking nice with low voltage indicator + 4.2)) { // not looking nice with low voltage indicator canvas_set_font(canvas, FontBatteryPercent); // align charge dispaly value with digits to draw @@ -145,8 +145,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { if(power->state == PowerStateCharging) { canvas_set_bitmap_mode(canvas, 1); // TODO: replace -1 magic for uint8_t with re-framing - if(battery_style == BatteryStylePercent || - battery_style == BatteryStyleBarPercent) { + if(battery_icon == BatteryIconPercent || battery_icon == BatteryIconBarPercent) { canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 1, 1, 22, 6); canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10); @@ -155,7 +154,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontBatteryPercent); canvas_draw_str_aligned( canvas, 16, 4, AlignCenter, AlignCenter, batteryPercentile); - } else if(battery_style == BatteryStyleInvertedPercent) { + } else if(battery_icon == BatteryIconInvertedPercent) { canvas_set_color(canvas, ColorWhite); canvas_draw_box(canvas, 1, 1, 22, 6); canvas_draw_icon(canvas, 2, -1, &I_Charging_lightning_9x10); diff --git a/applications/services/power/power_service/power.h b/applications/services/power/power_service/power.h index 58c85a9a9..6e41d5c6e 100644 --- a/applications/services/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -26,14 +26,15 @@ typedef enum { } PowerEventType; typedef enum { - BatteryStyleOff = 1, - BatteryStyleBar = 2, - BatteryStylePercent = 3, - BatteryStyleInvertedPercent = 4, - BatteryStyleRetro3 = 5, - BatteryStyleRetro5 = 6, - BatteryStyleBarPercent = 0, -} BatteryStyle; + BatteryIconOff = 1, + BatteryIconBar = 2, + BatteryIconPercent = 3, + BatteryIconInvertedPercent = 4, + BatteryIconRetro3 = 5, + BatteryIconRetro5 = 6, + BatteryIconBarPercent = 0, + BatteryIconCount = 7, +} BatteryIcon; typedef union { uint8_t battery_level; diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index c83f16499..eeaa7fce8 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -60,17 +61,28 @@ static void storage_cli_info(Cli* cli, FuriString* path) { } } else if(furi_string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0) { SDInfo sd_info; + SD_CID sd_cid; FS_Error error = storage_sd_info(api, &sd_info); + BSP_SD_GetCIDRegister(&sd_cid); if(error != FSE_OK) { storage_cli_print_error(error); } else { printf( - "Label: %s\r\nType: %s\r\n%luKiB total\r\n%luKiB free\r\n", + "Label: %s\r\nType: %s\r\n%luKiB total\r\n%luKiB free\r\n" + "%02x%2.2s %5.5s %i.%i\r\nSN:%04lx %02i/%i\r\n", sd_info.label, sd_api_get_fs_type_text(sd_info.fs_type), sd_info.kb_total, - sd_info.kb_free); + sd_info.kb_free, + sd_cid.ManufacturerID, + sd_cid.OEM_AppliID, + sd_cid.ProdName, + sd_cid.ProdRev >> 4, + sd_cid.ProdRev & 0xf, + sd_cid.ProdSN, + sd_cid.ManufactMonth, + sd_cid.ManufactYear + 2000); } } else { storage_cli_print_usage(); diff --git a/applications/services/xtreme/application.fam b/applications/services/xtreme/application.fam new file mode 100644 index 000000000..2dfcab051 --- /dev/null +++ b/applications/services/xtreme/application.fam @@ -0,0 +1,10 @@ +App( + appid="xtreme", + apptype=FlipperAppType.STARTUP, + entry_point="xtreme_on_system_start", + requires=["storage"], + order=1000, + provides=[ + "xtreme", + ], +) diff --git a/applications/services/xtreme/assets.c b/applications/services/xtreme/assets.c new file mode 100644 index 000000000..1862f1ec7 --- /dev/null +++ b/applications/services/xtreme/assets.c @@ -0,0 +1,160 @@ +#include "assets.h" +#include +#include + +#define ICONS_FMT PACKS_DIR "/%s/Icons/%s" + +XtremeAssets* xtreme_assets = NULL; + +void anim(const Icon** replace, const char* name, FuriString* path, File* file) { + do { + furi_string_printf(path, ICONS_FMT "/meta", XTREME_SETTINGS()->asset_pack, name); + if(!storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) + break; + int32_t width, height, frame_rate, frame_count; + storage_file_read(file, &width, 4); + storage_file_read(file, &height, 4); + storage_file_read(file, &frame_rate, 4); + storage_file_read(file, &frame_count, 4); + storage_file_close(file); + + Icon* icon = malloc(sizeof(Icon)); + FURI_CONST_ASSIGN(icon->width, width); + FURI_CONST_ASSIGN(icon->height, height); + FURI_CONST_ASSIGN(icon->frame_rate, frame_rate); + FURI_CONST_ASSIGN(icon->frame_count, frame_count); + icon->frames = malloc(sizeof(const uint8_t*) * icon->frame_count); + const char* pack = XTREME_SETTINGS()->asset_pack; + + bool ok = true; + for(int i = 0; i < icon->frame_count; ++i) { + FURI_CONST_ASSIGN_PTR(icon->frames[i], 0); + if(ok) { + ok = false; + furi_string_printf(path, ICONS_FMT "/frame_%02d.bm", pack, name, i); + do { + if(!storage_file_open( + file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) + break; + + uint64_t size = storage_file_size(file); + FURI_CONST_ASSIGN_PTR(icon->frames[i], malloc(size)); + if(storage_file_read(file, (void*)icon->frames[i], size) == size) ok = true; + storage_file_close(file); + } while(0); + } + } + if(!ok) { + for(int i = 0; i < icon->frame_count; ++i) { + if(icon->frames[i]) { + free((void*)icon->frames[i]); + } + } + free((void*)icon->frames); + free(icon); + + break; + } + + *replace = icon; + } while(false); +} + +void icon(const Icon** replace, const char* name, FuriString* path, File* file) { + furi_string_printf(path, ICONS_FMT ".bmx", XTREME_SETTINGS()->asset_pack, name); + if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + uint64_t size = storage_file_size(file) - 8; + int32_t width, height; + storage_file_read(file, &width, 4); + storage_file_read(file, &height, 4); + + Icon* icon = malloc(sizeof(Icon)); + FURI_CONST_ASSIGN(icon->frame_count, 1); + FURI_CONST_ASSIGN(icon->frame_rate, 0); + FURI_CONST_ASSIGN(icon->width, width); + FURI_CONST_ASSIGN(icon->height, height); + icon->frames = malloc(sizeof(const uint8_t*)); + FURI_CONST_ASSIGN_PTR(icon->frames[0], malloc(size)); + storage_file_read(file, (void*)icon->frames[0], size); + *replace = icon; + + storage_file_close(file); + } +} + +void swap(XtremeAssets* x, FuriString* p, File* f) { + anim(&x->A_Levelup_128x64, "Animations/Levelup_128x64", p, f); + icon(&x->I_BLE_Pairing_128x64, "BLE/BLE_Pairing_128x64", p, f); + icon(&x->I_DolphinCommon_56x48, "Dolphin/DolphinCommon_56x48", p, f); + icon(&x->I_DolphinMafia_115x62, "iButton/DolphinMafia_115x62", p, f); + icon(&x->I_DolphinNice_96x59, "iButton/DolphinNice_96x59", p, f); + icon(&x->I_DolphinWait_61x59, "iButton/DolphinWait_61x59", p, f); + icon(&x->I_iButtonDolphinVerySuccess_108x52, "iButton/iButtonDolphinVerySuccess_108x52", p, f); + icon(&x->I_DolphinReadingSuccess_59x63, "Infrared/DolphinReadingSuccess_59x63", p, f); + icon(&x->I_NFC_dolphin_emulation_47x61, "NFC/NFC_dolphin_emulation_47x61", p, f); + icon(&x->I_passport_bad_46x49, "Passport/passport_bad_46x49", p, f); + icon(&x->I_passport_DB, "Passport/passport_DB", p, f); + icon(&x->I_passport_happy_46x49, "Passport/passport_happy_46x49", p, f); + icon(&x->I_passport_okay_46x49, "Passport/passport_okay_46x49", p, f); + icon(&x->I_RFIDDolphinReceive_97x61, "RFID/RFIDDolphinReceive_97x61", p, f); + icon(&x->I_RFIDDolphinSend_97x61, "RFID/RFIDDolphinSend_97x61", p, f); + icon(&x->I_RFIDDolphinSuccess_108x57, "RFID/RFIDDolphinSuccess_108x57", p, f); + icon(&x->I_Cry_dolph_55x52, "Settings/Cry_dolph_55x52", p, f); + icon(&x->I_Scanning_123x52, "SubGhz/Scanning_123x52", p, f); + icon(&x->I_Auth_62x31, "U2F/Auth_62x31", p, f); + icon(&x->I_Connect_me_62x31, "U2F/Connect_me_62x31", p, f); + icon(&x->I_Connected_62x31, "U2F/Connected_62x31", p, f); + icon(&x->I_Error_62x31, "U2F/Error_62x31", p, f); +} + +void XTREME_ASSETS_LOAD() { + if(xtreme_assets != NULL) return; + + xtreme_assets = malloc(sizeof(XtremeAssets)); + XtremeSettings* xtreme_settings = XTREME_SETTINGS(); + + xtreme_assets->A_Levelup_128x64 = &A_Levelup_128x64; + xtreme_assets->I_BLE_Pairing_128x64 = &I_BLE_Pairing_128x64; + xtreme_assets->I_DolphinCommon_56x48 = &I_DolphinCommon_56x48; + xtreme_assets->I_DolphinMafia_115x62 = &I_DolphinMafia_115x62; + xtreme_assets->I_DolphinNice_96x59 = &I_DolphinNice_96x59; + xtreme_assets->I_DolphinWait_61x59 = &I_DolphinWait_61x59; + xtreme_assets->I_iButtonDolphinVerySuccess_108x52 = &I_iButtonDolphinVerySuccess_108x52; + xtreme_assets->I_DolphinReadingSuccess_59x63 = &I_DolphinReadingSuccess_59x63; + xtreme_assets->I_NFC_dolphin_emulation_47x61 = &I_NFC_dolphin_emulation_47x61; + xtreme_assets->I_passport_bad_46x49 = &I_passport_bad_46x49; + xtreme_assets->I_passport_DB = &I_passport_DB; + xtreme_assets->I_passport_happy_46x49 = &I_passport_happy_46x49; + xtreme_assets->I_passport_okay_46x49 = &I_passport_okay_46x49; + xtreme_assets->I_RFIDDolphinReceive_97x61 = &I_RFIDDolphinReceive_97x61; + xtreme_assets->I_RFIDDolphinSend_97x61 = &I_RFIDDolphinSend_97x61; + xtreme_assets->I_RFIDDolphinSuccess_108x57 = &I_RFIDDolphinSuccess_108x57; + xtreme_assets->I_Cry_dolph_55x52 = &I_Cry_dolph_55x52; + xtreme_assets->I_Scanning_123x52 = &I_Scanning_123x52; + xtreme_assets->I_Auth_62x31 = &I_Auth_62x31; + xtreme_assets->I_Connect_me_62x31 = &I_Connect_me_62x31; + xtreme_assets->I_Connected_62x31 = &I_Connected_62x31; + xtreme_assets->I_Error_62x31 = &I_Error_62x31; + + if(xtreme_settings->asset_pack[0] == '\0') return; + xtreme_assets->is_nsfw = strncmp(xtreme_settings->asset_pack, "NSFW", strlen("NSFW")) == 0; + FileInfo info; + FuriString* path = furi_string_alloc(); + furi_string_printf(path, PACKS_DIR "/%s", xtreme_settings->asset_pack); + Storage* storage = furi_record_open(RECORD_STORAGE); + if(storage_common_stat(storage, furi_string_get_cstr(path), &info) == FSE_OK && + info.flags & FSF_DIRECTORY) { + File* file = storage_file_alloc(storage); + swap(xtreme_assets, path, file); + storage_file_free(file); + } + furi_record_close(RECORD_STORAGE); + furi_string_free(path); +} + +XtremeAssets* XTREME_ASSETS() { + if(xtreme_assets == NULL) { + XTREME_ASSETS_LOAD(); + } + return xtreme_assets; +} diff --git a/applications/settings/xtreme_settings/xtreme_assets.h b/applications/services/xtreme/assets.h similarity index 85% rename from applications/settings/xtreme_settings/xtreme_assets.h rename to applications/services/xtreme/assets.h index df618c47d..b88a6cf1e 100644 --- a/applications/settings/xtreme_settings/xtreme_assets.h +++ b/applications/services/xtreme/assets.h @@ -1,12 +1,14 @@ #pragma once +#include "settings.h" #include -#include "xtreme_settings.h" #include #define PACKS_DIR EXT_PATH("dolphin_custom") typedef struct { + bool is_nsfw; + const Icon* A_Levelup_128x64; const Icon* I_BLE_Pairing_128x64; const Icon* I_DolphinCommon_56x48; const Icon* I_DolphinMafia_115x62; @@ -30,10 +32,6 @@ typedef struct { const Icon* I_Error_62x31; } XtremeAssets; -XtremeAssets* XTREME_ASSETS(); - void XTREME_ASSETS_LOAD(); -void swap_bmx_icon(const Icon** replace, const char* base, const char* name, FuriString* path, File* file); - -void free_bmx_icon(Icon* icon); +XtremeAssets* XTREME_ASSETS(); diff --git a/applications/services/xtreme/on_system_start.c b/applications/services/xtreme/on_system_start.c new file mode 100644 index 000000000..531888f1b --- /dev/null +++ b/applications/services/xtreme/on_system_start.c @@ -0,0 +1,7 @@ +#include "settings.h" +#include "assets.h" + +void xtreme_on_system_start() { + XTREME_SETTINGS_LOAD(); + XTREME_ASSETS_LOAD(); +} diff --git a/applications/settings/xtreme_settings/xtreme_settings.c b/applications/services/xtreme/settings.c similarity index 55% rename from applications/settings/xtreme_settings/xtreme_settings.c rename to applications/services/xtreme/settings.c index 84018bcf0..eea68bd2b 100644 --- a/applications/settings/xtreme_settings/xtreme_settings.c +++ b/applications/services/xtreme/settings.c @@ -1,19 +1,23 @@ -#include "xtreme_settings.h" +#include "settings.h" XtremeSettings* xtreme_settings = NULL; XtremeSettings* XTREME_SETTINGS() { - if (xtreme_settings == NULL) { + if(xtreme_settings == NULL) { XTREME_SETTINGS_LOAD(); } return xtreme_settings; } bool XTREME_SETTINGS_LOAD() { - if (xtreme_settings == NULL) { + if(xtreme_settings == NULL) { xtreme_settings = malloc(sizeof(XtremeSettings)); bool loaded = saved_struct_load( - XTREME_SETTINGS_PATH, xtreme_settings, sizeof(XtremeSettings), XTREME_SETTINGS_MAGIC, XTREME_SETTINGS_VERSION); + XTREME_SETTINGS_PATH, + xtreme_settings, + sizeof(XtremeSettings), + XTREME_SETTINGS_MAGIC, + XTREME_SETTINGS_VERSION); if(!loaded) { memset(xtreme_settings, 0, sizeof(XtremeSettings)); loaded = XTREME_SETTINGS_SAVE(); @@ -24,9 +28,13 @@ bool XTREME_SETTINGS_LOAD() { } bool XTREME_SETTINGS_SAVE() { - if (xtreme_settings == NULL) { + if(xtreme_settings == NULL) { XTREME_SETTINGS_LOAD(); } return saved_struct_save( - XTREME_SETTINGS_PATH, xtreme_settings, sizeof(XtremeSettings), XTREME_SETTINGS_MAGIC, XTREME_SETTINGS_VERSION); + XTREME_SETTINGS_PATH, + xtreme_settings, + sizeof(XtremeSettings), + XTREME_SETTINGS_MAGIC, + XTREME_SETTINGS_VERSION); } diff --git a/applications/settings/xtreme_settings/xtreme_settings.h b/applications/services/xtreme/settings.h similarity index 62% rename from applications/settings/xtreme_settings/xtreme_settings.h rename to applications/services/xtreme/settings.h index 0a19ca643..b4f12b1b8 100644 --- a/applications/settings/xtreme_settings/xtreme_settings.h +++ b/applications/services/xtreme/settings.h @@ -1,6 +1,6 @@ #pragma once -#include "xtreme_settings_filename.h" +#include "settings_filename.h" #include #include @@ -11,17 +11,24 @@ #define MAX_PACK_NAME_LEN 32 -#define XTREME_SETTINGS_VERSION (1) +#define XTREME_SETTINGS_VERSION (2) #define XTREME_SETTINGS_PATH INT_PATH(XTREME_SETTINGS_FILE_NAME) #define XTREME_SETTINGS_MAGIC (0x69) +// Some settings function backwards (logically) in +// order to fit the default value we want +// (values will default to 0 / false) typedef struct { + char asset_pack[MAX_PACK_NAME_LEN]; + uint16_t anim_speed; int32_t cycle_anims; bool unlock_anims; - bool nsfw_mode; - char asset_pack[MAX_PACK_NAME_LEN]; - BatteryStyle battery_style; - uint16_t anim_speed; + BatteryIcon battery_icon; + bool status_icons; + bool bar_borders; + bool bar_background; + bool bad_bt; + bool sort_ignore_dirs; } XtremeSettings; XtremeSettings* XTREME_SETTINGS(); diff --git a/applications/settings/xtreme_settings/xtreme_settings_filename.h b/applications/services/xtreme/settings_filename.h similarity index 100% rename from applications/settings/xtreme_settings/xtreme_settings_filename.h rename to applications/services/xtreme/settings_filename.h diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 42712bc9c..4172214a9 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -20,17 +20,29 @@ typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMess static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; - const char* screen_header = "Product: Flipper Zero\n" - "Model: FZ.1\n"; - const char* screen_text = "FCC ID: 2A2V6-FZ\n" - "IC: 27624-FZ"; + FuriString* screen_header = furi_string_alloc_printf( + "Product: %s\n" + "Model: %s", + furi_hal_version_get_model_name(), + furi_hal_version_get_model_code()); - dialog_message_set_header(message, screen_header, 0, 0, AlignLeft, AlignTop); - dialog_message_set_text(message, screen_text, 0, 26, AlignLeft, AlignTop); + FuriString* screen_text = furi_string_alloc_printf( + "FCC ID: %s\n" + "IC: %s", + furi_hal_version_get_fcc_id(), + furi_hal_version_get_ic_id()); + + dialog_message_set_header( + message, furi_string_get_cstr(screen_header), 0, 0, AlignLeft, AlignTop); + dialog_message_set_text( + message, furi_string_get_cstr(screen_text), 0, 26, AlignLeft, AlignTop); result = dialog_message_show(dialogs, message); dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop); dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); + furi_string_free(screen_header); + furi_string_free(screen_text); + return result; } @@ -222,9 +234,9 @@ static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { snprintf(header, sizeof(header), "Charged!"); } - if (!strcmp(value, "")) { + if(!strcmp(value, "")) { canvas_draw_str_aligned(canvas, x + 92, y + 14, AlignCenter, AlignCenter, header); - } else if (!strcmp(header, "")) { + } else if(!strcmp(header, "")) { canvas_draw_str_aligned(canvas, x + 92, y + 14, AlignCenter, AlignCenter, value); } else { canvas_draw_str_aligned(canvas, x + 92, y + 9, AlignCenter, AlignCenter, header); @@ -298,7 +310,6 @@ const AboutDialogScreen about_screens[] = { const int about_screens_count = sizeof(about_screens) / sizeof(AboutDialogScreen); - int32_t about_settings_app(void* p) { bool battery_info = false; if(p && strlen(p) && !strcmp(p, "batt")) { @@ -324,24 +335,19 @@ int32_t about_settings_app(void* p) { DialogMessageButton screen_result; // draw empty screen to prevent menu flickering - view_dispatcher_add_view( - view_dispatcher, battery_info_index, battery_view); + view_dispatcher_add_view(view_dispatcher, battery_info_index, battery_view); view_dispatcher_add_view( view_dispatcher, empty_screen_index, empty_screen_get_view(empty_screen)); view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); screen_index = -1 + !battery_info; while(screen_index > -2) { - - if (screen_index == -1) { - if (!battery_info) { + if(screen_index == -1) { + if(!battery_info) { break; } with_view_model( - battery_view, - PowerInfo * model, - { power_get_info(power, model); }, - true); + battery_view, PowerInfo * model, { power_get_info(power, model); }, true); view_dispatcher_switch_to_view(view_dispatcher, battery_info_index); furi_semaphore_acquire(semaphore, 2000); } else { @@ -360,7 +366,6 @@ int32_t about_settings_app(void* p) { screen_index = -2; } } - } dialog_message_free(message); diff --git a/applications/settings/application.fam b/applications/settings/application.fam index 0c4a98835..49695b4b3 100644 --- a/applications/settings/application.fam +++ b/applications/settings/application.fam @@ -5,7 +5,7 @@ App( provides=[ "passport", "system_settings", - "xtreme_settings", + "xtreme_app", "about", ], ) diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c index 964736b66..31921b9f3 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_confirm.c @@ -1,5 +1,5 @@ #include "../bt_settings_app.h" -#include "furi_hal_bt.h" +#include void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, void* context) { furi_assert(context); diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c index 4112d94d9..59071959c 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c @@ -1,6 +1,7 @@ #include "../bt_settings_app.h" #include "furi_hal_bt.h" -#include "../../xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" +#include void bt_settings_app_scene_forget_dev_success_popup_callback(void* context) { BtSettingsApp* app = context; diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c index bcbc902b2..5db98e9de 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_start.c @@ -1,5 +1,5 @@ #include "../bt_settings_app.h" -#include "furi_hal_bt.h" +#include enum BtSetting { BtSettingOff, diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c index cdafbb828..cad5f43f4 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_disable.c @@ -6,7 +6,7 @@ #include "../desktop_settings_app.h" #include #include "desktop_settings_scene.h" -#include "../../xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #define SCENE_EVENT_EXIT (0U) diff --git a/applications/settings/dolphin_passport/passport.c b/applications/settings/dolphin_passport/passport.c index 3bea705ac..d6474b4cf 100644 --- a/applications/settings/dolphin_passport/passport.c +++ b/applications/settings/dolphin_passport/passport.c @@ -6,7 +6,7 @@ #include #include #include "dolphin/dolphin.h" -#include "../xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" #include "math.h" typedef struct { @@ -40,7 +40,7 @@ static void render_callback(Canvas* canvas, void* _ctx) { const char* mood_str = NULL; const Icon* portrait = NULL; - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { if(stats->butthurt <= 4) { portrait = xtreme_assets->I_passport_happy_46x49; mood_str = "Status: Wet"; @@ -67,7 +67,7 @@ static void render_callback(Canvas* canvas, void* _ctx) { uint32_t xp_need = dolphin_state_xp_to_levelup(stats->icounter); uint32_t xp_above_last_levelup = dolphin_state_xp_above_last_levelup(stats->icounter); uint32_t xp_levelup = 0; - if (ctx->progress_total) { + if(ctx->progress_total) { xp_levelup = xp_need + stats->icounter; } else { xp_levelup = xp_need + xp_above_last_levelup; diff --git a/applications/settings/power_settings_app/application.fam b/applications/settings/power_settings_app/application.fam index a5b1966b2..6f3589e1a 100644 --- a/applications/settings/power_settings_app/application.fam +++ b/applications/settings/power_settings_app/application.fam @@ -6,6 +6,7 @@ App( requires=[ "gui", "power", + "locale", ], flags=["InsomniaSafe"], stack_size=1 * 1024, diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c index ecab8c333..afcc6f950 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c @@ -1,5 +1,5 @@ #include "../power_settings_app.h" -#include "../../xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" void power_settings_scene_power_off_dialog_callback(DialogExResult result, void* context) { furi_assert(context); @@ -12,7 +12,7 @@ void power_settings_scene_power_off_on_enter(void* context) { DialogEx* dialog = app->dialog; dialog_ex_set_header(dialog, "Turn Off Device?", 64, 2, AlignCenter, AlignTop); - if(XTREME_SETTINGS()->nsfw_mode) { + if(XTREME_ASSETS()->is_nsfw) { dialog_ex_set_text( dialog, " I will be\nwaiting for\n you master", 78, 16, AlignLeft, AlignTop); } else { diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index 5353a2e2a..d29769d21 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -2,6 +2,7 @@ #include #include #include +#include #define LOW_CHARGE_THRESHOLD 10 #define HIGH_DRAIN_CURRENT_THRESHOLD 100 @@ -101,7 +102,15 @@ static void battery_info_draw_callback(Canvas* canvas, void* context) { char health[10]; snprintf(batt_level, sizeof(batt_level), "%lu%%", (uint32_t)model->charge); - snprintf(temperature, sizeof(temperature), "%lu C", (uint32_t)model->gauge_temperature); + if(locale_get_measurement_unit() == LocaleMeasurementUnitsMetric) { + snprintf(temperature, sizeof(temperature), "%lu C", (uint32_t)model->gauge_temperature); + } else { + snprintf( + temperature, + sizeof(temperature), + "%lu F", + (uint32_t)locale_celsius_to_fahrenheit(model->gauge_temperature)); + } snprintf( voltage, sizeof(voltage), diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c index b2e77e22d..4901e960e 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c @@ -1,4 +1,5 @@ #include "../storage_settings.h" +#include static void storage_settings_scene_sd_info_dialog_callback(DialogExResult result, void* context) { StorageSettings* app = context; @@ -11,7 +12,10 @@ void storage_settings_scene_sd_info_on_enter(void* context) { DialogEx* dialog_ex = app->dialog_ex; SDInfo sd_info; + SD_CID sd_cid; FS_Error sd_status = storage_sd_info(app->fs_api, &sd_info); + BSP_SD_GetCIDRegister(&sd_cid); + scene_manager_set_scene_state(app->scene_manager, StorageSettingsSDInfo, sd_status); dialog_ex_set_context(dialog_ex, app); @@ -53,18 +57,25 @@ void storage_settings_scene_sd_info_on_enter(void* context) { furi_string_printf( app->text_string, - "Label: %s\nType: %s\n%.2f %s total\n%.2f %s free\n%.2f%% free", - + "Label: %s\nType: %s\n%.2f %s total\n%.2f %s free %.2f%% free\n" + "%02X%2.2s %5.5s %i.%i\nSN:%04lX %02i/%i", sd_info.label, sd_api_get_fs_type_text(sd_info.fs_type), sd_total_val, sd_total_unit, sd_free_val, sd_free_unit, - (double)(((int)sd_info.kb_free * 100.0) / (int)sd_info.kb_total)); - + (double)(((int)sd_info.kb_free * 100.0) / (int)sd_info.kb_total), + sd_cid.ManufacturerID, + sd_cid.OEM_AppliID, + sd_cid.ProdName, + sd_cid.ProdRev >> 4, + sd_cid.ProdRev & 0xf, + sd_cid.ProdSN, + sd_cid.ManufactMonth, + sd_cid.ManufactYear + 2000); dialog_ex_set_text( - dialog_ex, furi_string_get_cstr(app->text_string), 4, 4, AlignLeft, AlignTop); + dialog_ex, furi_string_get_cstr(app->text_string), 4, 1, AlignLeft, AlignTop); } view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx); @@ -101,4 +112,4 @@ void storage_settings_scene_sd_info_on_exit(void* context) { dialog_ex_reset(dialog_ex); furi_string_reset(app->text_string); -} +} \ No newline at end of file diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c index 455cbaa78..13f53acd1 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_unmounted.c @@ -1,5 +1,5 @@ #include "../storage_settings.h" -#include "../../xtreme_settings/xtreme_assets.h" +#include "xtreme/assets.h" static void storage_settings_scene_unmounted_dialog_callback(DialogExResult result, void* context) { diff --git a/applications/settings/xtreme_settings/application.fam b/applications/settings/xtreme_app/application.fam similarity index 66% rename from applications/settings/xtreme_settings/application.fam rename to applications/settings/xtreme_app/application.fam index 54dd95af3..e1b7fc964 100644 --- a/applications/settings/xtreme_settings/application.fam +++ b/applications/settings/xtreme_app/application.fam @@ -1,11 +1,12 @@ App( - appid="xtreme_settings", + appid="xtreme_app", name="Xtreme FW", apptype=FlipperAppType.SETTINGS, - entry_point="xtreme_settings_app", + entry_point="xtreme_app", stack_size=2 * 1024, requires=[ "gui", + "xtreme", ], order=90, ) diff --git a/applications/settings/xtreme_app/scenes/xtreme_app_scene.c b/applications/settings/xtreme_app/scenes/xtreme_app_scene.c new file mode 100644 index 000000000..5448bb85a --- /dev/null +++ b/applications/settings/xtreme_app/scenes/xtreme_app_scene.c @@ -0,0 +1,30 @@ +#include "xtreme_app_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const xtreme_app_on_enter_handlers[])(void*) = { +#include "xtreme_app_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const xtreme_app_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "xtreme_app_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const xtreme_app_on_exit_handlers[])(void* context) = { +#include "xtreme_app_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers xtreme_app_scene_handlers = { + .on_enter_handlers = xtreme_app_on_enter_handlers, + .on_event_handlers = xtreme_app_on_event_handlers, + .on_exit_handlers = xtreme_app_on_exit_handlers, + .scene_num = XtremeAppSceneNum, +}; diff --git a/applications/settings/xtreme_app/scenes/xtreme_app_scene.h b/applications/settings/xtreme_app/scenes/xtreme_app_scene.h new file mode 100644 index 000000000..d7f19abac --- /dev/null +++ b/applications/settings/xtreme_app/scenes/xtreme_app_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) XtremeAppScene##id, +typedef enum { +#include "xtreme_app_scene_config.h" + XtremeAppSceneNum, +} XtremeAppScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers xtreme_app_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "xtreme_app_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "xtreme_app_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "xtreme_app_scene_config.h" +#undef ADD_SCENE diff --git a/applications/settings/xtreme_app/scenes/xtreme_app_scene_config.h b/applications/settings/xtreme_app/scenes/xtreme_app_scene_config.h new file mode 100644 index 000000000..9eed63575 --- /dev/null +++ b/applications/settings/xtreme_app/scenes/xtreme_app_scene_config.h @@ -0,0 +1 @@ +ADD_SCENE(xtreme_app, main, Main) diff --git a/applications/settings/xtreme_app/scenes/xtreme_app_scene_main.c b/applications/settings/xtreme_app/scenes/xtreme_app_scene_main.c new file mode 100644 index 000000000..03602bb58 --- /dev/null +++ b/applications/settings/xtreme_app/scenes/xtreme_app_scene_main.c @@ -0,0 +1,319 @@ +#include "../xtreme_app.h" +#include +#include +#include + +static void xtreme_app_scene_main_asset_pack_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text( + item, index == 0 ? "SFW" : *asset_packs_get(app->asset_packs, index - 1)); + strlcpy( + XTREME_SETTINGS()->asset_pack, + index == 0 ? "" : *asset_packs_get(app->asset_packs, index - 1), + MAX_PACK_NAME_LEN); + app->settings_changed = true; + app->assets_changed = true; +} + +const char* const anim_speed_names[] = + {"25%", "50%", "75%", "100%", "125%", "150%", "175%", "200%", "225%", "250%", "275%", "300%"}; +const int32_t anim_speed_values[COUNT_OF(anim_speed_names)] = + {25, 50, 75, 0, 125, 150, 175, 200, 225, 250, 275, 300}; +static void xtreme_app_scene_main_anim_speed_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, anim_speed_names[index]); + XTREME_SETTINGS()->anim_speed = anim_speed_values[index]; + app->settings_changed = true; +} + +const char* const cycle_anims_names[] = { + "OFF", + "Meta.txt", + "30 S", + "1 M", + "5 M", + "10 M", + "15 M", + "30 M", + "1 H", + "2 H", + "6 H", + "12 H", + "24 H"}; +const int32_t cycle_anims_values[COUNT_OF(cycle_anims_names)] = + {-1, 0, 30, 60, 300, 600, 900, 1800, 3600, 7200, 21600, 43200, 86400}; +static void xtreme_app_scene_main_cycle_anims_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, cycle_anims_names[index]); + XTREME_SETTINGS()->cycle_anims = cycle_anims_values[index]; + app->settings_changed = true; +} + +static void xtreme_app_scene_main_unlock_anims_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + bool value = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, value ? "ON" : "OFF"); + XTREME_SETTINGS()->unlock_anims = value; + app->settings_changed = true; +} + +const char* const battery_icon_names[] = + {"OFF", "Bar", "%", "Inv. %", "Retro 3", "Retro 5", "Bar %"}; +static void xtreme_app_scene_main_battery_icon_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, battery_icon_names[index]); + XTREME_SETTINGS()->battery_icon = (index + 1) % BatteryIconCount; + app->settings_changed = true; +} + +static void xtreme_app_scene_main_status_icons_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + bool value = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, value ? "ON" : "OFF"); + XTREME_SETTINGS()->status_icons = value; + app->settings_changed = true; +} + +static void xtreme_app_scene_main_bar_borders_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + bool value = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, value ? "ON" : "OFF"); + XTREME_SETTINGS()->bar_borders = value; + app->settings_changed = true; +} + +static void xtreme_app_scene_main_bar_background_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + bool value = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, value ? "ON" : "OFF"); + XTREME_SETTINGS()->bar_background = value; + app->settings_changed = true; +} + +static void xtreme_app_scene_main_bad_bk_mode_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + bool value = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, value ? "BT" : "USB"); + XTREME_SETTINGS()->bad_bt = value; + app->settings_changed = true; +} + +static void xtreme_app_scene_main_subghz_extend_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + app->subghz_extend = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, app->subghz_extend ? "ON" : "OFF"); + app->subghz_changed = true; +} + +static void xtreme_app_scene_main_subghz_bypass_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + app->subghz_bypass = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, app->subghz_bypass ? "ON" : "OFF"); + app->subghz_changed = true; +} + +static void xtreme_app_scene_main_sort_folders_before_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + bool value = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, value ? "ON" : "OFF"); + XTREME_SETTINGS()->sort_ignore_dirs = !value; + app->settings_changed = true; +} + +static void xtreme_app_scene_main_xp_level_changed(VariableItem* item) { + XtremeApp* app = variable_item_get_context(item); + app->dolphin_level = variable_item_get_current_value_index(item) + 1; + char level_str[4]; + snprintf(level_str, 4, "%i", app->dolphin_level); + variable_item_set_current_value_text(item, level_str); + app->level_changed = true; +} + +void xtreme_app_scene_main_on_enter(void* context) { + XtremeApp* app = context; + XtremeSettings* xtreme_settings = XTREME_SETTINGS(); + VariableItemList* var_item_list = app->var_item_list; + VariableItem* item; + uint8_t value_index; + + Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); + DolphinStats stats = dolphin_stats(dolphin); + furi_record_close(RECORD_DOLPHIN); + app->dolphin_level = stats.level; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* subghz_range = flipper_format_file_alloc(storage); + app->subghz_extend = false; + app->subghz_bypass = false; + if(flipper_format_file_open_existing(subghz_range, "/ext/subghz/assets/extend_range.txt")) { + flipper_format_read_bool( + subghz_range, "use_ext_range_at_own_risk", &app->subghz_extend, 1); + flipper_format_read_bool(subghz_range, "ignore_default_tx_region", &app->subghz_bypass, 1); + } + flipper_format_free(subghz_range); + + uint current_pack = 0; + asset_packs_init(app->asset_packs); + File* folder = storage_file_alloc(storage); + FileInfo info; + char* name = malloc(MAX_PACK_NAME_LEN); + if(storage_dir_open(folder, PACKS_DIR)) { + while(storage_dir_read(folder, &info, name, MAX_PACK_NAME_LEN)) { + if(info.flags & FSF_DIRECTORY) { + char* copy = malloc(MAX_PACK_NAME_LEN); + strlcpy(copy, name, MAX_PACK_NAME_LEN); + uint idx = 0; + if(strcmp(copy, "NSFW") != 0) { + for(; idx < asset_packs_size(app->asset_packs); idx++) { + char* comp = *asset_packs_get(app->asset_packs, idx); + if(strcasecmp(copy, comp) < 0 && strcmp(comp, "NSFW") != 0) { + break; + } + } + } + asset_packs_push_at(app->asset_packs, idx, copy); + if(current_pack != 0) { + if(idx < current_pack) current_pack++; + } else { + if(strcmp(copy, xtreme_settings->asset_pack) == 0) current_pack = idx + 1; + } + } + } + } + free(name); + storage_file_free(folder); + furi_record_close(RECORD_STORAGE); + + item = variable_item_list_add( + var_item_list, + "Asset Pack", + asset_packs_size(app->asset_packs) + 1, + xtreme_app_scene_main_asset_pack_changed, + app); + variable_item_set_current_value_index(item, current_pack); + variable_item_set_current_value_text( + item, current_pack == 0 ? "SFW" : *asset_packs_get(app->asset_packs, current_pack - 1)); + + item = variable_item_list_add( + var_item_list, + "Anim Speed", + COUNT_OF(anim_speed_names), + xtreme_app_scene_main_anim_speed_changed, + app); + value_index = value_index_int32( + xtreme_settings->anim_speed, anim_speed_values, COUNT_OF(anim_speed_names)); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, anim_speed_names[value_index]); + + item = variable_item_list_add( + var_item_list, + "Cycle Anims", + COUNT_OF(cycle_anims_names), + xtreme_app_scene_main_cycle_anims_changed, + app); + value_index = value_index_int32( + xtreme_settings->cycle_anims, cycle_anims_values, COUNT_OF(cycle_anims_names)); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, cycle_anims_names[value_index]); + + item = variable_item_list_add( + var_item_list, "Unlock Anims", 2, xtreme_app_scene_main_unlock_anims_changed, app); + variable_item_set_current_value_index(item, xtreme_settings->unlock_anims); + variable_item_set_current_value_text(item, xtreme_settings->unlock_anims ? "ON" : "OFF"); + + + variable_item_list_add(var_item_list, " = Status Bar =", 0, NULL, app); + + item = variable_item_list_add( + var_item_list, + "Battery Icon", + BatteryIconCount, + xtreme_app_scene_main_battery_icon_changed, + app); + value_index = (xtreme_settings->battery_icon + BatteryIconCount - 1) % BatteryIconCount; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, battery_icon_names[value_index]); + + item = variable_item_list_add( + var_item_list, "Status Icons", 2, xtreme_app_scene_main_status_icons_changed, app); + variable_item_set_current_value_index(item, xtreme_settings->status_icons); + variable_item_set_current_value_text(item, xtreme_settings->status_icons ? "ON" : "OFF"); + + item = variable_item_list_add( + var_item_list, "Bar Borders", 2, xtreme_app_scene_main_bar_borders_changed, app); + variable_item_set_current_value_index(item, xtreme_settings->bar_borders); + variable_item_set_current_value_text(item, xtreme_settings->bar_borders ? "ON" : "OFF"); + + item = variable_item_list_add( + var_item_list, "Bar Background", 2, xtreme_app_scene_main_bar_background_changed, app); + variable_item_set_current_value_index(item, xtreme_settings->bar_background); + variable_item_set_current_value_text(item, xtreme_settings->bar_background ? "ON" : "OFF"); + + + variable_item_list_add(var_item_list, " = Protocols =", 0, NULL, app); + + item = variable_item_list_add( + var_item_list, "Bad KB Mode", 2, xtreme_app_scene_main_bad_bk_mode_changed, app); + variable_item_set_current_value_index(item, xtreme_settings->bad_bt); + variable_item_set_current_value_text(item, xtreme_settings->bad_bt ? "BT" : "USB"); + + item = variable_item_list_add( + var_item_list, "SubGHz Extend", 2, xtreme_app_scene_main_subghz_extend_changed, app); + variable_item_set_current_value_index(item, app->subghz_extend); + variable_item_set_current_value_text(item, app->subghz_extend ? "ON" : "OFF"); + + item = variable_item_list_add( + var_item_list, "SubGHz Bypass", 2, xtreme_app_scene_main_subghz_bypass_changed, app); + variable_item_set_current_value_index(item, app->subghz_bypass); + variable_item_set_current_value_text(item, app->subghz_bypass ? "ON" : "OFF"); + + + variable_item_list_add(var_item_list, " = Misc =", 0, NULL, app); + + item = variable_item_list_add( + var_item_list, + "Sort Dirs First", + 2, + xtreme_app_scene_main_sort_folders_before_changed, + app); + variable_item_set_current_value_index(item, !xtreme_settings->sort_ignore_dirs); + variable_item_set_current_value_text(item, !xtreme_settings->sort_ignore_dirs ? "ON" : "OFF"); + + char level_str[4]; + snprintf(level_str, 4, "%i", app->dolphin_level); + item = variable_item_list_add( + var_item_list, + "XP Level", + DOLPHIN_LEVEL_COUNT + 1, + xtreme_app_scene_main_xp_level_changed, + app); + variable_item_set_current_value_index(item, app->dolphin_level - 1); + variable_item_set_current_value_text(item, level_str); + + FuriString* version_tag = furi_string_alloc_printf( + "%s %s", version_get_gitbranchnum(NULL), version_get_builddate(NULL)); + variable_item_list_add(var_item_list, furi_string_get_cstr(version_tag), 0, NULL, app); + + view_dispatcher_switch_to_view(app->view_dispatcher, XtremeAppViewVarItemList); +} + +bool xtreme_app_scene_main_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void xtreme_app_scene_main_on_exit(void* context) { + XtremeApp* app = context; + asset_packs_it_t it; + for(asset_packs_it(it, app->asset_packs); !asset_packs_end_p(it); asset_packs_next(it)) { + free(*asset_packs_cref(it)); + } + asset_packs_clear(app->asset_packs); + variable_item_list_reset(app->var_item_list); +} diff --git a/applications/settings/xtreme_settings/xtreme_settings_app.c b/applications/settings/xtreme_app/xtreme_app.c similarity index 59% rename from applications/settings/xtreme_settings/xtreme_settings_app.c rename to applications/settings/xtreme_app/xtreme_app.c index 780e76730..c6d67b915 100644 --- a/applications/settings/xtreme_settings/xtreme_settings_app.c +++ b/applications/settings/xtreme_app/xtreme_app.c @@ -1,24 +1,24 @@ -#include "xtreme_settings_app.h" +#include "xtreme_app.h" -static bool xtreme_settings_custom_event_callback(void* context, uint32_t event) { +static bool xtreme_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); - XtremeSettingsApp* app = context; + XtremeApp* app = context; return scene_manager_handle_custom_event(app->scene_manager, event); } -void xtreme_settings_reboot(void* context) { +void xtreme_app_reboot(void* context) { UNUSED(context); power_reboot(PowerBootModeNormal); } -static bool xtreme_settings_back_event_callback(void* context) { +static bool xtreme_app_back_event_callback(void* context) { furi_assert(context); - XtremeSettingsApp* app = context; + XtremeApp* app = context; - if (app->level_changed) { + if(app->level_changed) { Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); DolphinStats stats = dolphin_stats(dolphin); - if (app->dolphin_level != stats.level) { + if(app->dolphin_level != stats.level) { int xp = app->dolphin_level > 1 ? dolphin_get_levels()[app->dolphin_level - 2] : 0; dolphin->state->data.icounter = xp + 1; dolphin->state->dirty = true; @@ -27,27 +27,29 @@ static bool xtreme_settings_back_event_callback(void* context) { furi_record_close(RECORD_DOLPHIN); } - if (app->subghz_changed) { + if(app->subghz_changed) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* subghz_range = flipper_format_file_alloc(storage); if(flipper_format_file_open_existing(subghz_range, "/ext/subghz/assets/extend_range.txt")) { - flipper_format_insert_or_update_bool(subghz_range, "use_ext_range_at_own_risk", &app->subghz_extend, 1); - flipper_format_insert_or_update_bool(subghz_range, "ignore_default_tx_region", &app->subghz_bypass, 1); + flipper_format_insert_or_update_bool( + subghz_range, "use_ext_range_at_own_risk", &app->subghz_extend, 1); + flipper_format_insert_or_update_bool( + subghz_range, "ignore_default_tx_region", &app->subghz_bypass, 1); } flipper_format_free(subghz_range); furi_record_close(RECORD_STORAGE); } - if (app->settings_changed) { + if(app->settings_changed) { XTREME_SETTINGS_SAVE(); - if (app->assets_changed) { + if(app->assets_changed) { popup_set_header(app->popup, "Rebooting...", 64, 26, AlignCenter, AlignCenter); popup_set_text(app->popup, "Swapping assets...", 64, 40, AlignCenter, AlignCenter); - popup_set_callback(app->popup, xtreme_settings_reboot); + popup_set_callback(app->popup, xtreme_app_reboot); popup_set_context(app->popup, app); popup_set_timeout(app->popup, 1000); popup_enable_timeout(app->popup); - view_dispatcher_switch_to_view(app->view_dispatcher, XtremeSettingsAppViewPopup); + view_dispatcher_switch_to_view(app->view_dispatcher, XtremeAppViewPopup); return true; } } @@ -55,20 +57,20 @@ static bool xtreme_settings_back_event_callback(void* context) { return scene_manager_handle_back_event(app->scene_manager); } -XtremeSettingsApp* xtreme_settings_app_alloc() { - XtremeSettingsApp* app = malloc(sizeof(XtremeSettingsApp)); +XtremeApp* xtreme_app_alloc() { + XtremeApp* app = malloc(sizeof(XtremeApp)); app->gui = furi_record_open(RECORD_GUI); // View Dispatcher and Scene Manager app->view_dispatcher = view_dispatcher_alloc(); - app->scene_manager = scene_manager_alloc(&xtreme_settings_scene_handlers, app); + app->scene_manager = scene_manager_alloc(&xtreme_app_scene_handlers, app); view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_custom_event_callback( - app->view_dispatcher, xtreme_settings_custom_event_callback); + app->view_dispatcher, xtreme_app_custom_event_callback); view_dispatcher_set_navigation_event_callback( - app->view_dispatcher, xtreme_settings_back_event_callback); + app->view_dispatcher, xtreme_app_back_event_callback); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); @@ -76,27 +78,22 @@ XtremeSettingsApp* xtreme_settings_app_alloc() { app->var_item_list = variable_item_list_alloc(); view_dispatcher_add_view( app->view_dispatcher, - XtremeSettingsAppViewVarItemList, + XtremeAppViewVarItemList, variable_item_list_get_view(app->var_item_list)); app->popup = popup_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - XtremeSettingsAppViewPopup, - popup_get_view(app->popup)); + view_dispatcher_add_view(app->view_dispatcher, XtremeAppViewPopup, popup_get_view(app->popup)); - // Set first scene - scene_manager_next_scene(app->scene_manager, XtremeSettingsAppSceneStart); return app; } -void xtreme_settings_app_free(XtremeSettingsApp* app) { +void xtreme_app_free(XtremeApp* app) { furi_assert(app); // Gui modules - view_dispatcher_remove_view(app->view_dispatcher, XtremeSettingsAppViewVarItemList); + view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewVarItemList); variable_item_list_free(app->var_item_list); - view_dispatcher_remove_view(app->view_dispatcher, XtremeSettingsAppViewPopup); + view_dispatcher_remove_view(app->view_dispatcher, XtremeAppViewPopup); popup_free(app->popup); // View Dispatcher and Scene Manager @@ -108,10 +105,11 @@ void xtreme_settings_app_free(XtremeSettingsApp* app) { free(app); } -extern int32_t xtreme_settings_app(void* p) { +extern int32_t xtreme_app(void* p) { UNUSED(p); - XtremeSettingsApp* app = xtreme_settings_app_alloc(); + XtremeApp* app = xtreme_app_alloc(); + scene_manager_next_scene(app->scene_manager, XtremeAppSceneMain); view_dispatcher_run(app->view_dispatcher); - xtreme_settings_app_free(app); + xtreme_app_free(app); return 0; } diff --git a/applications/settings/xtreme_settings/xtreme_settings_app.h b/applications/settings/xtreme_app/xtreme_app.h similarity index 79% rename from applications/settings/xtreme_settings/xtreme_settings_app.h rename to applications/settings/xtreme_app/xtreme_app.h index 7265da078..23adbf5ac 100644 --- a/applications/settings/xtreme_settings/xtreme_settings_app.h +++ b/applications/settings/xtreme_app/xtreme_app.h @@ -8,14 +8,14 @@ #include #include #include -#include "xtreme_settings.h" -#include "xtreme_assets.h" -#include "scenes/xtreme_settings_scene.h" +#include "scenes/xtreme_app_scene.h" #include "dolphin/helpers/dolphin_state.h" #include "dolphin/dolphin.h" #include "dolphin/dolphin_i.h" #include #include +#include "xtreme/settings.h" +#include "xtreme/assets.h" ARRAY_DEF(asset_packs, char*) @@ -33,9 +33,9 @@ typedef struct { bool subghz_changed; bool level_changed; asset_packs_t asset_packs; -} XtremeSettingsApp; +} XtremeApp; typedef enum { - XtremeSettingsAppViewVarItemList, - XtremeSettingsAppViewPopup, -} XtremeSettingsAppView; + XtremeAppViewVarItemList, + XtremeAppViewPopup, +} XtremeAppView; diff --git a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene.c b/applications/settings/xtreme_settings/scenes/xtreme_settings_scene.c deleted file mode 100644 index 3d97ed979..000000000 --- a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "xtreme_settings_scene.h" - -// Generate scene on_enter handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, -void (*const xtreme_settings_on_enter_handlers[])(void*) = { -#include "xtreme_settings_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_event handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, -bool (*const xtreme_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = { -#include "xtreme_settings_scene_config.h" -}; -#undef ADD_SCENE - -// Generate scene on_exit handlers array -#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, -void (*const xtreme_settings_on_exit_handlers[])(void* context) = { -#include "xtreme_settings_scene_config.h" -}; -#undef ADD_SCENE - -// Initialize scene handlers configuration structure -const SceneManagerHandlers xtreme_settings_scene_handlers = { - .on_enter_handlers = xtreme_settings_on_enter_handlers, - .on_event_handlers = xtreme_settings_on_event_handlers, - .on_exit_handlers = xtreme_settings_on_exit_handlers, - .scene_num = XtremeSettingsAppSceneNum, -}; diff --git a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_config.h b/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_config.h deleted file mode 100644 index eddd4f82f..000000000 --- a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_config.h +++ /dev/null @@ -1 +0,0 @@ -ADD_SCENE(xtreme_settings, start, Start) diff --git a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_start.c b/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_start.c deleted file mode 100644 index 90bdde83f..000000000 --- a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_start.c +++ /dev/null @@ -1,256 +0,0 @@ -#include "../xtreme_settings_app.h" -#include -#include -#include - -static void xtreme_settings_scene_start_base_graphics_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - bool value = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, value ? "NSFW" : "SFW"); - XTREME_SETTINGS()->nsfw_mode = value; - app->settings_changed = true; - app->assets_changed = true; -} - -static void xtreme_settings_scene_start_asset_pack_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, index == 0 ? "OFF" : *asset_packs_get(app->asset_packs, index - 1)); - strlcpy(XTREME_SETTINGS()->asset_pack, index == 0 ? "" : *asset_packs_get(app->asset_packs, index - 1), MAX_PACK_NAME_LEN); - app->settings_changed = true; - app->assets_changed = true; -} - -const char* const anim_speed_names[] = - {"25%", "50%", "75%", "100%", "125%", "150%", "175%", "200%", "225%", "250%", "275%", "300%"}; -const int32_t anim_speed_values[COUNT_OF(anim_speed_names)] = - {25, 50, 75, 0, 125, 150, 175, 200, 225, 250, 275, 300}; -static void xtreme_settings_scene_start_anim_speed_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, anim_speed_names[index]); - XTREME_SETTINGS()->anim_speed = anim_speed_values[index]; - app->settings_changed = true; -} - -const char* const cycle_anims_names[] = - {"OFF", "Meta.txt", "30 S", "1 M", "5 M", "10 M", "15 M", "30 M", "1 H", "2 H", "6 H", "12 H", "24 H"}; -const int32_t cycle_anims_values[COUNT_OF(cycle_anims_names)] = - {-1, 0, 30, 60, 300, 600, 900, 1800, 3600, 7200, 21600, 43200, 86400}; -static void xtreme_settings_scene_start_cycle_anims_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, cycle_anims_names[index]); - XTREME_SETTINGS()->cycle_anims = cycle_anims_values[index]; - app->settings_changed = true; -} - -static void xtreme_settings_scene_start_unlock_anims_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - bool value = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, value ? "ON" : "OFF"); - XTREME_SETTINGS()->unlock_anims = value; - app->settings_changed = true; -} - -const char* const battery_style_names[] = - {"OFF", "Bar", "%", "Inv. %", "Retro 3", "Retro 5", "Bar %"}; -const int32_t battery_style_values[COUNT_OF(battery_style_names)] = { - BatteryStyleOff, - BatteryStyleBar, - BatteryStylePercent, - BatteryStyleInvertedPercent, - BatteryStyleRetro3, - BatteryStyleRetro5, - BatteryStyleBarPercent -}; -static void xtreme_settings_scene_start_battery_style_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, battery_style_names[index]); - XTREME_SETTINGS()->battery_style = battery_style_values[index]; - app->settings_changed = true; -} - -static void xtreme_settings_scene_start_xp_level_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - app->dolphin_level = variable_item_get_current_value_index(item) + 1; - char level_str[4]; - snprintf(level_str, 4, "%i", app->dolphin_level); - variable_item_set_current_value_text(item, level_str); - app->level_changed = true; -} - -static void xtreme_settings_scene_start_subghz_extend_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - app->subghz_extend = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, app->subghz_extend ? "ON" : "OFF"); - app->subghz_changed = true; -} - -static void xtreme_settings_scene_start_subghz_bypass_changed(VariableItem* item) { - XtremeSettingsApp* app = variable_item_get_context(item); - app->subghz_bypass = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, app->subghz_bypass ? "ON" : "OFF"); - app->subghz_changed = true; -} - -void xtreme_settings_scene_start_on_enter(void* context) { - XtremeSettingsApp* app = context; - XtremeSettings* xtreme_settings = XTREME_SETTINGS(); - VariableItemList* var_item_list = app->var_item_list; - VariableItem* item; - uint8_t value_index; - - Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); - DolphinStats stats = dolphin_stats(dolphin); - furi_record_close(RECORD_DOLPHIN); - app->dolphin_level = stats.level; - - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* subghz_range = flipper_format_file_alloc(storage); - app->subghz_extend = false; - app->subghz_bypass = false; - if(flipper_format_file_open_existing(subghz_range, "/ext/subghz/assets/extend_range.txt")) { - flipper_format_read_bool(subghz_range, "use_ext_range_at_own_risk", &app->subghz_extend, 1); - flipper_format_read_bool(subghz_range, "ignore_default_tx_region", &app->subghz_bypass, 1); - } - flipper_format_free(subghz_range); - - uint current_pack = 0; - asset_packs_init(app->asset_packs); - File* folder = storage_file_alloc(storage); - FileInfo info; - char* name = malloc(MAX_PACK_NAME_LEN); - do { - if (!storage_dir_open(folder, PACKS_DIR)) break; - while(true) { - if (!storage_dir_read(folder, &info, name, MAX_PACK_NAME_LEN)) break; - if(info.flags & FSF_DIRECTORY) { - char* copy = malloc(MAX_PACK_NAME_LEN); - strlcpy(copy, name, MAX_PACK_NAME_LEN); - asset_packs_push_back(app->asset_packs, copy); - if (strcmp(name, xtreme_settings->asset_pack) == 0) current_pack = asset_packs_size(app->asset_packs); - } - } - } while(false); - free(name); - storage_file_free(folder); - furi_record_close(RECORD_STORAGE); - - item = variable_item_list_add( - var_item_list, - "Base Graphics", - 2, - xtreme_settings_scene_start_base_graphics_changed, - app); - variable_item_set_current_value_index(item, xtreme_settings->nsfw_mode); - variable_item_set_current_value_text(item, xtreme_settings->nsfw_mode ? "NSFW" : "SFW"); - - item = variable_item_list_add( - var_item_list, - "Asset Pack", - asset_packs_size(app->asset_packs) + 1, - xtreme_settings_scene_start_asset_pack_changed, - app); - variable_item_set_current_value_index(item, current_pack); - variable_item_set_current_value_text(item, current_pack == 0 ? "OFF" : *asset_packs_get(app->asset_packs, current_pack - 1)); - - item = variable_item_list_add( - var_item_list, - "Anim Speed", - COUNT_OF(anim_speed_names), - xtreme_settings_scene_start_anim_speed_changed, - app); - value_index = value_index_int32( - xtreme_settings->anim_speed, anim_speed_values, COUNT_OF(anim_speed_names)); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, anim_speed_names[value_index]); - - item = variable_item_list_add( - var_item_list, - "Cycle Anims", - COUNT_OF(cycle_anims_names), - xtreme_settings_scene_start_cycle_anims_changed, - app); - value_index = value_index_int32( - xtreme_settings->cycle_anims, cycle_anims_values, COUNT_OF(cycle_anims_names)); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, cycle_anims_names[value_index]); - - item = variable_item_list_add( - var_item_list, - "Unlock Anims", - 2, - xtreme_settings_scene_start_unlock_anims_changed, - app); - variable_item_set_current_value_index(item, xtreme_settings->unlock_anims); - variable_item_set_current_value_text(item, xtreme_settings->unlock_anims ? "ON" : "OFF"); - - item = variable_item_list_add( - var_item_list, - "Battery Style", - COUNT_OF(battery_style_names), - xtreme_settings_scene_start_battery_style_changed, - app); - value_index = value_index_int32( - xtreme_settings->battery_style, battery_style_values, COUNT_OF(battery_style_names)); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, battery_style_names[value_index]); - - char level_str[4]; - snprintf(level_str, 4, "%i", app->dolphin_level); - item = variable_item_list_add( - var_item_list, - "XP Level", - DOLPHIN_LEVEL_COUNT + 1, - xtreme_settings_scene_start_xp_level_changed, - app); - variable_item_set_current_value_index(item, app->dolphin_level - 1); - variable_item_set_current_value_text(item, level_str); - - item = variable_item_list_add( - var_item_list, - "SubGHz Extend", - 2, - xtreme_settings_scene_start_subghz_extend_changed, - app); - variable_item_set_current_value_index(item, app->subghz_extend); - variable_item_set_current_value_text(item, app->subghz_extend ? "ON" : "OFF"); - - item = variable_item_list_add( - var_item_list, - "SubGHz Bypass", - 2, - xtreme_settings_scene_start_subghz_bypass_changed, - app); - variable_item_set_current_value_index(item, app->subghz_bypass); - variable_item_set_current_value_text(item, app->subghz_bypass ? "ON" : "OFF"); - - FuriString* version_tag = furi_string_alloc_printf("%s %s", version_get_gitbranchnum(NULL), version_get_builddate(NULL)); - item = variable_item_list_add( - var_item_list, - furi_string_get_cstr(version_tag), - 0, - NULL, - app); - - view_dispatcher_switch_to_view(app->view_dispatcher, XtremeSettingsAppViewVarItemList); -} - -bool xtreme_settings_scene_start_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - bool consumed = false; - return consumed; -} - -void xtreme_settings_scene_start_on_exit(void* context) { - XtremeSettingsApp* app = context; - asset_packs_it_t it; - for (asset_packs_it(it, app->asset_packs); !asset_packs_end_p(it); asset_packs_next(it)) { - free(*asset_packs_cref(it)); - } - asset_packs_clear(app->asset_packs); - variable_item_list_reset(app->var_item_list); -} diff --git a/applications/settings/xtreme_settings/xtreme_assets.c b/applications/settings/xtreme_settings/xtreme_assets.c deleted file mode 100644 index 444b50951..000000000 --- a/applications/settings/xtreme_settings/xtreme_assets.c +++ /dev/null @@ -1,123 +0,0 @@ -#include "xtreme_assets.h" -#include "assets_icons.h" -#include - -XtremeAssets* xtreme_assets = NULL; - -XtremeAssets* XTREME_ASSETS() { - if (xtreme_assets == NULL) { - XTREME_ASSETS_LOAD(); - } - return xtreme_assets; -} - -void XTREME_ASSETS_LOAD() { - if (xtreme_assets != NULL) return; - - xtreme_assets = malloc(sizeof(XtremeAssets)); - XtremeSettings* xtreme_settings = XTREME_SETTINGS(); - - if (xtreme_settings->nsfw_mode) { - xtreme_assets->I_BLE_Pairing_128x64 = &I_BLE_Pairing_128x64; - xtreme_assets->I_DolphinCommon_56x48 = &I_DolphinCommon_56x48; - xtreme_assets->I_DolphinMafia_115x62 = &I_DolphinMafia_115x62; - xtreme_assets->I_DolphinNice_96x59 = &I_DolphinNice_96x59; - xtreme_assets->I_DolphinWait_61x59 = &I_DolphinWait_61x59; - xtreme_assets->I_iButtonDolphinVerySuccess_108x52 = &I_iButtonDolphinVerySuccess_108x52; - xtreme_assets->I_DolphinReadingSuccess_59x63 = &I_DolphinReadingSuccess_59x63; - xtreme_assets->I_NFC_dolphin_emulation_47x61 = &I_NFC_dolphin_emulation_47x61; - xtreme_assets->I_passport_bad_46x49 = &I_flipper; - xtreme_assets->I_passport_DB = &I_passport_DB; - xtreme_assets->I_passport_happy_46x49 = &I_flipper; - xtreme_assets->I_passport_okay_46x49 = &I_flipper; - xtreme_assets->I_RFIDDolphinReceive_97x61 = &I_RFIDDolphinReceive_97x61; - xtreme_assets->I_RFIDDolphinSend_97x61 = &I_RFIDDolphinSend_97x61; - xtreme_assets->I_RFIDDolphinSuccess_108x57 = &I_RFIDDolphinSuccess_108x57; - xtreme_assets->I_Cry_dolph_55x52 = &I_Cry_dolph_55x52; - xtreme_assets->I_Scanning_123x52 = &I_Scanning_123x52; - xtreme_assets->I_Auth_62x31 = &I_Auth_62x31; - xtreme_assets->I_Connect_me_62x31 = &I_Connect_me_62x31; - xtreme_assets->I_Connected_62x31 = &I_Connected_62x31; - xtreme_assets->I_Error_62x31 = &I_Error_62x31; - } else { - xtreme_assets->I_BLE_Pairing_128x64 = &I_BLE_Pairing_128x64_sfw; - xtreme_assets->I_DolphinCommon_56x48 = &I_DolphinCommon_56x48_sfw; - xtreme_assets->I_DolphinMafia_115x62 = &I_DolphinMafia_115x62_sfw; - xtreme_assets->I_DolphinNice_96x59 = &I_DolphinNice_96x59_sfw; - xtreme_assets->I_DolphinWait_61x59 = &I_DolphinWait_61x59_sfw; - xtreme_assets->I_iButtonDolphinVerySuccess_108x52 = &I_iButtonDolphinVerySuccess_108x52_sfw; - xtreme_assets->I_DolphinReadingSuccess_59x63 = &I_DolphinReadingSuccess_59x63_sfw; - xtreme_assets->I_NFC_dolphin_emulation_47x61 = &I_NFC_dolphin_emulation_47x61_sfw; - xtreme_assets->I_passport_bad_46x49 = &I_passport_bad1_46x49_sfw; - xtreme_assets->I_passport_DB = &I_passport_DB_sfw; - xtreme_assets->I_passport_happy_46x49 = &I_passport_happy1_46x49_sfw; - xtreme_assets->I_passport_okay_46x49 = &I_passport_okay1_46x49_sfw; - xtreme_assets->I_RFIDDolphinReceive_97x61 = &I_RFIDDolphinReceive_97x61_sfw; - xtreme_assets->I_RFIDDolphinSend_97x61 = &I_RFIDDolphinSend_97x61_sfw; - xtreme_assets->I_RFIDDolphinSuccess_108x57 = &I_RFIDDolphinSuccess_108x57_sfw; - xtreme_assets->I_Cry_dolph_55x52 = &I_Cry_dolph_55x52_sfw; - xtreme_assets->I_Scanning_123x52 = &I_Scanning_123x52_sfw; - xtreme_assets->I_Auth_62x31 = &I_Auth_62x31_sfw; - xtreme_assets->I_Connect_me_62x31 = &I_Connect_me_62x31_sfw; - xtreme_assets->I_Connected_62x31 = &I_Connected_62x31_sfw; - xtreme_assets->I_Error_62x31 = &I_Error_62x31_sfw; - } - - if (xtreme_settings->asset_pack[0] == '\0') return; - FileInfo info; - FuriString* path = furi_string_alloc(); - const char* pack = xtreme_settings->asset_pack; - furi_string_printf(path, PACKS_DIR "/%s", pack); - Storage* storage = furi_record_open(RECORD_STORAGE); - if (storage_common_stat(storage, furi_string_get_cstr(path), &info) == FSE_OK && info.flags & FSF_DIRECTORY) { - File* file = storage_file_alloc(storage); - - swap_bmx_icon(&xtreme_assets->I_BLE_Pairing_128x64, pack, "BLE/BLE_Pairing_128x64.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_DolphinCommon_56x48, pack, "Dolphin/DolphinCommon_56x48.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_DolphinMafia_115x62, pack, "iButton/DolphinMafia_115x62.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_DolphinNice_96x59, pack, "iButton/DolphinNice_96x59.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_DolphinWait_61x59, pack, "iButton/DolphinWait_61x59.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_iButtonDolphinVerySuccess_108x52, pack, "iButton/iButtonDolphinVerySuccess_108x52.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_DolphinReadingSuccess_59x63, pack, "Infrared/DolphinReadingSuccess_59x63.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_NFC_dolphin_emulation_47x61, pack, "NFC/NFC_dolphin_emulation_47x61.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_passport_bad_46x49, pack, "Passport/passport_bad_46x49.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_passport_DB, pack, "Passport/passport_DB.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_passport_happy_46x49, pack, "Passport/passport_happy_46x49.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_passport_okay_46x49, pack, "Passport/passport_okay_46x49.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_RFIDDolphinReceive_97x61, pack, "RFID/RFIDDolphinReceive_97x61.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_RFIDDolphinSend_97x61, pack, "RFID/RFIDDolphinSend_97x61.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_RFIDDolphinSuccess_108x57, pack, "RFID/RFIDDolphinSuccess_108x57.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_Cry_dolph_55x52, pack, "Settings/Cry_dolph_55x52.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_Scanning_123x52, pack, "SubGhz/Scanning_123x52.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_Auth_62x31, pack, "U2F/Auth_62x31.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_Connect_me_62x31, pack, "U2F/Connect_me_62x31.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_Connected_62x31, pack, "U2F/Connected_62x31.bmx", path, file); - swap_bmx_icon(&xtreme_assets->I_Error_62x31, pack, "U2F/Error_62x31.bmx", path, file); - - storage_file_free(file); - } - furi_record_close(RECORD_STORAGE); - furi_string_free(path); -} - -void swap_bmx_icon(const Icon** replace, const char* pack, const char* name, FuriString* path, File* file) { - furi_string_printf(path, PACKS_DIR "/%s/Icons/%s", pack, name); - if (storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { - uint64_t size = storage_file_size(file) - 8; - int32_t width, height; - storage_file_read(file, &width, 4); - storage_file_read(file, &height, 4); - - Icon* icon = malloc(sizeof(Icon)); - FURI_CONST_ASSIGN(icon->frame_count, 1); - FURI_CONST_ASSIGN(icon->frame_rate, 0); - FURI_CONST_ASSIGN(icon->width, width); - FURI_CONST_ASSIGN(icon->height, height); - icon->frames = malloc(sizeof(const uint8_t*)); - FURI_CONST_ASSIGN_PTR(icon->frames[0], malloc(size)); - storage_file_read(file, (void*)icon->frames[0], size); - *replace = icon; - - storage_file_close(file); - } -} diff --git a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c index 71ce5a7c3..08c9e2d7f 100644 --- a/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c +++ b/applications/system/storage_move_to_sd/scenes/storage_move_to_sd_scene_confirm.c @@ -1,7 +1,7 @@ #include "../storage_move_to_sd.h" -#include "gui/canvas.h" -#include "gui/modules/widget_elements/widget_element_i.h" -#include "storage/storage.h" +#include +#include +#include static void storage_move_to_sd_scene_confirm_widget_callback( GuiButtonType result, diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.h b/applications/system/storage_move_to_sd/storage_move_to_sd.h index a62d87c1f..135f3e9b0 100644 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.h +++ b/applications/system/storage_move_to_sd/storage_move_to_sd.h @@ -1,17 +1,16 @@ #pragma once -#include "gui/modules/widget_elements/widget_element_i.h" -#include #include #include #include #include -#include - #include #include +#include +#include #include #include +#include #include "scenes/storage_move_to_sd_scene.h" diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index f8e21ca3e..2bf6dab26 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -76,8 +76,8 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) { for(size_t idx = 0; idx < COUNT_OF(update_cli_subcommands); ++idx) { const CliSubcommand* subcmd_def = &update_cli_subcommands[idx]; if(furi_string_cmp_str(subcommand, subcmd_def->command) == 0) { - furi_string_free(subcommand); subcmd_def->handler(args); + furi_string_free(subcommand); return; } } diff --git a/applications/system/updater/util/update_task.c b/applications/system/updater/util/update_task.c index b43a6df16..54fe27995 100644 --- a/applications/system/updater/util/update_task.c +++ b/applications/system/updater/util/update_task.c @@ -287,7 +287,9 @@ bool update_task_parse_manifest(UpdateTask* update_task) { } update_task_set_progress(update_task, UpdateTaskStageProgress, 50); - if(manifest->target != furi_hal_version_get_hw_target()) { + /* Check target only if it's set - skipped for pre-production samples */ + if(furi_hal_version_get_hw_target() && + (manifest->target != furi_hal_version_get_hw_target())) { break; } diff --git a/assets/SConscript b/assets/SConscript index aace521d2..ef5d83c79 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -96,4 +96,4 @@ if assetsenv["IS_BASE_FIRMWARE"]: env.Replace(FW_RESOURCES=resources) assetsenv.Alias("resources", resources) -Return("assetslib") \ No newline at end of file +Return("assetslib") diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png index e82c6f2e9..759007623 100644 Binary files a/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png and b/assets/dolphin/blocking/L0_NoDb_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png index 58dab74d4..c9810b61e 100644 Binary files a/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png and b/assets/dolphin/blocking/L0_NoDb_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png index 83ac2d551..e4d381b0a 100644 Binary files a/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png and b/assets/dolphin/blocking/L0_NoDb_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png b/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png index 789dc8822..b48aef978 100644 Binary files a/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png and b/assets/dolphin/blocking/L0_NoDb_128x51/frame_3.png differ diff --git a/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png b/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png index 05f5241c8..f9a7e073a 100644 Binary files a/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png and b/assets/dolphin/blocking/L0_SdBad_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png b/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png index bd0f2b933..147561f0a 100644 Binary files a/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png and b/assets/dolphin/blocking/L0_SdBad_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png index ed3aa717d..6ebbc1111 100644 Binary files a/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png and b/assets/dolphin/blocking/L0_SdOk_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png index 58add1b98..5f7a5d2a5 100644 Binary files a/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png and b/assets/dolphin/blocking/L0_SdOk_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png index a47aebec7..a3450ae05 100644 Binary files a/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png and b/assets/dolphin/blocking/L0_SdOk_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png b/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png index 614ef9c5a..1e52f1513 100644 Binary files a/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png and b/assets/dolphin/blocking/L0_SdOk_128x51/frame_3.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_0.png b/assets/dolphin/blocking/L0_Url_128x51/frame_0.png index 5d4b5cf2e..387c85ea2 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_0.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_1.png b/assets/dolphin/blocking/L0_Url_128x51/frame_1.png index 69f1fb365..9975ca3f0 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_1.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_2.png b/assets/dolphin/blocking/L0_Url_128x51/frame_2.png index 855e7450e..84241c3f1 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_2.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_3.png b/assets/dolphin/blocking/L0_Url_128x51/frame_3.png index 9e9a79405..c44b171bf 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_3.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_3.png differ diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_0.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_0.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_1.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_1.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_10.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_10.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_11.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_11.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_12.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_12.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_13.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_13.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_14.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_14.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_15.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_15.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_16.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_16.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_17.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_17.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_18.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_18.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_19.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_19.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_2.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_2.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_20.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_20.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_21.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_21.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_22.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_22.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_23.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_23.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_24.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_24.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_25.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_25.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_26.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_26.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_27.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_27.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_3.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_3.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_4.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_4.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_5.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_5.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_6.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_6.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_7.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_7.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_8.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_8.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_9.png b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_9.png diff --git a/assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/meta.txt b/assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/PaxGod_TikTok_Marketing/meta.txt rename to assets/dolphin/custom/NSFW/Anims/PaxGod_TikTok_Marketing/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_28.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_28.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_28.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_28.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_29.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_29.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_29.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_29.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_30.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_30.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_30.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_30.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_1/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_1/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_1/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_1/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_1/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_1/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_1/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_10/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_10/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_10/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_10/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_10/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_10/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_10/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_28.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_28.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_28.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_28.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_29.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_29.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_29.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_29.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_30.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_30.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_30.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_30.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_31.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_31.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_31.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_31.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_32.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_32.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_32.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_32.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_33.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_33.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_33.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_33.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_34.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_34.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_34.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_34.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_35.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_35.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_35.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_35.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_36.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_36.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_36.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_36.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_37.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_37.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_37.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_37.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_38.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_38.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_38.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_38.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_39.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_39.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_39.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_39.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_40.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_40.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_40.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_40.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_41.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_41.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_41.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_41.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_42.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_42.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_42.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_42.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_43.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_43.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_43.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_43.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_44.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_44.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_44.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_44.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_45.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_45.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_45.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_45.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_46.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_46.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_46.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_46.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_47.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_47.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_47.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_47.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_48.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_48.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_48.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_48.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_49.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_49.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_49.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_49.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_11/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_11/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_11/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_11/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_11/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_11/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_11/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_12/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_12/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_12/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_12/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_12/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_12/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_12/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_13/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_13/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_13/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_13/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_13/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_13/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_13/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_14/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_14/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_14/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_14/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_14/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_14/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_14/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_14/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_14/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_14/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_14/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_14/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_14/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_14/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_14/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_14/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_14/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_14/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_14/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_14/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_14/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_14/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_14/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_14/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_14/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_14/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_14/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_14/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_15/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_15/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_15/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_15/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_15/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_15/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_15/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_16/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_16/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_16/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_16/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_16/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_16/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_16/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_28.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_28.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_28.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_28.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_29.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_29.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_29.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_29.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_30.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_30.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_30.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_30.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_31.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_31.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_31.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_31.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_17/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_17/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_17/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_17/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_17/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_17/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_17/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_18/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_18/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_18/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_18/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_18/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_18/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_18/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_19/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_19/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_19/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_19/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_19/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_19/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_19/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_2/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_2/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_2/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_2/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_2/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_2/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_2/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_20/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_20/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_20/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_20/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_20/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_20/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_20/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_21/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_21/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_21/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_21/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_21/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_21/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_21/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_21/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_21/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_21/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_21/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_21/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_21/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_21/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_21/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_21/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_21/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_21/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_21/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_21/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_21/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_21/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_21/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_21/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_21/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_21/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_21/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_21/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_28.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_28.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_28.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_28.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_29.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_29.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_29.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_29.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_30.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_30.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_30.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_30.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_31.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_31.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_31.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_31.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_32.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_32.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_32.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_32.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_33.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_33.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_33.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_33.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_34.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_34.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_34.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_34.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_35.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_35.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_35.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_35.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_36.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_36.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_36.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_36.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_37.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_37.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_37.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_37.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_38.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_38.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_38.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_38.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_39.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_39.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_39.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_39.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_40.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_40.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_40.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_40.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_41.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_41.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_41.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_41.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_42.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_42.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_42.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_42.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_43.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_43.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_43.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_43.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_44.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_44.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_44.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_44.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_45.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_45.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_45.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_45.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_46.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_46.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_46.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_46.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_47.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_47.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_47.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_47.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_48.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_48.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_48.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_48.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_49.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_49.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_49.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_49.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_50.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_50.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_50.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_50.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_51.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_51.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_51.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_51.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_52.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_52.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_52.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_52.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_53.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_53.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_53.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_53.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_54.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_54.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_54.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_54.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_55.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_55.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_55.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_55.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_56.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_56.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_56.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_56.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_57.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_57.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_57.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_57.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_58.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_58.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_58.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_58.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_59.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_59.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_59.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_59.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_22/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_22/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_22/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_22/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_22/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_22/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_22/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_23/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_23/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_23/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_23/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_23/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_23/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_23/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_28.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_28.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_28.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_28.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_29.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_29.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_29.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_29.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_24/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_24/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_24/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_24/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_24/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_24/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_24/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_28.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_28.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_28.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_28.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_29.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_29.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_29.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_29.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_30.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_30.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_30.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_30.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_31.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_31.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_31.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_31.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_32.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_32.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_32.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_32.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_33.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_33.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_33.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_33.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_34.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_34.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_34.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_34.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_35.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_35.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_35.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_35.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_25/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_25/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_25/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_25/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_25/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_25/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_25/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_26/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_26/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_26/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_26/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_26/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_26/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_26/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_27/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_27/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_27/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_27/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_27/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_27/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_27/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_28/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_28/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_28/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_28/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_28/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_28/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_28/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_28/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_28/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_28/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_28/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_28/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_28/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_28/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_28/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_28/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_28/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_28/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_28/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_28/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_28/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_28/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_28/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_28/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_28/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_28/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_28/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_28/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_28.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_28.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_28.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_28.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_29.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_29.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_29.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_29.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_30.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_30.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_30.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_30.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_31.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_31.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_31.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_31.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_32.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_32.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_32.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_32.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_33.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_33.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_33.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_33.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_34.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_34.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_34.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_34.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_35.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_35.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_35.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_35.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_36.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_36.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_36.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_36.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_37.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_37.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_37.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_37.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_38.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_38.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_38.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_38.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_39.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_39.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_39.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_39.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_40.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_40.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_40.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_40.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_41.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_41.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_41.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_41.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_42.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_42.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_42.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_42.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_43.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_43.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_43.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_43.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_44.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_44.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_44.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_44.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_45.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_45.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_45.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_45.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_46.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_46.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_46.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_46.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_47.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_47.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_47.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_47.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_48.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_48.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_48.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_48.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_49.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_49.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_49.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_49.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_50.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_50.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_50.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_50.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_51.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_51.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_51.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_51.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_29/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_29/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_29/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_29/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_29/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_29/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_29/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_3/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_3/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_3/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_3/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_3/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_3/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_3/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_28.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_28.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_28.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_28.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_29.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_29.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_29.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_29.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_30.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_30.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_30.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_30.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_31.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_31.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_31.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_31.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_32.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_32.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_32.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_32.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_33.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_33.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_33.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_33.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_34.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_34.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_34.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_34.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_35.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_35.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_35.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_35.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_36.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_36.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_36.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_36.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_37.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_37.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_37.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_37.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_38.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_38.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_38.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_38.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_39.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_39.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_39.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_39.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_40.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_40.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_40.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_40.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_41.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_41.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_41.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_41.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_42.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_42.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_42.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_42.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_43.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_43.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_43.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_43.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_44.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_44.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_44.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_44.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_45.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_45.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_45.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_45.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_46.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_46.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_46.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_46.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_47.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_47.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_47.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_47.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_48.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_48.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_48.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_48.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_49.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_49.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_49.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_49.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_30/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_30/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_30/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_30/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_30/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_30/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_30/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_4/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_4/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_4/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_4/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_4/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_4/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_4/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_14.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_14.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_14.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_14.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_15.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_15.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_15.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_15.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_16.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_16.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_16.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_16.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_17.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_17.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_17.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_17.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_18.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_18.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_18.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_18.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_19.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_19.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_19.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_19.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_20.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_20.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_20.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_20.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_21.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_21.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_21.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_21.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_22.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_22.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_22.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_22.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_23.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_23.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_23.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_23.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_24.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_24.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_24.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_24.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_25.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_25.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_25.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_25.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_26.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_26.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_26.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_26.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_27.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_27.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_27.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_27.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_5/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_5/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_5/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_5/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_5/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_5/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_5/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_6/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_6/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_6/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_6/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_6/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_6/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_6/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_6/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_6/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_6/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_6/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_6/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_6/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_6/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_6/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_6/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_6/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_6/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_6/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_6/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_6/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_6/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_6/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_6/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_6/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_6/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_6/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_6/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_6/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_6/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_6/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_6/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_10.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_10.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_10.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_10.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_11.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_11.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_11.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_11.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_12.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_12.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_12.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_12.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_13.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_13.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_13.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_13.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_8.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_8.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_8.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_8.png diff --git a/assets/dolphin/external/nsfw/lvl_7/frame_9.png b/assets/dolphin/custom/NSFW/Anims/lvl_7/frame_9.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/frame_9.png rename to assets/dolphin/custom/NSFW/Anims/lvl_7/frame_9.png diff --git a/assets/dolphin/external/nsfw/lvl_7/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_7/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_7/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_7/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_8/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_8/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_8/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_8/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_8/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_8/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_8/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_8/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_8/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_8/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_8/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_8/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_8/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_8/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_8/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_8/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_8/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_8/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_8/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_8/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_8/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_8/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_8/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_8/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_8/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_8/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_8/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_8/meta.txt diff --git a/assets/dolphin/external/nsfw/lvl_9/frame_0.png b/assets/dolphin/custom/NSFW/Anims/lvl_9/frame_0.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/frame_0.png rename to assets/dolphin/custom/NSFW/Anims/lvl_9/frame_0.png diff --git a/assets/dolphin/external/nsfw/lvl_9/frame_1.png b/assets/dolphin/custom/NSFW/Anims/lvl_9/frame_1.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/frame_1.png rename to assets/dolphin/custom/NSFW/Anims/lvl_9/frame_1.png diff --git a/assets/dolphin/external/nsfw/lvl_9/frame_2.png b/assets/dolphin/custom/NSFW/Anims/lvl_9/frame_2.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/frame_2.png rename to assets/dolphin/custom/NSFW/Anims/lvl_9/frame_2.png diff --git a/assets/dolphin/external/nsfw/lvl_9/frame_3.png b/assets/dolphin/custom/NSFW/Anims/lvl_9/frame_3.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/frame_3.png rename to assets/dolphin/custom/NSFW/Anims/lvl_9/frame_3.png diff --git a/assets/dolphin/external/nsfw/lvl_9/frame_4.png b/assets/dolphin/custom/NSFW/Anims/lvl_9/frame_4.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/frame_4.png rename to assets/dolphin/custom/NSFW/Anims/lvl_9/frame_4.png diff --git a/assets/dolphin/external/nsfw/lvl_9/frame_5.png b/assets/dolphin/custom/NSFW/Anims/lvl_9/frame_5.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/frame_5.png rename to assets/dolphin/custom/NSFW/Anims/lvl_9/frame_5.png diff --git a/assets/dolphin/external/nsfw/lvl_9/frame_6.png b/assets/dolphin/custom/NSFW/Anims/lvl_9/frame_6.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/frame_6.png rename to assets/dolphin/custom/NSFW/Anims/lvl_9/frame_6.png diff --git a/assets/dolphin/external/nsfw/lvl_9/frame_7.png b/assets/dolphin/custom/NSFW/Anims/lvl_9/frame_7.png similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/frame_7.png rename to assets/dolphin/custom/NSFW/Anims/lvl_9/frame_7.png diff --git a/assets/dolphin/external/nsfw/lvl_9/meta.txt b/assets/dolphin/custom/NSFW/Anims/lvl_9/meta.txt similarity index 100% rename from assets/dolphin/external/nsfw/lvl_9/meta.txt rename to assets/dolphin/custom/NSFW/Anims/lvl_9/meta.txt diff --git a/assets/dolphin/external/nsfw/manifest.txt b/assets/dolphin/custom/NSFW/Anims/manifest.txt similarity index 100% rename from assets/dolphin/external/nsfw/manifest.txt rename to assets/dolphin/custom/NSFW/Anims/manifest.txt diff --git a/assets/icons/Animations/Levelup1_128x64/frame_00.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_00.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_00.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_00.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_01.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_01.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_01.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_01.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_02.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_02.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_02.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_02.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_03.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_03.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_03.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_03.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_04.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_04.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_04.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_04.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_05.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_05.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_05.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_05.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_06.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_06.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_06.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_06.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_07.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_07.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_07.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_07.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_08.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_08.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_08.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_08.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_09.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_09.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_09.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_09.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_10.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_10.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_10.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_10.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_11.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_11.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_11.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_11.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_12.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_12.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_12.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_12.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_13.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_13.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_13.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_13.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_14.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_14.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_14.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_14.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_15.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_15.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_15.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_15.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_16.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_16.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_16.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_16.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_17.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_17.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_17.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_17.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_18.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_18.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_18.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_18.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_19.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_19.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_19.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_19.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_20.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_20.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_20.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_20.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_21.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_21.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_21.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_21.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_22.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_22.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_22.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_22.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_23.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_23.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_23.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_23.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_24.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_24.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_24.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_24.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_25.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_25.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_25.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_25.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_26.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_26.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_26.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_26.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_27.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_27.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_27.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_27.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_28.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_28.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_28.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_28.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_29.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_29.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_29.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_29.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_30.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_30.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_30.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_30.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_31.png b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_31.png similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_31.png rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_31.png diff --git a/assets/icons/Animations/Levelup1_128x64/frame_rate b/assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_rate similarity index 100% rename from assets/icons/Animations/Levelup1_128x64/frame_rate rename to assets/dolphin/custom/NSFW/Icons/Animations/Levelup_128x64/frame_rate diff --git a/assets/dolphin/custom/NSFW/Icons/BLE/BLE_Pairing_128x64.png b/assets/dolphin/custom/NSFW/Icons/BLE/BLE_Pairing_128x64.png new file mode 100644 index 000000000..f60598005 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/BLE/BLE_Pairing_128x64.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/Dolphin/DolphinCommon_56x48.png b/assets/dolphin/custom/NSFW/Icons/Dolphin/DolphinCommon_56x48.png new file mode 100644 index 000000000..e80fea5bd Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/Dolphin/DolphinCommon_56x48.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/Infrared/DolphinReadingSuccess_59x63.png b/assets/dolphin/custom/NSFW/Icons/Infrared/DolphinReadingSuccess_59x63.png new file mode 100644 index 000000000..93a7ad79c Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/Infrared/DolphinReadingSuccess_59x63.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/NFC/NFC_dolphin_emulation_47x61.png b/assets/dolphin/custom/NSFW/Icons/NFC/NFC_dolphin_emulation_47x61.png new file mode 100644 index 000000000..e85b50f26 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/NFC/NFC_dolphin_emulation_47x61.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/Passport/passport_DB.png b/assets/dolphin/custom/NSFW/Icons/Passport/passport_DB.png new file mode 100644 index 000000000..f813f2afd Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/Passport/passport_DB.png differ diff --git a/assets/icons/Passport/flipper.png b/assets/dolphin/custom/NSFW/Icons/Passport/passport_bad_46x49.png similarity index 100% rename from assets/icons/Passport/flipper.png rename to assets/dolphin/custom/NSFW/Icons/Passport/passport_bad_46x49.png diff --git a/assets/dolphin/custom/NSFW/Icons/Passport/passport_happy_46x49.png b/assets/dolphin/custom/NSFW/Icons/Passport/passport_happy_46x49.png new file mode 100644 index 000000000..98d7e15f9 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/Passport/passport_happy_46x49.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/Passport/passport_okay_46x49.png b/assets/dolphin/custom/NSFW/Icons/Passport/passport_okay_46x49.png new file mode 100644 index 000000000..98d7e15f9 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/Passport/passport_okay_46x49.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinReceive_97x61.png b/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinReceive_97x61.png new file mode 100644 index 000000000..2528ebc95 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinReceive_97x61.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinSend_97x61.png b/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinSend_97x61.png new file mode 100644 index 000000000..fef503263 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinSend_97x61.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinSuccess_108x57.png b/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinSuccess_108x57.png new file mode 100644 index 000000000..78c4e93f8 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/RFID/RFIDDolphinSuccess_108x57.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/Settings/Cry_dolph_55x52.png b/assets/dolphin/custom/NSFW/Icons/Settings/Cry_dolph_55x52.png new file mode 100644 index 000000000..d1164c594 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/Settings/Cry_dolph_55x52.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/SubGhz/Scanning_123x52.png b/assets/dolphin/custom/NSFW/Icons/SubGhz/Scanning_123x52.png new file mode 100644 index 000000000..a48c5330e Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/SubGhz/Scanning_123x52.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/U2F/Auth_62x31.png b/assets/dolphin/custom/NSFW/Icons/U2F/Auth_62x31.png new file mode 100644 index 000000000..255e391a4 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/U2F/Auth_62x31.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/U2F/Connect_me_62x31.png b/assets/dolphin/custom/NSFW/Icons/U2F/Connect_me_62x31.png new file mode 100644 index 000000000..a8cfe1efb Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/U2F/Connect_me_62x31.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/U2F/Connected_62x31.png b/assets/dolphin/custom/NSFW/Icons/U2F/Connected_62x31.png new file mode 100644 index 000000000..55b7782ad Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/U2F/Connected_62x31.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/U2F/Error_62x31.png b/assets/dolphin/custom/NSFW/Icons/U2F/Error_62x31.png new file mode 100644 index 000000000..8760ba461 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/U2F/Error_62x31.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/iButton/DolphinMafia_115x62.png b/assets/dolphin/custom/NSFW/Icons/iButton/DolphinMafia_115x62.png new file mode 100644 index 000000000..e53a1c040 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/iButton/DolphinMafia_115x62.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/iButton/DolphinNice_96x59.png b/assets/dolphin/custom/NSFW/Icons/iButton/DolphinNice_96x59.png new file mode 100644 index 000000000..43cc58bd9 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/iButton/DolphinNice_96x59.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/iButton/DolphinWait_61x59.png b/assets/dolphin/custom/NSFW/Icons/iButton/DolphinWait_61x59.png new file mode 100644 index 000000000..4beec55ef Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/iButton/DolphinWait_61x59.png differ diff --git a/assets/dolphin/custom/NSFW/Icons/iButton/iButtonDolphinVerySuccess_108x52.png b/assets/dolphin/custom/NSFW/Icons/iButton/iButtonDolphinVerySuccess_108x52.png new file mode 100644 index 000000000..90b589ff8 Binary files /dev/null and b/assets/dolphin/custom/NSFW/Icons/iButton/iButtonDolphinVerySuccess_108x52.png differ diff --git a/assets/dolphin/custom/ReadMe.md b/assets/dolphin/custom/ReadMe.md new file mode 100644 index 000000000..7dd7f80fb --- /dev/null +++ b/assets/dolphin/custom/ReadMe.md @@ -0,0 +1,6 @@ +# Pre-included Asset Packs + +Includes a WatchDogs asset pack by default. Credits: +- [WrenchAtHome](https://github.com/wrenchathome) for some [desktop anims](https://github.com/wrenchathome/flip0anims) +- [u/Cheroon](https://www.reddit.com/user/Cheroon/) for the [passport portait](https://www.reddit.com/r/watch_dogs/comments/50n046/pixel_art_wrench_mask_gif/) +- [WillyJL](https://github.com/Willy-JL) for other assets, icons and animations diff --git a/assets/dolphin/custom/WatchDogs/Icons/RFID/rfid_success.png b/assets/dolphin/custom/WatchDogs/Icons/RFID/RFIDDolphinSuccess_108x57.png similarity index 100% rename from assets/dolphin/custom/WatchDogs/Icons/RFID/rfid_success.png rename to assets/dolphin/custom/WatchDogs/Icons/RFID/RFIDDolphinSuccess_108x57.png diff --git a/assets/dolphin/external/sfw/L1_Boxing_128x64/frame_0.png b/assets/dolphin/external/L1_Boxing_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Boxing_128x64/frame_0.png rename to assets/dolphin/external/L1_Boxing_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Boxing_128x64/frame_1.png b/assets/dolphin/external/L1_Boxing_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Boxing_128x64/frame_1.png rename to assets/dolphin/external/L1_Boxing_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Boxing_128x64/frame_2.png b/assets/dolphin/external/L1_Boxing_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Boxing_128x64/frame_2.png rename to assets/dolphin/external/L1_Boxing_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Boxing_128x64/frame_3.png b/assets/dolphin/external/L1_Boxing_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Boxing_128x64/frame_3.png rename to assets/dolphin/external/L1_Boxing_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Boxing_128x64/frame_4.png b/assets/dolphin/external/L1_Boxing_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Boxing_128x64/frame_4.png rename to assets/dolphin/external/L1_Boxing_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Boxing_128x64/frame_5.png b/assets/dolphin/external/L1_Boxing_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Boxing_128x64/frame_5.png rename to assets/dolphin/external/L1_Boxing_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Boxing_128x64/frame_6.png b/assets/dolphin/external/L1_Boxing_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Boxing_128x64/frame_6.png rename to assets/dolphin/external/L1_Boxing_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Boxing_128x64/meta.txt b/assets/dolphin/external/L1_Boxing_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Boxing_128x64/meta.txt rename to assets/dolphin/external/L1_Boxing_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/frame_0.png b/assets/dolphin/external/L1_Cry_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/frame_0.png rename to assets/dolphin/external/L1_Cry_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/frame_1.png b/assets/dolphin/external/L1_Cry_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/frame_1.png rename to assets/dolphin/external/L1_Cry_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/frame_2.png b/assets/dolphin/external/L1_Cry_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/frame_2.png rename to assets/dolphin/external/L1_Cry_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/frame_3.png b/assets/dolphin/external/L1_Cry_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/frame_3.png rename to assets/dolphin/external/L1_Cry_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/frame_4.png b/assets/dolphin/external/L1_Cry_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/frame_4.png rename to assets/dolphin/external/L1_Cry_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/frame_5.png b/assets/dolphin/external/L1_Cry_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/frame_5.png rename to assets/dolphin/external/L1_Cry_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/frame_6.png b/assets/dolphin/external/L1_Cry_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/frame_6.png rename to assets/dolphin/external/L1_Cry_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/frame_7.png b/assets/dolphin/external/L1_Cry_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/frame_7.png rename to assets/dolphin/external/L1_Cry_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Cry_128x64/meta.txt b/assets/dolphin/external/L1_Cry_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Cry_128x64/meta.txt rename to assets/dolphin/external/L1_Cry_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_0.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_0.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_1.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_1.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_10.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_10.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_11.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_11.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_12.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_12.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_13.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_13.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_13.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_14.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_14.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_14.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_14.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_15.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_15.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_15.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_15.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_16.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_16.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_16.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_16.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_17.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_17.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_17.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_17.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_18.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_18.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_18.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_18.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_2.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_2.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_3.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_3.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_4.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_4.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_5.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_5.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_6.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_6.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_7.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_7.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_8.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_8.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_9.png b/assets/dolphin/external/L1_Furippa1_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/frame_9.png rename to assets/dolphin/external/L1_Furippa1_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L1_Furippa1_128x64/meta.txt b/assets/dolphin/external/L1_Furippa1_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Furippa1_128x64/meta.txt rename to assets/dolphin/external/L1_Furippa1_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_0.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_0.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_1.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_1.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_10.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_10.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_11.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_11.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_12.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_12.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_2.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_2.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_3.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_3.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_4.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_4.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_5.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_5.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_6.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_6.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_7.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_7.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_8.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_8.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_9.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/frame_9.png rename to assets/dolphin/external/L1_Happy_holidays_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L1_Happy_holidays_128x64/meta.txt b/assets/dolphin/external/L1_Happy_holidays_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Happy_holidays_128x64/meta.txt rename to assets/dolphin/external/L1_Happy_holidays_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/frame_0.png b/assets/dolphin/external/L1_Laptop_128x51/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/frame_0.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/frame_1.png b/assets/dolphin/external/L1_Laptop_128x51/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/frame_1.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/frame_2.png b/assets/dolphin/external/L1_Laptop_128x51/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/frame_2.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/frame_3.png b/assets/dolphin/external/L1_Laptop_128x51/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/frame_3.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/frame_4.png b/assets/dolphin/external/L1_Laptop_128x51/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/frame_4.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/frame_5.png b/assets/dolphin/external/L1_Laptop_128x51/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/frame_5.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/frame_6.png b/assets/dolphin/external/L1_Laptop_128x51/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/frame_6.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/frame_7.png b/assets/dolphin/external/L1_Laptop_128x51/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/frame_7.png rename to assets/dolphin/external/L1_Laptop_128x51/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Laptop_128x51/meta.txt b/assets/dolphin/external/L1_Laptop_128x51/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Laptop_128x51/meta.txt rename to assets/dolphin/external/L1_Laptop_128x51/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_0.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_0.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_1.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_1.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_10.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_10.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_11.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_11.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_12.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_12.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_2.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_2.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_3.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_3.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_4.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_4.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_5.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_5.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_6.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_6.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_7.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_7.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_8.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_8.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_9.png b/assets/dolphin/external/L1_Leaving_sad_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/frame_9.png rename to assets/dolphin/external/L1_Leaving_sad_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L1_Leaving_sad_128x64/meta.txt b/assets/dolphin/external/L1_Leaving_sad_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Leaving_sad_128x64/meta.txt rename to assets/dolphin/external/L1_Leaving_sad_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_0.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_0.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_1.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_1.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_10.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_10.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_11.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_11.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_12.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_12.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_13.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_13.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_13.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_2.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_2.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_3.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_3.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_4.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_4.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_5.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_5.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_6.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_6.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_7.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_7.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_8.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_8.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_9.png b/assets/dolphin/external/L1_Mad_fist_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/frame_9.png rename to assets/dolphin/external/L1_Mad_fist_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L1_Mad_fist_128x64/meta.txt b/assets/dolphin/external/L1_Mad_fist_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Mad_fist_128x64/meta.txt rename to assets/dolphin/external/L1_Mad_fist_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_0.png b/assets/dolphin/external/L1_Mods_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_0.png rename to assets/dolphin/external/L1_Mods_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_1.png b/assets/dolphin/external/L1_Mods_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_1.png rename to assets/dolphin/external/L1_Mods_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_10.png b/assets/dolphin/external/L1_Mods_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_10.png rename to assets/dolphin/external/L1_Mods_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_11.png b/assets/dolphin/external/L1_Mods_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_11.png rename to assets/dolphin/external/L1_Mods_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_12.png b/assets/dolphin/external/L1_Mods_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_12.png rename to assets/dolphin/external/L1_Mods_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_13.png b/assets/dolphin/external/L1_Mods_128x64/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_13.png rename to assets/dolphin/external/L1_Mods_128x64/frame_13.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_14.png b/assets/dolphin/external/L1_Mods_128x64/frame_14.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_14.png rename to assets/dolphin/external/L1_Mods_128x64/frame_14.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_15.png b/assets/dolphin/external/L1_Mods_128x64/frame_15.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_15.png rename to assets/dolphin/external/L1_Mods_128x64/frame_15.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_16.png b/assets/dolphin/external/L1_Mods_128x64/frame_16.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_16.png rename to assets/dolphin/external/L1_Mods_128x64/frame_16.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_17.png b/assets/dolphin/external/L1_Mods_128x64/frame_17.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_17.png rename to assets/dolphin/external/L1_Mods_128x64/frame_17.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_18.png b/assets/dolphin/external/L1_Mods_128x64/frame_18.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_18.png rename to assets/dolphin/external/L1_Mods_128x64/frame_18.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_19.png b/assets/dolphin/external/L1_Mods_128x64/frame_19.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_19.png rename to assets/dolphin/external/L1_Mods_128x64/frame_19.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_2.png b/assets/dolphin/external/L1_Mods_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_2.png rename to assets/dolphin/external/L1_Mods_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_20.png b/assets/dolphin/external/L1_Mods_128x64/frame_20.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_20.png rename to assets/dolphin/external/L1_Mods_128x64/frame_20.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_21.png b/assets/dolphin/external/L1_Mods_128x64/frame_21.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_21.png rename to assets/dolphin/external/L1_Mods_128x64/frame_21.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_22.png b/assets/dolphin/external/L1_Mods_128x64/frame_22.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_22.png rename to assets/dolphin/external/L1_Mods_128x64/frame_22.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_23.png b/assets/dolphin/external/L1_Mods_128x64/frame_23.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_23.png rename to assets/dolphin/external/L1_Mods_128x64/frame_23.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_24.png b/assets/dolphin/external/L1_Mods_128x64/frame_24.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_24.png rename to assets/dolphin/external/L1_Mods_128x64/frame_24.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_25.png b/assets/dolphin/external/L1_Mods_128x64/frame_25.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_25.png rename to assets/dolphin/external/L1_Mods_128x64/frame_25.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_26.png b/assets/dolphin/external/L1_Mods_128x64/frame_26.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_26.png rename to assets/dolphin/external/L1_Mods_128x64/frame_26.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_27.png b/assets/dolphin/external/L1_Mods_128x64/frame_27.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_27.png rename to assets/dolphin/external/L1_Mods_128x64/frame_27.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_28.png b/assets/dolphin/external/L1_Mods_128x64/frame_28.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_28.png rename to assets/dolphin/external/L1_Mods_128x64/frame_28.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_29.png b/assets/dolphin/external/L1_Mods_128x64/frame_29.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_29.png rename to assets/dolphin/external/L1_Mods_128x64/frame_29.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_3.png b/assets/dolphin/external/L1_Mods_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_3.png rename to assets/dolphin/external/L1_Mods_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_30.png b/assets/dolphin/external/L1_Mods_128x64/frame_30.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_30.png rename to assets/dolphin/external/L1_Mods_128x64/frame_30.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_31.png b/assets/dolphin/external/L1_Mods_128x64/frame_31.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_31.png rename to assets/dolphin/external/L1_Mods_128x64/frame_31.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_32.png b/assets/dolphin/external/L1_Mods_128x64/frame_32.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_32.png rename to assets/dolphin/external/L1_Mods_128x64/frame_32.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_33.png b/assets/dolphin/external/L1_Mods_128x64/frame_33.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_33.png rename to assets/dolphin/external/L1_Mods_128x64/frame_33.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_34.png b/assets/dolphin/external/L1_Mods_128x64/frame_34.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_34.png rename to assets/dolphin/external/L1_Mods_128x64/frame_34.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_35.png b/assets/dolphin/external/L1_Mods_128x64/frame_35.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_35.png rename to assets/dolphin/external/L1_Mods_128x64/frame_35.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_36.png b/assets/dolphin/external/L1_Mods_128x64/frame_36.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_36.png rename to assets/dolphin/external/L1_Mods_128x64/frame_36.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_37.png b/assets/dolphin/external/L1_Mods_128x64/frame_37.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_37.png rename to assets/dolphin/external/L1_Mods_128x64/frame_37.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_38.png b/assets/dolphin/external/L1_Mods_128x64/frame_38.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_38.png rename to assets/dolphin/external/L1_Mods_128x64/frame_38.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_39.png b/assets/dolphin/external/L1_Mods_128x64/frame_39.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_39.png rename to assets/dolphin/external/L1_Mods_128x64/frame_39.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_4.png b/assets/dolphin/external/L1_Mods_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_4.png rename to assets/dolphin/external/L1_Mods_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_40.png b/assets/dolphin/external/L1_Mods_128x64/frame_40.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_40.png rename to assets/dolphin/external/L1_Mods_128x64/frame_40.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_5.png b/assets/dolphin/external/L1_Mods_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_5.png rename to assets/dolphin/external/L1_Mods_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_6.png b/assets/dolphin/external/L1_Mods_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_6.png rename to assets/dolphin/external/L1_Mods_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_7.png b/assets/dolphin/external/L1_Mods_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_7.png rename to assets/dolphin/external/L1_Mods_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_8.png b/assets/dolphin/external/L1_Mods_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_8.png rename to assets/dolphin/external/L1_Mods_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/frame_9.png b/assets/dolphin/external/L1_Mods_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/frame_9.png rename to assets/dolphin/external/L1_Mods_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L1_Mods_128x64/meta.txt b/assets/dolphin/external/L1_Mods_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Mods_128x64/meta.txt rename to assets/dolphin/external/L1_Mods_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_0.png b/assets/dolphin/external/L1_Painting_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_0.png rename to assets/dolphin/external/L1_Painting_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_1.png b/assets/dolphin/external/L1_Painting_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_1.png rename to assets/dolphin/external/L1_Painting_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_10.png b/assets/dolphin/external/L1_Painting_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_10.png rename to assets/dolphin/external/L1_Painting_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_11.png b/assets/dolphin/external/L1_Painting_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_11.png rename to assets/dolphin/external/L1_Painting_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_2.png b/assets/dolphin/external/L1_Painting_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_2.png rename to assets/dolphin/external/L1_Painting_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_3.png b/assets/dolphin/external/L1_Painting_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_3.png rename to assets/dolphin/external/L1_Painting_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_4.png b/assets/dolphin/external/L1_Painting_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_4.png rename to assets/dolphin/external/L1_Painting_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_5.png b/assets/dolphin/external/L1_Painting_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_5.png rename to assets/dolphin/external/L1_Painting_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_6.png b/assets/dolphin/external/L1_Painting_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_6.png rename to assets/dolphin/external/L1_Painting_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_7.png b/assets/dolphin/external/L1_Painting_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_7.png rename to assets/dolphin/external/L1_Painting_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_8.png b/assets/dolphin/external/L1_Painting_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_8.png rename to assets/dolphin/external/L1_Painting_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/frame_9.png b/assets/dolphin/external/L1_Painting_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/frame_9.png rename to assets/dolphin/external/L1_Painting_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L1_Painting_128x64/meta.txt b/assets/dolphin/external/L1_Painting_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Painting_128x64/meta.txt rename to assets/dolphin/external/L1_Painting_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_0.png b/assets/dolphin/external/L1_Read_books_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_0.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_1.png b/assets/dolphin/external/L1_Read_books_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_1.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_2.png b/assets/dolphin/external/L1_Read_books_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_2.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_3.png b/assets/dolphin/external/L1_Read_books_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_3.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_4.png b/assets/dolphin/external/L1_Read_books_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_4.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_5.png b/assets/dolphin/external/L1_Read_books_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_5.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_6.png b/assets/dolphin/external/L1_Read_books_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_6.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_7.png b/assets/dolphin/external/L1_Read_books_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_7.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/frame_8.png b/assets/dolphin/external/L1_Read_books_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/frame_8.png rename to assets/dolphin/external/L1_Read_books_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Read_books_128x64/meta.txt b/assets/dolphin/external/L1_Read_books_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Read_books_128x64/meta.txt rename to assets/dolphin/external/L1_Read_books_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_0.png b/assets/dolphin/external/L1_Recording_128x51/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_0.png rename to assets/dolphin/external/L1_Recording_128x51/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_1.png b/assets/dolphin/external/L1_Recording_128x51/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_1.png rename to assets/dolphin/external/L1_Recording_128x51/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_10.png b/assets/dolphin/external/L1_Recording_128x51/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_10.png rename to assets/dolphin/external/L1_Recording_128x51/frame_10.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_11.png b/assets/dolphin/external/L1_Recording_128x51/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_11.png rename to assets/dolphin/external/L1_Recording_128x51/frame_11.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_2.png b/assets/dolphin/external/L1_Recording_128x51/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_2.png rename to assets/dolphin/external/L1_Recording_128x51/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_3.png b/assets/dolphin/external/L1_Recording_128x51/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_3.png rename to assets/dolphin/external/L1_Recording_128x51/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_4.png b/assets/dolphin/external/L1_Recording_128x51/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_4.png rename to assets/dolphin/external/L1_Recording_128x51/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_5.png b/assets/dolphin/external/L1_Recording_128x51/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_5.png rename to assets/dolphin/external/L1_Recording_128x51/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_6.png b/assets/dolphin/external/L1_Recording_128x51/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_6.png rename to assets/dolphin/external/L1_Recording_128x51/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_7.png b/assets/dolphin/external/L1_Recording_128x51/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_7.png rename to assets/dolphin/external/L1_Recording_128x51/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_8.png b/assets/dolphin/external/L1_Recording_128x51/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_8.png rename to assets/dolphin/external/L1_Recording_128x51/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/frame_9.png b/assets/dolphin/external/L1_Recording_128x51/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/frame_9.png rename to assets/dolphin/external/L1_Recording_128x51/frame_9.png diff --git a/assets/dolphin/external/sfw/L1_Recording_128x51/meta.txt b/assets/dolphin/external/L1_Recording_128x51/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Recording_128x51/meta.txt rename to assets/dolphin/external/L1_Recording_128x51/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Sleep_128x64/frame_0.png b/assets/dolphin/external/L1_Sleep_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleep_128x64/frame_0.png rename to assets/dolphin/external/L1_Sleep_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Sleep_128x64/frame_1.png b/assets/dolphin/external/L1_Sleep_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleep_128x64/frame_1.png rename to assets/dolphin/external/L1_Sleep_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Sleep_128x64/frame_2.png b/assets/dolphin/external/L1_Sleep_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleep_128x64/frame_2.png rename to assets/dolphin/external/L1_Sleep_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Sleep_128x64/frame_3.png b/assets/dolphin/external/L1_Sleep_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleep_128x64/frame_3.png rename to assets/dolphin/external/L1_Sleep_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Sleep_128x64/meta.txt b/assets/dolphin/external/L1_Sleep_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleep_128x64/meta.txt rename to assets/dolphin/external/L1_Sleep_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_0.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_0.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_1.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_1.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_10.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_10.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_11.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_11.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_12.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_12.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_13.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_13.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_13.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_14.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_14.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_14.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_15.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_15.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_15.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_16.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_16.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_16.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_17.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_17.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_17.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_17.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_18.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_18.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_18.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_18.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_19.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_19.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_19.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_19.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_2.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_2.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_20.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_20.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_20.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_20.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_21.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_21.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_21.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_21.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_22.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_22.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_22.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_22.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_23.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_23.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_23.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_24.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_24.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_24.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_24.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_25.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_25.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_25.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_25.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_26.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_26.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_26.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_26.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_27.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_27.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_27.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_28.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_28.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_28.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_29.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_29.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_29.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_29.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_3.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_3.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_30.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_30.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_30.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_30.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_31.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_31.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_31.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_32.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_32.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_32.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_33.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_33.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_33.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_33.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_34.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_34.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_34.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_35.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_35.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_35.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_36.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_36.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_36.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_36.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_4.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_4.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_5.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_5.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_6.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_6.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_7.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_7.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_8.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_8.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_9.png b/assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/frame_9.png rename to assets/dolphin/external/L1_Sleigh_ride_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/meta.txt b/assets/dolphin/external/L1_Sleigh_ride_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Sleigh_ride_128x64/meta.txt rename to assets/dolphin/external/L1_Sleigh_ride_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L1_Waves_128x50/frame_0.png b/assets/dolphin/external/L1_Waves_128x50/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Waves_128x50/frame_0.png rename to assets/dolphin/external/L1_Waves_128x50/frame_0.png diff --git a/assets/dolphin/external/sfw/L1_Waves_128x50/frame_1.png b/assets/dolphin/external/L1_Waves_128x50/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Waves_128x50/frame_1.png rename to assets/dolphin/external/L1_Waves_128x50/frame_1.png diff --git a/assets/dolphin/external/sfw/L1_Waves_128x50/frame_2.png b/assets/dolphin/external/L1_Waves_128x50/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Waves_128x50/frame_2.png rename to assets/dolphin/external/L1_Waves_128x50/frame_2.png diff --git a/assets/dolphin/external/sfw/L1_Waves_128x50/frame_3.png b/assets/dolphin/external/L1_Waves_128x50/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L1_Waves_128x50/frame_3.png rename to assets/dolphin/external/L1_Waves_128x50/frame_3.png diff --git a/assets/dolphin/external/sfw/L1_Waves_128x50/meta.txt b/assets/dolphin/external/L1_Waves_128x50/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L1_Waves_128x50/meta.txt rename to assets/dolphin/external/L1_Waves_128x50/meta.txt diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_0.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_0.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_1.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_1.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_10.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_10.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_11.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_11.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_12.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_12.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_13.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_13.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_13.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_14.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_14.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_14.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_14.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_15.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_15.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_15.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_15.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_16.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_16.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_16.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_16.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_17.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_17.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_17.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_17.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_18.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_18.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_18.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_18.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_2.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_2.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_3.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_3.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_4.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_4.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_5.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_5.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_6.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_6.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_7.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_7.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_8.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_8.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_9.png b/assets/dolphin/external/L2_Furippa2_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/frame_9.png rename to assets/dolphin/external/L2_Furippa2_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L2_Furippa2_128x64/meta.txt b/assets/dolphin/external/L2_Furippa2_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L2_Furippa2_128x64/meta.txt rename to assets/dolphin/external/L2_Furippa2_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_0.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_0.png rename to assets/dolphin/external/L2_Hacking_pc_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_1.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_1.png rename to assets/dolphin/external/L2_Hacking_pc_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_2.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_2.png rename to assets/dolphin/external/L2_Hacking_pc_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_3.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_3.png rename to assets/dolphin/external/L2_Hacking_pc_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_4.png b/assets/dolphin/external/L2_Hacking_pc_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Hacking_pc_128x64/frame_4.png rename to assets/dolphin/external/L2_Hacking_pc_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L2_Hacking_pc_128x64/meta.txt b/assets/dolphin/external/L2_Hacking_pc_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L2_Hacking_pc_128x64/meta.txt rename to assets/dolphin/external/L2_Hacking_pc_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_0.png b/assets/dolphin/external/L2_Soldering_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_0.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_1.png b/assets/dolphin/external/L2_Soldering_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_1.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_10.png b/assets/dolphin/external/L2_Soldering_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_10.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_2.png b/assets/dolphin/external/L2_Soldering_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_2.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_3.png b/assets/dolphin/external/L2_Soldering_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_3.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_4.png b/assets/dolphin/external/L2_Soldering_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_4.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_5.png b/assets/dolphin/external/L2_Soldering_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_5.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_6.png b/assets/dolphin/external/L2_Soldering_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_6.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_7.png b/assets/dolphin/external/L2_Soldering_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_7.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_8.png b/assets/dolphin/external/L2_Soldering_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_8.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/frame_9.png b/assets/dolphin/external/L2_Soldering_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/frame_9.png rename to assets/dolphin/external/L2_Soldering_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L2_Soldering_128x64/meta.txt b/assets/dolphin/external/L2_Soldering_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L2_Soldering_128x64/meta.txt rename to assets/dolphin/external/L2_Soldering_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_0.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_0.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_1.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_1.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_10.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_10.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_11.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_11.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_12.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_12.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_13.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_13.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_13.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_14.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_14.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_14.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_14.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_15.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_15.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_15.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_15.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_16.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_16.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_16.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_16.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_17.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_17.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_17.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_17.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_18.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_18.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_18.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_18.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_19.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_19.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_19.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_19.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_2.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_2.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_20.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_20.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_20.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_20.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_3.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_3.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_4.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_4.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_5.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_5.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_6.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_6.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_7.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_7.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_8.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_8.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_9.png b/assets/dolphin/external/L2_Wake_up_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/frame_9.png rename to assets/dolphin/external/L2_Wake_up_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L2_Wake_up_128x64/meta.txt b/assets/dolphin/external/L2_Wake_up_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L2_Wake_up_128x64/meta.txt rename to assets/dolphin/external/L2_Wake_up_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_0.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_0.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_1.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_1.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_10.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_10.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_11.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_11.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_12.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_12.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_13.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_13.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_13.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_14.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_14.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_14.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_14.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_15.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_15.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_15.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_15.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_16.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_16.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_16.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_16.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_17.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_17.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_17.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_17.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_18.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_18.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_18.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_18.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_2.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_2.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_3.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_3.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_4.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_4.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_5.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_5.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_6.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_6.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_7.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_7.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_8.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_8.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_9.png b/assets/dolphin/external/L3_Furippa3_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/frame_9.png rename to assets/dolphin/external/L3_Furippa3_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L3_Furippa3_128x64/meta.txt b/assets/dolphin/external/L3_Furippa3_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L3_Furippa3_128x64/meta.txt rename to assets/dolphin/external/L3_Furippa3_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_0.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_0.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_0.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_1.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_1.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_1.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_10.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_10.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_10.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_11.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_11.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_11.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_12.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_12.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_12.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_13.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_13.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_13.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_2.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_2.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_2.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_3.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_3.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_3.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_4.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_4.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_4.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_5.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_5.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_5.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_6.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_6.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_6.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_7.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_7.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_7.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_8.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_8.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_8.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_9.png b/assets/dolphin/external/L3_Hijack_radio_128x64/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/frame_9.png rename to assets/dolphin/external/L3_Hijack_radio_128x64/frame_9.png diff --git a/assets/dolphin/external/sfw/L3_Hijack_radio_128x64/meta.txt b/assets/dolphin/external/L3_Hijack_radio_128x64/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L3_Hijack_radio_128x64/meta.txt rename to assets/dolphin/external/L3_Hijack_radio_128x64/meta.txt diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_0.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_0.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_0.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_0.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_1.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_1.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_1.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_1.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_10.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_10.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_10.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_10.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_11.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_11.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_11.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_11.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_12.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_12.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_12.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_12.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_13.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_13.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_13.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_13.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_2.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_2.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_2.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_2.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_3.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_3.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_3.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_3.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_4.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_4.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_4.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_4.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_5.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_5.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_5.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_5.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_6.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_6.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_6.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_6.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_7.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_7.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_7.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_7.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_8.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_8.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_8.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_8.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_9.png b/assets/dolphin/external/L3_Lab_research_128x54/frame_9.png similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/frame_9.png rename to assets/dolphin/external/L3_Lab_research_128x54/frame_9.png diff --git a/assets/dolphin/external/sfw/L3_Lab_research_128x54/meta.txt b/assets/dolphin/external/L3_Lab_research_128x54/meta.txt similarity index 100% rename from assets/dolphin/external/sfw/L3_Lab_research_128x54/meta.txt rename to assets/dolphin/external/L3_Lab_research_128x54/meta.txt diff --git a/assets/dolphin/external/sfw/manifest.txt b/assets/dolphin/external/manifest.txt similarity index 100% rename from assets/dolphin/external/sfw/manifest.txt rename to assets/dolphin/external/manifest.txt diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png index 5104afb85..9a48d15f7 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_0.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png index 2b08366d6..b58936d81 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_1.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png index 12dc13430..5b474fff2 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_2.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png index f17f8713d..952f968fb 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_3.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png index 7a6992a2b..2bb43b306 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_4.png differ diff --git a/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png b/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png index 00d984300..d7f8c6402 100644 Binary files a/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png and b/assets/dolphin/internal/L1_NoSd_128x49/frame_5.png differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_00.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_00.png deleted file mode 100644 index bf97f8d6e..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_00.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_01.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_01.png deleted file mode 100644 index 39c910d3a..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_01.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_02.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_02.png deleted file mode 100644 index 4975adf86..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_02.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_03.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_03.png deleted file mode 100644 index 5a05529c5..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_03.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_04.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_04.png deleted file mode 100644 index e6c88df92..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_04.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_05.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_05.png deleted file mode 100644 index e7bae4d6c..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_05.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_06.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_06.png deleted file mode 100644 index 489bce368..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_06.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_07.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_07.png deleted file mode 100644 index 32e864e98..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_07.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_08.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_08.png deleted file mode 100644 index c692f4895..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_08.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_09.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_09.png deleted file mode 100644 index fb1c8bb90..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_09.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_10.png b/assets/icons/Animations/Levelup1_128x64_sfw/frame_10.png deleted file mode 100644 index 3b0205a48..000000000 Binary files a/assets/icons/Animations/Levelup1_128x64_sfw/frame_10.png and /dev/null differ diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_rate b/assets/icons/Animations/Levelup2_128x64_sfw/frame_rate deleted file mode 100644 index 0cfbf0888..000000000 --- a/assets/icons/Animations/Levelup2_128x64_sfw/frame_rate +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_00.png b/assets/icons/Animations/Levelup_128x64/frame_00.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_00.png rename to assets/icons/Animations/Levelup_128x64/frame_00.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_01.png b/assets/icons/Animations/Levelup_128x64/frame_01.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_01.png rename to assets/icons/Animations/Levelup_128x64/frame_01.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_02.png b/assets/icons/Animations/Levelup_128x64/frame_02.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_02.png rename to assets/icons/Animations/Levelup_128x64/frame_02.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_03.png b/assets/icons/Animations/Levelup_128x64/frame_03.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_03.png rename to assets/icons/Animations/Levelup_128x64/frame_03.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_04.png b/assets/icons/Animations/Levelup_128x64/frame_04.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_04.png rename to assets/icons/Animations/Levelup_128x64/frame_04.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_05.png b/assets/icons/Animations/Levelup_128x64/frame_05.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_05.png rename to assets/icons/Animations/Levelup_128x64/frame_05.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_06.png b/assets/icons/Animations/Levelup_128x64/frame_06.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_06.png rename to assets/icons/Animations/Levelup_128x64/frame_06.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_07.png b/assets/icons/Animations/Levelup_128x64/frame_07.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_07.png rename to assets/icons/Animations/Levelup_128x64/frame_07.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_08.png b/assets/icons/Animations/Levelup_128x64/frame_08.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_08.png rename to assets/icons/Animations/Levelup_128x64/frame_08.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_09.png b/assets/icons/Animations/Levelup_128x64/frame_09.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_09.png rename to assets/icons/Animations/Levelup_128x64/frame_09.png diff --git a/assets/icons/Animations/Levelup2_128x64_sfw/frame_10.png b/assets/icons/Animations/Levelup_128x64/frame_10.png similarity index 100% rename from assets/icons/Animations/Levelup2_128x64_sfw/frame_10.png rename to assets/icons/Animations/Levelup_128x64/frame_10.png diff --git a/assets/icons/Animations/Levelup1_128x64_sfw/frame_rate b/assets/icons/Animations/Levelup_128x64/frame_rate similarity index 100% rename from assets/icons/Animations/Levelup1_128x64_sfw/frame_rate rename to assets/icons/Animations/Levelup_128x64/frame_rate diff --git a/assets/icons/Archive/badusb_10px.png b/assets/icons/Archive/badkb_10px.png similarity index 100% rename from assets/icons/Archive/badusb_10px.png rename to assets/icons/Archive/badkb_10px.png diff --git a/assets/icons/BLE/BLE_Pairing_128x64.png b/assets/icons/BLE/BLE_Pairing_128x64.png index f60598005..34068c300 100644 Binary files a/assets/icons/BLE/BLE_Pairing_128x64.png and b/assets/icons/BLE/BLE_Pairing_128x64.png differ diff --git a/assets/icons/BLE/BLE_Pairing_128x64_sfw.png b/assets/icons/BLE/BLE_Pairing_128x64_sfw.png deleted file mode 100644 index 34068c300..000000000 Binary files a/assets/icons/BLE/BLE_Pairing_128x64_sfw.png and /dev/null differ diff --git a/assets/icons/BadUsb/Clock_18x18.png b/assets/icons/BadKb/Clock_18x18.png similarity index 100% rename from assets/icons/BadUsb/Clock_18x18.png rename to assets/icons/BadKb/Clock_18x18.png diff --git a/assets/icons/BadUsb/Error_18x18.png b/assets/icons/BadKb/Error_18x18.png similarity index 100% rename from assets/icons/BadUsb/Error_18x18.png rename to assets/icons/BadKb/Error_18x18.png diff --git a/assets/icons/BadUsb/EviSmile1_18x21.png b/assets/icons/BadKb/EviSmile1_18x21.png similarity index 100% rename from assets/icons/BadUsb/EviSmile1_18x21.png rename to assets/icons/BadKb/EviSmile1_18x21.png diff --git a/assets/icons/BadUsb/EviSmile2_18x21.png b/assets/icons/BadKb/EviSmile2_18x21.png similarity index 100% rename from assets/icons/BadUsb/EviSmile2_18x21.png rename to assets/icons/BadKb/EviSmile2_18x21.png diff --git a/assets/icons/BadUsb/EviWaiting1_18x21.png b/assets/icons/BadKb/EviWaiting1_18x21.png similarity index 100% rename from assets/icons/BadUsb/EviWaiting1_18x21.png rename to assets/icons/BadKb/EviWaiting1_18x21.png diff --git a/assets/icons/BadUsb/EviWaiting2_18x21.png b/assets/icons/BadKb/EviWaiting2_18x21.png similarity index 100% rename from assets/icons/BadUsb/EviWaiting2_18x21.png rename to assets/icons/BadKb/EviWaiting2_18x21.png diff --git a/assets/icons/BadUsb/Percent_10x14.png b/assets/icons/BadKb/Percent_10x14.png similarity index 100% rename from assets/icons/BadUsb/Percent_10x14.png rename to assets/icons/BadKb/Percent_10x14.png diff --git a/assets/icons/BadUsb/Smile_18x18.png b/assets/icons/BadKb/Smile_18x18.png similarity index 100% rename from assets/icons/BadUsb/Smile_18x18.png rename to assets/icons/BadKb/Smile_18x18.png diff --git a/assets/icons/BadUsb/UsbTree_48x22.png b/assets/icons/BadKb/UsbTree_48x22.png similarity index 100% rename from assets/icons/BadUsb/UsbTree_48x22.png rename to assets/icons/BadKb/UsbTree_48x22.png diff --git a/assets/icons/Dolphin/DolphinCommon_56x48.png b/assets/icons/Dolphin/DolphinCommon_56x48.png index e80fea5bd..089aaed83 100644 Binary files a/assets/icons/Dolphin/DolphinCommon_56x48.png and b/assets/icons/Dolphin/DolphinCommon_56x48.png differ diff --git a/assets/icons/Dolphin/DolphinCommon_56x48_sfw.png b/assets/icons/Dolphin/DolphinCommon_56x48_sfw.png deleted file mode 100644 index 089aaed83..000000000 Binary files a/assets/icons/Dolphin/DolphinCommon_56x48_sfw.png and /dev/null differ diff --git a/assets/icons/Infrared/DolphinReadingSuccess_59x63.png b/assets/icons/Infrared/DolphinReadingSuccess_59x63.png index 93a7ad79c..46f559f65 100644 Binary files a/assets/icons/Infrared/DolphinReadingSuccess_59x63.png and b/assets/icons/Infrared/DolphinReadingSuccess_59x63.png differ diff --git a/assets/icons/Infrared/DolphinReadingSuccess_59x63_sfw.png b/assets/icons/Infrared/DolphinReadingSuccess_59x63_sfw.png deleted file mode 100644 index 46f559f65..000000000 Binary files a/assets/icons/Infrared/DolphinReadingSuccess_59x63_sfw.png and /dev/null differ diff --git a/assets/icons/Interface/SmallArrowDown_4x7.png b/assets/icons/Interface/SmallArrowDown_4x7.png deleted file mode 100644 index 5c5252b16..000000000 Binary files a/assets/icons/Interface/SmallArrowDown_4x7.png and /dev/null differ diff --git a/assets/icons/Interface/SmallArrowUp_4x7.png b/assets/icons/Interface/SmallArrowUp_4x7.png deleted file mode 100644 index 886369abc..000000000 Binary files a/assets/icons/Interface/SmallArrowUp_4x7.png and /dev/null differ diff --git a/assets/icons/MainMenu/BadUsb_14/frame_01.png b/assets/icons/MainMenu/BadKb_14/frame_01.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_01.png rename to assets/icons/MainMenu/BadKb_14/frame_01.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_02.png b/assets/icons/MainMenu/BadKb_14/frame_02.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_02.png rename to assets/icons/MainMenu/BadKb_14/frame_02.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_03.png b/assets/icons/MainMenu/BadKb_14/frame_03.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_03.png rename to assets/icons/MainMenu/BadKb_14/frame_03.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_04.png b/assets/icons/MainMenu/BadKb_14/frame_04.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_04.png rename to assets/icons/MainMenu/BadKb_14/frame_04.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_05.png b/assets/icons/MainMenu/BadKb_14/frame_05.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_05.png rename to assets/icons/MainMenu/BadKb_14/frame_05.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_06.png b/assets/icons/MainMenu/BadKb_14/frame_06.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_06.png rename to assets/icons/MainMenu/BadKb_14/frame_06.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_07.png b/assets/icons/MainMenu/BadKb_14/frame_07.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_07.png rename to assets/icons/MainMenu/BadKb_14/frame_07.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_08.png b/assets/icons/MainMenu/BadKb_14/frame_08.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_08.png rename to assets/icons/MainMenu/BadKb_14/frame_08.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_09.png b/assets/icons/MainMenu/BadKb_14/frame_09.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_09.png rename to assets/icons/MainMenu/BadKb_14/frame_09.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_10.png b/assets/icons/MainMenu/BadKb_14/frame_10.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_10.png rename to assets/icons/MainMenu/BadKb_14/frame_10.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_11.png b/assets/icons/MainMenu/BadKb_14/frame_11.png similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_11.png rename to assets/icons/MainMenu/BadKb_14/frame_11.png diff --git a/assets/icons/MainMenu/BadUsb_14/frame_rate b/assets/icons/MainMenu/BadKb_14/frame_rate similarity index 100% rename from assets/icons/MainMenu/BadUsb_14/frame_rate rename to assets/icons/MainMenu/BadKb_14/frame_rate diff --git a/assets/icons/NFC/ArrowC_1_36x36.png b/assets/icons/NFC/ArrowC_1_36x36.png deleted file mode 100644 index 3a0c6dd0c..000000000 Binary files a/assets/icons/NFC/ArrowC_1_36x36.png and /dev/null differ diff --git a/assets/icons/NFC/Detailed_chip_17x13.png b/assets/icons/NFC/Detailed_chip_17x13.png deleted file mode 100644 index 9aaa1c555..000000000 Binary files a/assets/icons/NFC/Detailed_chip_17x13.png and /dev/null differ diff --git a/assets/icons/NFC/Medium-chip-22x21.png b/assets/icons/NFC/Medium-chip-22x21.png deleted file mode 100644 index b1f15432d..000000000 Binary files a/assets/icons/NFC/Medium-chip-22x21.png and /dev/null differ diff --git a/assets/icons/NFC/NFC_dolphin_emulation_47x61.png b/assets/icons/NFC/NFC_dolphin_emulation_47x61.png index e85b50f26..178353128 100644 Binary files a/assets/icons/NFC/NFC_dolphin_emulation_47x61.png and b/assets/icons/NFC/NFC_dolphin_emulation_47x61.png differ diff --git a/assets/icons/NFC/NFC_dolphin_emulation_47x61_sfw.png b/assets/icons/NFC/NFC_dolphin_emulation_47x61_sfw.png deleted file mode 100644 index 178353128..000000000 Binary files a/assets/icons/NFC/NFC_dolphin_emulation_47x61_sfw.png and /dev/null differ diff --git a/assets/icons/NFC/Tap_reader_36x38.png b/assets/icons/NFC/Tap_reader_36x38.png deleted file mode 100644 index 4e0ba8f05..000000000 Binary files a/assets/icons/NFC/Tap_reader_36x38.png and /dev/null differ diff --git a/assets/icons/Passport/passport_DB.png b/assets/icons/Passport/passport_DB.png index f813f2afd..69b2ac9ad 100644 Binary files a/assets/icons/Passport/passport_DB.png and b/assets/icons/Passport/passport_DB.png differ diff --git a/assets/icons/Passport/passport_DB_sfw.png b/assets/icons/Passport/passport_DB_sfw.png deleted file mode 100644 index 69b2ac9ad..000000000 Binary files a/assets/icons/Passport/passport_DB_sfw.png and /dev/null differ diff --git a/assets/icons/Passport/passport_bad1_46x49_sfw.png b/assets/icons/Passport/passport_bad1_46x49_sfw.png deleted file mode 100644 index 9b0e7c74e..000000000 Binary files a/assets/icons/Passport/passport_bad1_46x49_sfw.png and /dev/null differ diff --git a/assets/icons/Passport/passport_bad3_46x49_sfw.png b/assets/icons/Passport/passport_bad3_46x49_sfw.png deleted file mode 100644 index e39e6629d..000000000 Binary files a/assets/icons/Passport/passport_bad3_46x49_sfw.png and /dev/null differ diff --git a/assets/icons/Passport/passport_bad2_46x49_sfw.png b/assets/icons/Passport/passport_bad_46x49.png similarity index 100% rename from assets/icons/Passport/passport_bad2_46x49_sfw.png rename to assets/icons/Passport/passport_bad_46x49.png diff --git a/assets/icons/Passport/passport_happy1_46x49_sfw.png b/assets/icons/Passport/passport_happy1_46x49_sfw.png deleted file mode 100644 index 56ea000cd..000000000 Binary files a/assets/icons/Passport/passport_happy1_46x49_sfw.png and /dev/null differ diff --git a/assets/icons/Passport/passport_happy3_46x49_sfw.png b/assets/icons/Passport/passport_happy3_46x49_sfw.png deleted file mode 100644 index 7aef17674..000000000 Binary files a/assets/icons/Passport/passport_happy3_46x49_sfw.png and /dev/null differ diff --git a/assets/icons/Passport/passport_happy2_46x49_sfw.png b/assets/icons/Passport/passport_happy_46x49.png similarity index 100% rename from assets/icons/Passport/passport_happy2_46x49_sfw.png rename to assets/icons/Passport/passport_happy_46x49.png diff --git a/assets/icons/Passport/passport_okay1_46x49_sfw.png b/assets/icons/Passport/passport_okay1_46x49_sfw.png deleted file mode 100644 index 198ba5436..000000000 Binary files a/assets/icons/Passport/passport_okay1_46x49_sfw.png and /dev/null differ diff --git a/assets/icons/Passport/passport_okay3_46x49_sfw.png b/assets/icons/Passport/passport_okay3_46x49_sfw.png deleted file mode 100644 index e65da5b0e..000000000 Binary files a/assets/icons/Passport/passport_okay3_46x49_sfw.png and /dev/null differ diff --git a/assets/icons/Passport/passport_okay2_46x49_sfw.png b/assets/icons/Passport/passport_okay_46x49.png similarity index 100% rename from assets/icons/Passport/passport_okay2_46x49_sfw.png rename to assets/icons/Passport/passport_okay_46x49.png diff --git a/assets/icons/RFID/RFIDDolphinReceive_97x61.png b/assets/icons/RFID/RFIDDolphinReceive_97x61.png index 2528ebc95..e1f5f9f80 100644 Binary files a/assets/icons/RFID/RFIDDolphinReceive_97x61.png and b/assets/icons/RFID/RFIDDolphinReceive_97x61.png differ diff --git a/assets/icons/RFID/RFIDDolphinReceive_97x61_sfw.png b/assets/icons/RFID/RFIDDolphinReceive_97x61_sfw.png deleted file mode 100644 index e1f5f9f80..000000000 Binary files a/assets/icons/RFID/RFIDDolphinReceive_97x61_sfw.png and /dev/null differ diff --git a/assets/icons/RFID/RFIDDolphinSend_97x61.png b/assets/icons/RFID/RFIDDolphinSend_97x61.png index fef503263..380a970d9 100644 Binary files a/assets/icons/RFID/RFIDDolphinSend_97x61.png and b/assets/icons/RFID/RFIDDolphinSend_97x61.png differ diff --git a/assets/icons/RFID/RFIDDolphinSend_97x61_sfw.png b/assets/icons/RFID/RFIDDolphinSend_97x61_sfw.png deleted file mode 100644 index 380a970d9..000000000 Binary files a/assets/icons/RFID/RFIDDolphinSend_97x61_sfw.png and /dev/null differ diff --git a/assets/icons/RFID/RFIDDolphinSuccess_108x57.png b/assets/icons/RFID/RFIDDolphinSuccess_108x57.png index 78c4e93f8..341999109 100644 Binary files a/assets/icons/RFID/RFIDDolphinSuccess_108x57.png and b/assets/icons/RFID/RFIDDolphinSuccess_108x57.png differ diff --git a/assets/icons/RFID/RFIDDolphinSuccess_108x57_sfw.png b/assets/icons/RFID/RFIDDolphinSuccess_108x57_sfw.png deleted file mode 100644 index 341999109..000000000 Binary files a/assets/icons/RFID/RFIDDolphinSuccess_108x57_sfw.png and /dev/null differ diff --git a/assets/icons/Settings/Cry_dolph_55x52.png b/assets/icons/Settings/Cry_dolph_55x52.png index d1164c594..86d9db1b4 100644 Binary files a/assets/icons/Settings/Cry_dolph_55x52.png and b/assets/icons/Settings/Cry_dolph_55x52.png differ diff --git a/assets/icons/Settings/Cry_dolph_55x52_sfw.png b/assets/icons/Settings/Cry_dolph_55x52_sfw.png deleted file mode 100644 index 86d9db1b4..000000000 Binary files a/assets/icons/Settings/Cry_dolph_55x52_sfw.png and /dev/null differ diff --git a/assets/icons/StatusBar/Attention_5x8.png b/assets/icons/StatusBar/Attention_5x8.png deleted file mode 100644 index 137d4c4d0..000000000 Binary files a/assets/icons/StatusBar/Attention_5x8.png and /dev/null differ diff --git a/assets/icons/StatusBar/Charging-lightning_9x10.png b/assets/icons/StatusBar/Charging_lightning_9x10.png similarity index 100% rename from assets/icons/StatusBar/Charging-lightning_9x10.png rename to assets/icons/StatusBar/Charging_lightning_9x10.png diff --git a/assets/icons/StatusBar/Charging-lightning_mask_9x10.png b/assets/icons/StatusBar/Charging_lightning_mask_9x10.png similarity index 100% rename from assets/icons/StatusBar/Charging-lightning_mask_9x10.png rename to assets/icons/StatusBar/Charging_lightning_mask_9x10.png diff --git a/assets/icons/StatusBar/GameMode_11x8.png b/assets/icons/StatusBar/GameMode_11x8.png deleted file mode 100644 index 49f2e25bf..000000000 Binary files a/assets/icons/StatusBar/GameMode_11x8.png and /dev/null differ diff --git a/assets/icons/SubGhz/Scanning_123x52.png b/assets/icons/SubGhz/Scanning_123x52.png index a48c5330e..ec785948d 100644 Binary files a/assets/icons/SubGhz/Scanning_123x52.png and b/assets/icons/SubGhz/Scanning_123x52.png differ diff --git a/assets/icons/SubGhz/Scanning_123x52_sfw.png b/assets/icons/SubGhz/Scanning_123x52_sfw.png deleted file mode 100644 index ec785948d..000000000 Binary files a/assets/icons/SubGhz/Scanning_123x52_sfw.png and /dev/null differ diff --git a/assets/icons/U2F/Auth_62x31.png b/assets/icons/U2F/Auth_62x31.png index dd220bb65..40f094ac9 100644 Binary files a/assets/icons/U2F/Auth_62x31.png and b/assets/icons/U2F/Auth_62x31.png differ diff --git a/assets/icons/U2F/Auth_62x31_sfw.png b/assets/icons/U2F/Auth_62x31_sfw.png deleted file mode 100644 index 40f094ac9..000000000 Binary files a/assets/icons/U2F/Auth_62x31_sfw.png and /dev/null differ diff --git a/assets/icons/U2F/Connect_me_62x31.png b/assets/icons/U2F/Connect_me_62x31.png index 495e8ab55..68c48c0e6 100644 Binary files a/assets/icons/U2F/Connect_me_62x31.png and b/assets/icons/U2F/Connect_me_62x31.png differ diff --git a/assets/icons/U2F/Connect_me_62x31_sfw.png b/assets/icons/U2F/Connect_me_62x31_sfw.png deleted file mode 100644 index 68c48c0e6..000000000 Binary files a/assets/icons/U2F/Connect_me_62x31_sfw.png and /dev/null differ diff --git a/assets/icons/U2F/Connected_62x31.png b/assets/icons/U2F/Connected_62x31.png index bc1010ca9..eeaf660b1 100644 Binary files a/assets/icons/U2F/Connected_62x31.png and b/assets/icons/U2F/Connected_62x31.png differ diff --git a/assets/icons/U2F/Connected_62x31_sfw.png b/assets/icons/U2F/Connected_62x31_sfw.png deleted file mode 100644 index eeaf660b1..000000000 Binary files a/assets/icons/U2F/Connected_62x31_sfw.png and /dev/null differ diff --git a/assets/icons/U2F/Error_62x31.png b/assets/icons/U2F/Error_62x31.png index b78e010b7..bb280e751 100644 Binary files a/assets/icons/U2F/Error_62x31.png and b/assets/icons/U2F/Error_62x31.png differ diff --git a/assets/icons/U2F/Error_62x31_sfw.png b/assets/icons/U2F/Error_62x31_sfw.png deleted file mode 100644 index bb280e751..000000000 Binary files a/assets/icons/U2F/Error_62x31_sfw.png and /dev/null differ diff --git a/assets/icons/iButton/DolphinMafia_115x62.png b/assets/icons/iButton/DolphinMafia_115x62.png index e53a1c040..66fdb40ff 100644 Binary files a/assets/icons/iButton/DolphinMafia_115x62.png and b/assets/icons/iButton/DolphinMafia_115x62.png differ diff --git a/assets/icons/iButton/DolphinNice_96x59.png b/assets/icons/iButton/DolphinNice_96x59.png index 43cc58bd9..a299d3630 100644 Binary files a/assets/icons/iButton/DolphinNice_96x59.png and b/assets/icons/iButton/DolphinNice_96x59.png differ diff --git a/assets/icons/iButton/DolphinWait_61x59.png b/assets/icons/iButton/DolphinWait_61x59.png index 4beec55ef..423e07919 100644 Binary files a/assets/icons/iButton/DolphinWait_61x59.png and b/assets/icons/iButton/DolphinWait_61x59.png differ diff --git a/assets/icons/iButton/DolphinWait_61x59_sfw.png b/assets/icons/iButton/DolphinWait_61x59_sfw.png deleted file mode 100644 index 423e07919..000000000 Binary files a/assets/icons/iButton/DolphinWait_61x59_sfw.png and /dev/null differ diff --git a/assets/icons/iButton/iButtonDolphinVerySuccess_108x52.png b/assets/icons/iButton/iButtonDolphinVerySuccess_108x52.png index 90b589ff8..2b4bec7c6 100644 Binary files a/assets/icons/iButton/iButtonDolphinVerySuccess_108x52.png and b/assets/icons/iButton/iButtonDolphinVerySuccess_108x52.png differ diff --git a/assets/icons/iButton/iButtonDolphinVerySuccess_108x52_sfw.png b/assets/icons/iButton/iButtonDolphinVerySuccess_108x52_sfw.png deleted file mode 100644 index 2b4bec7c6..000000000 Binary files a/assets/icons/iButton/iButtonDolphinVerySuccess_108x52_sfw.png and /dev/null differ diff --git a/assets/resources/badkb/.badkb.settings b/assets/resources/badkb/.badkb.settings new file mode 100644 index 000000000..4841c2ded --- /dev/null +++ b/assets/resources/badkb/.badkb.settings @@ -0,0 +1 @@ +/any/badkb/layouts/en-US.kl diff --git a/assets/resources/badusb/Kiosk-Evasion-Bruteforce.txt b/assets/resources/badkb/Kiosk-Evasion-Bruteforce.txt similarity index 100% rename from assets/resources/badusb/Kiosk-Evasion-Bruteforce.txt rename to assets/resources/badkb/Kiosk-Evasion-Bruteforce.txt diff --git a/assets/resources/badusb/Wifi-Stealer_ORG.txt b/assets/resources/badkb/Wifi-Stealer_ORG.txt similarity index 100% rename from assets/resources/badusb/Wifi-Stealer_ORG.txt rename to assets/resources/badkb/Wifi-Stealer_ORG.txt diff --git a/assets/resources/badkb/demo_android.txt b/assets/resources/badkb/demo_android.txt new file mode 100644 index 000000000..2e4820490 --- /dev/null +++ b/assets/resources/badkb/demo_android.txt @@ -0,0 +1,14 @@ +REM Just another rickroll payload but for android +REM Credit: John Hickens + +GUI b +DELAY 600 +ENTER +DELAY 1000 +CTRL l +DELAY 100 +STRING https://github.com/ClaraCrazy/Flipper-Xtreme +DELAY 100 +ENTER +DELAY 500 +STRING f \ No newline at end of file diff --git a/assets/resources/badkb/demo_ios.txt b/assets/resources/badkb/demo_ios.txt new file mode 100644 index 000000000..17d0722d3 --- /dev/null +++ b/assets/resources/badkb/demo_ios.txt @@ -0,0 +1,24 @@ +REM Version 1.0 +REM OS: iOS +REM Author: Peaakss +REM Description: A simple payload that opens safari and inserts a link +REM NOTICE CHANGE "STRING" to your desired link | EXAMPLE: STRING https://github.com/ClaraCrazy/Flipper-Xtreme | +REM NOITCE Payload was made on iOS 16.1 - iPhone | Timing may have have to be changed based on version/model + +GUI h +DELAY 100 +GUI SPACE +DELAY 150 +BACKSPACE +DELAY 250 +STRING Safari +DELAY 100 +ENTER +DELAY 500 +GUI t +DELAY 250 +GUI l +DELAY 100 +STRING https://github.com/ClaraCrazy/Flipper-Xtreme +DELAY 250 +ENTER \ No newline at end of file diff --git a/assets/resources/badusb/demo_macos.txt b/assets/resources/badkb/demo_macos.txt similarity index 92% rename from assets/resources/badusb/demo_macos.txt rename to assets/resources/badkb/demo_macos.txt index 82543b28f..1fd4544b3 100644 --- a/assets/resources/badusb/demo_macos.txt +++ b/assets/resources/badkb/demo_macos.txt @@ -2,7 +2,7 @@ ID 1234:5678 Apple:Keyboard REM You can change these values to VID/PID of original Apple keyboard REM to bypass Keyboard Setup Assistant -REM This is BadUSB demo script for macOS +REM This is BadKB demo script for macOS REM Open terminal window DELAY 1000 @@ -75,7 +75,7 @@ ENTER HOME ENTER -STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format +STRING Flipper Zero BadKB feature is compatible with USB Rubber Ducky script format ENTER STRING More information about script syntax can be found here: ENTER diff --git a/assets/resources/badusb/demo_windows.txt b/assets/resources/badkb/demo_windows.txt similarity index 92% rename from assets/resources/badusb/demo_windows.txt rename to assets/resources/badkb/demo_windows.txt index 2ed33b3c0..f3b1309d1 100644 --- a/assets/resources/badusb/demo_windows.txt +++ b/assets/resources/badkb/demo_windows.txt @@ -1,4 +1,4 @@ -REM This is BadUSB demo script for windows +REM This is BadKB demo script for windows REM Open windows notepad DELAY 1000 @@ -76,7 +76,7 @@ ENTER HOME ENTER -STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format +STRING Flipper Zero BadKB feature is compatible with USB Rubber Ducky script format ENTER STRING More information about script syntax can be found here: ENTER diff --git a/assets/resources/badusb/layouts/ba-BA.kl b/assets/resources/badkb/layouts/ba-BA.kl similarity index 100% rename from assets/resources/badusb/layouts/ba-BA.kl rename to assets/resources/badkb/layouts/ba-BA.kl diff --git a/assets/resources/badusb/layouts/cz_CS.kl b/assets/resources/badkb/layouts/cz_CS.kl similarity index 100% rename from assets/resources/badusb/layouts/cz_CS.kl rename to assets/resources/badkb/layouts/cz_CS.kl diff --git a/assets/resources/badusb/layouts/da-DA.kl b/assets/resources/badkb/layouts/da-DA.kl similarity index 100% rename from assets/resources/badusb/layouts/da-DA.kl rename to assets/resources/badkb/layouts/da-DA.kl diff --git a/assets/resources/badusb/layouts/de-CH.kl b/assets/resources/badkb/layouts/de-CH.kl similarity index 100% rename from assets/resources/badusb/layouts/de-CH.kl rename to assets/resources/badkb/layouts/de-CH.kl diff --git a/assets/resources/badusb/layouts/de-DE.kl b/assets/resources/badkb/layouts/de-DE.kl similarity index 100% rename from assets/resources/badusb/layouts/de-DE.kl rename to assets/resources/badkb/layouts/de-DE.kl diff --git a/assets/resources/badusb/layouts/dvorak.kl b/assets/resources/badkb/layouts/dvorak.kl similarity index 100% rename from assets/resources/badusb/layouts/dvorak.kl rename to assets/resources/badkb/layouts/dvorak.kl diff --git a/assets/resources/badusb/layouts/en-UK.kl b/assets/resources/badkb/layouts/en-UK.kl similarity index 100% rename from assets/resources/badusb/layouts/en-UK.kl rename to assets/resources/badkb/layouts/en-UK.kl diff --git a/assets/resources/badusb/layouts/en-US.kl b/assets/resources/badkb/layouts/en-US.kl similarity index 100% rename from assets/resources/badusb/layouts/en-US.kl rename to assets/resources/badkb/layouts/en-US.kl diff --git a/assets/resources/badusb/layouts/es-ES.kl b/assets/resources/badkb/layouts/es-ES.kl similarity index 100% rename from assets/resources/badusb/layouts/es-ES.kl rename to assets/resources/badkb/layouts/es-ES.kl diff --git a/assets/resources/badusb/layouts/fr-BE.kl b/assets/resources/badkb/layouts/fr-BE.kl similarity index 100% rename from assets/resources/badusb/layouts/fr-BE.kl rename to assets/resources/badkb/layouts/fr-BE.kl diff --git a/assets/resources/badusb/layouts/fr-CH.kl b/assets/resources/badkb/layouts/fr-CH.kl similarity index 100% rename from assets/resources/badusb/layouts/fr-CH.kl rename to assets/resources/badkb/layouts/fr-CH.kl diff --git a/assets/resources/badusb/layouts/fr-FR.kl b/assets/resources/badkb/layouts/fr-FR.kl similarity index 100% rename from assets/resources/badusb/layouts/fr-FR.kl rename to assets/resources/badkb/layouts/fr-FR.kl diff --git a/assets/resources/badusb/layouts/hr-HR.kl b/assets/resources/badkb/layouts/hr-HR.kl similarity index 100% rename from assets/resources/badusb/layouts/hr-HR.kl rename to assets/resources/badkb/layouts/hr-HR.kl diff --git a/assets/resources/badusb/layouts/hu-HU.kl b/assets/resources/badkb/layouts/hu-HU.kl similarity index 100% rename from assets/resources/badusb/layouts/hu-HU.kl rename to assets/resources/badkb/layouts/hu-HU.kl diff --git a/assets/resources/badusb/layouts/it-IT.kl b/assets/resources/badkb/layouts/it-IT.kl similarity index 100% rename from assets/resources/badusb/layouts/it-IT.kl rename to assets/resources/badkb/layouts/it-IT.kl diff --git a/assets/resources/badusb/layouts/nb-NO.kl b/assets/resources/badkb/layouts/nb-NO.kl similarity index 100% rename from assets/resources/badusb/layouts/nb-NO.kl rename to assets/resources/badkb/layouts/nb-NO.kl diff --git a/assets/resources/badusb/layouts/nl-NL.kl b/assets/resources/badkb/layouts/nl-NL.kl similarity index 100% rename from assets/resources/badusb/layouts/nl-NL.kl rename to assets/resources/badkb/layouts/nl-NL.kl diff --git a/assets/resources/badusb/layouts/pt-BR.kl b/assets/resources/badkb/layouts/pt-BR.kl similarity index 100% rename from assets/resources/badusb/layouts/pt-BR.kl rename to assets/resources/badkb/layouts/pt-BR.kl diff --git a/assets/resources/badusb/layouts/pt-PT.kl b/assets/resources/badkb/layouts/pt-PT.kl similarity index 100% rename from assets/resources/badusb/layouts/pt-PT.kl rename to assets/resources/badkb/layouts/pt-PT.kl diff --git a/assets/resources/badusb/layouts/si-SI.kl b/assets/resources/badkb/layouts/si-SI.kl similarity index 100% rename from assets/resources/badusb/layouts/si-SI.kl rename to assets/resources/badkb/layouts/si-SI.kl diff --git a/assets/resources/badusb/layouts/sk-SK.kl b/assets/resources/badkb/layouts/sk-SK.kl old mode 100755 new mode 100644 similarity index 100% rename from assets/resources/badusb/layouts/sk-SK.kl rename to assets/resources/badkb/layouts/sk-SK.kl diff --git a/assets/resources/badusb/layouts/sv-SE.kl b/assets/resources/badkb/layouts/sv-SE.kl similarity index 100% rename from assets/resources/badusb/layouts/sv-SE.kl rename to assets/resources/badkb/layouts/sv-SE.kl diff --git a/assets/resources/badusb/layouts/tr-TR.kl b/assets/resources/badkb/layouts/tr-TR.kl similarity index 100% rename from assets/resources/badusb/layouts/tr-TR.kl rename to assets/resources/badkb/layouts/tr-TR.kl diff --git a/assets/resources/badusb/.badusb.settings b/assets/resources/badusb/.badusb.settings deleted file mode 100644 index 34330a3c0..000000000 --- a/assets/resources/badusb/.badusb.settings +++ /dev/null @@ -1 +0,0 @@ -/any/badusb/layouts/en-US.kl diff --git a/assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_0.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Boxing_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_1.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Boxing_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_2.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Boxing_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_3.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Boxing_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_4.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Boxing_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_5.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Boxing_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_6.bm b/assets/resources/dolphin/L1_Boxing_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Boxing_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Boxing_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Boxing_128x64/meta.txt b/assets/resources/dolphin/L1_Boxing_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Boxing_128x64/meta.txt rename to assets/resources/dolphin/L1_Boxing_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/frame_0.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Cry_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/frame_1.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Cry_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/frame_2.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Cry_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/frame_3.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Cry_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/frame_4.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Cry_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/frame_5.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Cry_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/frame_6.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Cry_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/frame_7.bm b/assets/resources/dolphin/L1_Cry_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Cry_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Cry_128x64/meta.txt b/assets/resources/dolphin/L1_Cry_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Cry_128x64/meta.txt rename to assets/resources/dolphin/L1_Cry_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_0.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_1.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_10.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_10.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_11.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_11.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_12.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_12.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_13.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_13.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_14.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_14.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_14.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_15.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_15.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_15.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_16.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_16.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_16.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_17.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_17.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_17.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_18.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_18.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_18.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_2.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_3.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_4.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_5.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_6.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_7.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_8.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_8.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_9.bm b/assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/frame_9.bm rename to assets/resources/dolphin/L1_Furippa1_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L1_Furippa1_128x64/meta.txt b/assets/resources/dolphin/L1_Furippa1_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Furippa1_128x64/meta.txt rename to assets/resources/dolphin/L1_Furippa1_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_0.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_1.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_10.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_10.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_11.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_11.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_12.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_12.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_2.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_3.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_4.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_5.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_6.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_7.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_8.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_8.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_9.bm b/assets/resources/dolphin/L1_Happy_holidays_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/frame_9.bm rename to assets/resources/dolphin/L1_Happy_holidays_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/meta.txt b/assets/resources/dolphin/L1_Happy_holidays_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Happy_holidays_128x64/meta.txt rename to assets/resources/dolphin/L1_Happy_holidays_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_0.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_0.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_1.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_1.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_2.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_2.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_3.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_3.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_4.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_4.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_5.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_5.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_6.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_6.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_7.bm b/assets/resources/dolphin/L1_Laptop_128x51/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/frame_7.bm rename to assets/resources/dolphin/L1_Laptop_128x51/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Laptop_128x51/meta.txt b/assets/resources/dolphin/L1_Laptop_128x51/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Laptop_128x51/meta.txt rename to assets/resources/dolphin/L1_Laptop_128x51/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_0.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_1.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_10.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_10.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_11.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_11.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_12.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_12.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_2.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_3.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_4.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_5.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_6.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_7.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_8.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_8.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_9.bm b/assets/resources/dolphin/L1_Leaving_sad_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/frame_9.bm rename to assets/resources/dolphin/L1_Leaving_sad_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/meta.txt b/assets/resources/dolphin/L1_Leaving_sad_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Leaving_sad_128x64/meta.txt rename to assets/resources/dolphin/L1_Leaving_sad_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_0.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_1.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_10.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_10.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_11.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_11.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_12.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_12.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_13.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_13.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_2.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_3.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_4.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_5.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_6.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_7.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_8.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_8.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_9.bm b/assets/resources/dolphin/L1_Mad_fist_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/frame_9.bm rename to assets/resources/dolphin/L1_Mad_fist_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L1_Mad_fist_128x64/meta.txt b/assets/resources/dolphin/L1_Mad_fist_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mad_fist_128x64/meta.txt rename to assets/resources/dolphin/L1_Mad_fist_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_0.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_1.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_10.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_10.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_11.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_11.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_12.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_12.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_13.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_13.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_14.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_14.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_14.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_14.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_15.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_15.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_15.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_15.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_16.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_16.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_16.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_16.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_17.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_17.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_17.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_17.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_18.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_18.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_18.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_18.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_19.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_19.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_19.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_19.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_2.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_20.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_20.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_20.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_20.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_21.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_21.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_21.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_21.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_22.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_22.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_22.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_22.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_23.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_23.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_23.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_23.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_24.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_24.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_24.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_24.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_25.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_25.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_25.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_25.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_26.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_26.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_26.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_26.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_27.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_27.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_27.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_27.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_28.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_28.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_28.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_28.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_29.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_29.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_29.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_29.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_3.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_30.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_30.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_30.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_30.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_31.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_31.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_31.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_31.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_32.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_32.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_32.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_32.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_33.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_33.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_33.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_33.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_34.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_34.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_34.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_34.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_35.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_35.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_35.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_35.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_36.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_36.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_36.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_36.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_37.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_37.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_37.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_37.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_38.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_38.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_38.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_38.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_39.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_39.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_39.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_39.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_4.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_40.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_40.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_40.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_40.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_5.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_6.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_7.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_8.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_8.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/frame_9.bm b/assets/resources/dolphin/L1_Mods_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/frame_9.bm rename to assets/resources/dolphin/L1_Mods_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L1_Mods_128x64/meta.txt b/assets/resources/dolphin/L1_Mods_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Mods_128x64/meta.txt rename to assets/resources/dolphin/L1_Mods_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_0.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_1.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_10.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_10.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_11.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_11.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_2.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_3.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_4.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_5.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_6.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_7.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_8.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_8.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/frame_9.bm b/assets/resources/dolphin/L1_Painting_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/frame_9.bm rename to assets/resources/dolphin/L1_Painting_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L1_Painting_128x64/meta.txt b/assets/resources/dolphin/L1_Painting_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Painting_128x64/meta.txt rename to assets/resources/dolphin/L1_Painting_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_0.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_1.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_2.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_3.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_4.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_5.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_6.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_7.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_8.bm b/assets/resources/dolphin/L1_Read_books_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/frame_8.bm rename to assets/resources/dolphin/L1_Read_books_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Read_books_128x64/meta.txt b/assets/resources/dolphin/L1_Read_books_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Read_books_128x64/meta.txt rename to assets/resources/dolphin/L1_Read_books_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_0.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_0.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_1.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_1.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_10.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_10.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_11.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_11.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_2.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_2.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_3.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_3.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_4.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_4.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_5.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_5.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_6.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_6.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_7.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_7.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_8.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_8.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/frame_9.bm b/assets/resources/dolphin/L1_Recording_128x51/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/frame_9.bm rename to assets/resources/dolphin/L1_Recording_128x51/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L1_Recording_128x51/meta.txt b/assets/resources/dolphin/L1_Recording_128x51/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Recording_128x51/meta.txt rename to assets/resources/dolphin/L1_Recording_128x51/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Sleep_128x64/frame_0.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleep_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Sleep_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleep_128x64/frame_1.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleep_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Sleep_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleep_128x64/frame_2.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleep_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Sleep_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleep_128x64/frame_3.bm b/assets/resources/dolphin/L1_Sleep_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleep_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Sleep_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleep_128x64/meta.txt b/assets/resources/dolphin/L1_Sleep_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleep_128x64/meta.txt rename to assets/resources/dolphin/L1_Sleep_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_0.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_0.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_1.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_1.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_10.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_10.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_11.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_11.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_12.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_12.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_13.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_13.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_14.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_14.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_14.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_14.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_15.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_15.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_15.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_15.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_16.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_16.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_16.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_16.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_17.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_17.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_17.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_17.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_18.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_18.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_18.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_18.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_19.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_19.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_19.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_19.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_2.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_2.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_20.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_20.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_20.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_20.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_21.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_21.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_21.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_21.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_22.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_22.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_22.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_22.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_23.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_23.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_23.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_23.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_24.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_24.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_24.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_24.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_25.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_25.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_25.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_25.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_26.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_26.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_26.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_26.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_27.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_27.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_27.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_27.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_28.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_28.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_28.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_28.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_29.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_29.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_29.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_29.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_3.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_3.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_30.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_30.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_30.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_30.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_31.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_31.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_31.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_31.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_32.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_32.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_32.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_32.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_33.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_33.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_33.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_33.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_34.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_34.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_34.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_34.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_35.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_35.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_35.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_35.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_36.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_36.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_36.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_36.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_4.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_4.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_5.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_5.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_6.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_6.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_7.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_7.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_8.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_8.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_9.bm b/assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/frame_9.bm rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/meta.txt b/assets/resources/dolphin/L1_Sleigh_ride_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Sleigh_ride_128x64/meta.txt rename to assets/resources/dolphin/L1_Sleigh_ride_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L1_Waves_128x50/frame_0.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Waves_128x50/frame_0.bm rename to assets/resources/dolphin/L1_Waves_128x50/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L1_Waves_128x50/frame_1.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Waves_128x50/frame_1.bm rename to assets/resources/dolphin/L1_Waves_128x50/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L1_Waves_128x50/frame_2.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Waves_128x50/frame_2.bm rename to assets/resources/dolphin/L1_Waves_128x50/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L1_Waves_128x50/frame_3.bm b/assets/resources/dolphin/L1_Waves_128x50/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L1_Waves_128x50/frame_3.bm rename to assets/resources/dolphin/L1_Waves_128x50/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L1_Waves_128x50/meta.txt b/assets/resources/dolphin/L1_Waves_128x50/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L1_Waves_128x50/meta.txt rename to assets/resources/dolphin/L1_Waves_128x50/meta.txt diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_0.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_0.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_1.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_1.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_10.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_10.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_11.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_11.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_12.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_12.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_13.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_13.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_14.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_14.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_14.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_15.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_15.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_15.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_16.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_16.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_16.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_17.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_17.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_17.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_18.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_18.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_18.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_2.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_2.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_3.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_3.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_4.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_4.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_5.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_5.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_6.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_6.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_7.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_7.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_8.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_8.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_9.bm b/assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/frame_9.bm rename to assets/resources/dolphin/L2_Furippa2_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L2_Furippa2_128x64/meta.txt b/assets/resources/dolphin/L2_Furippa2_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L2_Furippa2_128x64/meta.txt rename to assets/resources/dolphin/L2_Furippa2_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_0.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_0.bm rename to assets/resources/dolphin/L2_Hacking_pc_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_1.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_1.bm rename to assets/resources/dolphin/L2_Hacking_pc_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_2.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_2.bm rename to assets/resources/dolphin/L2_Hacking_pc_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_3.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_3.bm rename to assets/resources/dolphin/L2_Hacking_pc_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_4.bm b/assets/resources/dolphin/L2_Hacking_pc_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/frame_4.bm rename to assets/resources/dolphin/L2_Hacking_pc_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/meta.txt b/assets/resources/dolphin/L2_Hacking_pc_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L2_Hacking_pc_128x64/meta.txt rename to assets/resources/dolphin/L2_Hacking_pc_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_0.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_0.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_1.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_1.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_10.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_10.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_2.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_2.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_3.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_3.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_4.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_4.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_5.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_5.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_6.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_6.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_7.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_7.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_8.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_8.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_9.bm b/assets/resources/dolphin/L2_Soldering_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/frame_9.bm rename to assets/resources/dolphin/L2_Soldering_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L2_Soldering_128x64/meta.txt b/assets/resources/dolphin/L2_Soldering_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L2_Soldering_128x64/meta.txt rename to assets/resources/dolphin/L2_Soldering_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_0.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_0.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_1.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_1.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_10.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_10.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_11.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_11.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_12.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_12.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_13.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_13.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_14.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_14.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_14.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_14.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_15.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_15.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_15.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_15.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_16.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_16.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_16.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_16.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_17.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_17.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_17.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_17.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_18.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_18.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_18.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_18.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_19.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_19.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_19.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_19.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_2.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_2.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_20.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_20.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_20.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_20.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_3.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_3.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_4.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_4.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_5.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_5.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_6.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_6.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_7.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_7.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_8.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_8.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_9.bm b/assets/resources/dolphin/L2_Wake_up_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/frame_9.bm rename to assets/resources/dolphin/L2_Wake_up_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L2_Wake_up_128x64/meta.txt b/assets/resources/dolphin/L2_Wake_up_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L2_Wake_up_128x64/meta.txt rename to assets/resources/dolphin/L2_Wake_up_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_0.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_0.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_1.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_1.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_10.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_10.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_11.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_11.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_12.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_12.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_13.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_13.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_14.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_14.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_14.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_15.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_15.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_15.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_16.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_16.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_16.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_17.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_17.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_17.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_18.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_18.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_18.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_2.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_2.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_3.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_3.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_4.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_4.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_5.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_5.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_6.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_6.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_7.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_7.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_8.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_8.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_9.bm b/assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/frame_9.bm rename to assets/resources/dolphin/L3_Furippa3_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L3_Furippa3_128x64/meta.txt b/assets/resources/dolphin/L3_Furippa3_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L3_Furippa3_128x64/meta.txt rename to assets/resources/dolphin/L3_Furippa3_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_0.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_0.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_1.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_1.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_10.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_10.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_11.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_11.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_12.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_12.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_13.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_13.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_2.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_2.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_3.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_3.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_4.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_4.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_5.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_5.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_6.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_6.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_7.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_7.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_8.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_8.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_9.bm b/assets/resources/dolphin/L3_Hijack_radio_128x64/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/frame_9.bm rename to assets/resources/dolphin/L3_Hijack_radio_128x64/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/meta.txt b/assets/resources/dolphin/L3_Hijack_radio_128x64/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L3_Hijack_radio_128x64/meta.txt rename to assets/resources/dolphin/L3_Hijack_radio_128x64/meta.txt diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_0.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_0.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_0.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_0.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_1.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_1.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_1.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_1.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_10.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_10.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_10.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_10.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_11.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_11.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_11.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_11.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_12.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_12.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_12.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_12.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_13.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_13.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_13.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_13.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_2.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_2.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_2.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_2.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_3.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_3.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_3.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_3.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_4.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_4.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_4.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_4.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_5.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_5.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_5.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_5.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_6.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_6.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_6.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_6.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_7.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_7.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_7.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_7.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_8.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_8.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_8.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_8.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_9.bm b/assets/resources/dolphin/L3_Lab_research_128x54/frame_9.bm similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/frame_9.bm rename to assets/resources/dolphin/L3_Lab_research_128x54/frame_9.bm diff --git a/assets/resources/dolphin/sfw/L3_Lab_research_128x54/meta.txt b/assets/resources/dolphin/L3_Lab_research_128x54/meta.txt similarity index 100% rename from assets/resources/dolphin/sfw/L3_Lab_research_128x54/meta.txt rename to assets/resources/dolphin/L3_Lab_research_128x54/meta.txt diff --git a/assets/resources/dolphin/sfw/manifest.txt b/assets/resources/dolphin/manifest.txt similarity index 100% rename from assets/resources/dolphin/sfw/manifest.txt rename to assets/resources/dolphin/manifest.txt diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_21.bm diff --git a/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_22.bm new file mode 100644 index 000000000..63283c34a Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_22.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_23.bm new file mode 100644 index 000000000..843aed27c Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_23.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_24.bm new file mode 100644 index 000000000..ad87a3071 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_24.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_25.bm new file mode 100644 index 000000000..78de0389e Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_25.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_26.bm new file mode 100644 index 000000000..81738cccf Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_26.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_27.bm new file mode 100644 index 000000000..32bb893ca Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_27.bm differ diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/meta.txt similarity index 93% rename from assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/meta.txt index 6503043bd..fb0fdb228 100644 --- a/assets/resources/dolphin/nsfw/PaxGod_TikTok_Marketing/meta.txt +++ b/assets/resources/dolphin_custom/NSFW/Anims/PaxGod_TikTok_Marketing/meta.txt @@ -1,6 +1,5 @@ Filetype: Flipper Animation Version: 1 - Width: 128 Height: 64 Passive frames: 21 @@ -11,4 +10,4 @@ Frame rate: 5 Duration: 360 Active cooldown: 7 -Bubble slots: 0 +Bubble slots: 0 \ No newline at end of file diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_28.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_28.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_28.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_29.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_29.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_29.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_30.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_30.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_30.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_30.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_1/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_1/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_1/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_1/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_10/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_10/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_10/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_10/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_28.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_28.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_28.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_29.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_29.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_29.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_30.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_30.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_30.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_30.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_31.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_31.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_31.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_31.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_32.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_32.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_32.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_32.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_33.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_33.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_33.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_33.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_34.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_34.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_34.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_34.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_35.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_35.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_35.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_35.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_36.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_36.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_36.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_36.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_37.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_37.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_37.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_37.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_38.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_38.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_38.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_38.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_39.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_39.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_39.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_39.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_40.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_40.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_40.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_40.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_41.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_41.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_41.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_41.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_42.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_42.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_42.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_42.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_43.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_43.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_43.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_43.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_44.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_44.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_44.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_44.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_45.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_45.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_45.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_45.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_46.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_46.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_46.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_46.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_47.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_47.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_47.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_47.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_48.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_48.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_48.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_48.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_49.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_49.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_49.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_49.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_11/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_11/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_11/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_11/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_12/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_12/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_12/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_12/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_13/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_13/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_13/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_13/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_14/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_14/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_14/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_14/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_14/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_14/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_14/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_14/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_14/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_14/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_14/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_14/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_15/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_15/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_15/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_15/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_16/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_16/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_16/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_16/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_28.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_28.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_28.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_29.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_29.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_29.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_30.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_30.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_30.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_30.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_31.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_31.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_31.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_31.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_17/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_17/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_17/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_17/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_18/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_18/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_18/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_18/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_19/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_19/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_19/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_19/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_2/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_2/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_2/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_2/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_20/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_20/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_20/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_20/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_21/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_21/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_21/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_21/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_21/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_21/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_21/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_21/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_21/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_21/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_21/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_21/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_21/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_21/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_21/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_21/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_21/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_28.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_28.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_28.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_29.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_29.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_29.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_30.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_30.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_30.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_30.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_31.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_31.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_31.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_31.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_32.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_32.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_32.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_32.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_33.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_33.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_33.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_33.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_34.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_34.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_34.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_34.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_35.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_35.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_35.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_35.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_36.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_36.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_36.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_36.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_37.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_37.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_37.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_37.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_38.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_38.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_38.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_38.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_39.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_39.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_39.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_39.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_40.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_40.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_40.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_40.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_41.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_41.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_41.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_41.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_42.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_42.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_42.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_42.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_43.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_43.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_43.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_43.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_44.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_44.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_44.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_44.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_45.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_45.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_45.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_45.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_46.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_46.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_46.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_46.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_47.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_47.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_47.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_47.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_48.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_48.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_48.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_48.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_49.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_49.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_49.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_49.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_50.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_50.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_50.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_50.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_51.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_51.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_51.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_51.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_52.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_52.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_52.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_52.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_53.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_53.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_53.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_53.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_54.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_54.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_54.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_54.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_55.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_55.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_55.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_55.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_56.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_56.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_56.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_56.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_57.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_57.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_57.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_57.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_58.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_58.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_58.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_58.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_59.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_59.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_59.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_59.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_22/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_22/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_22/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_22/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_23/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_23/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_23/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_23/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_28.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_28.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_28.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_29.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_29.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_29.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_24/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_24/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_24/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_24/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_28.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_28.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_28.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_29.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_29.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_29.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_30.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_30.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_30.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_30.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_31.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_31.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_31.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_31.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_32.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_32.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_32.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_32.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_33.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_33.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_33.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_33.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_34.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_34.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_34.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_34.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_35.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_35.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_35.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_35.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_25/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_25/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_25/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_25/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_26/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_26/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_26/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_26/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_27/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_27/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_27/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_27/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_28/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_28/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_28/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_28/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_28/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_28/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_28/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_28/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_28/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_28/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_28/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_28/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_28/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_28/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_28/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_28/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_28/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_28.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_28.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_28.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_29.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_29.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_29.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_30.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_30.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_30.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_30.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_31.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_31.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_31.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_31.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_32.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_32.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_32.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_32.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_33.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_33.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_33.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_33.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_34.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_34.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_34.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_34.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_35.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_35.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_35.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_35.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_36.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_36.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_36.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_36.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_37.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_37.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_37.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_37.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_38.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_38.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_38.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_38.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_39.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_39.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_39.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_39.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_40.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_40.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_40.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_40.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_41.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_41.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_41.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_41.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_42.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_42.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_42.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_42.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_43.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_43.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_43.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_43.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_44.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_44.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_44.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_44.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_45.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_45.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_45.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_45.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_46.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_46.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_46.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_46.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_47.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_47.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_47.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_47.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_48.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_48.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_48.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_48.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_49.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_49.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_49.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_49.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_50.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_50.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_50.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_50.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_51.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_51.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_51.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_51.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_29/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_29/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_29/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_29/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_3/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_3/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_3/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_3/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_28.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_28.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_28.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_29.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_29.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_29.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_30.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_30.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_30.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_30.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_31.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_31.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_31.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_31.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_32.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_32.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_32.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_32.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_33.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_33.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_33.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_33.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_34.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_34.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_34.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_34.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_35.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_35.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_35.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_35.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_36.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_36.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_36.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_36.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_37.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_37.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_37.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_37.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_38.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_38.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_38.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_38.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_39.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_39.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_39.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_39.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_40.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_40.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_40.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_40.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_41.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_41.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_41.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_41.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_42.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_42.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_42.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_42.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_43.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_43.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_43.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_43.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_44.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_44.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_44.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_44.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_45.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_45.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_45.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_45.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_46.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_46.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_46.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_46.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_47.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_47.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_47.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_47.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_48.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_48.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_48.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_48.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_49.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_49.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_49.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_49.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_30/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_30/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_30/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_30/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_4/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_4/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_4/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_4/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_14.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_14.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_14.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_15.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_15.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_15.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_16.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_16.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_16.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_17.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_17.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_17.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_18.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_18.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_18.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_19.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_19.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_19.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_20.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_20.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_20.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_21.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_21.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_21.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_22.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_22.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_22.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_23.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_23.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_23.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_24.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_24.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_24.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_25.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_25.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_25.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_26.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_26.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_26.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_27.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_27.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_27.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_5/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_5/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_5/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_5/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_6/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_6/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_6/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_6/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_6/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_6/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_6/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_6/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_6/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_6/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_6/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_6/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_6/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_6/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_6/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_6/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_6/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_6/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_6/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_10.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_10.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_10.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_11.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_11.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_11.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_12.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_12.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_12.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_13.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_13.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_13.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_8.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_8.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_8.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_8.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/frame_9.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_9.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_7/frame_9.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/frame_9.bm diff --git a/assets/resources/dolphin/nsfw/lvl_7/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/meta.txt similarity index 92% rename from assets/resources/dolphin/nsfw/lvl_7/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_7/meta.txt index 43dd6af5a..f169de719 100644 --- a/assets/resources/dolphin/nsfw/lvl_7/meta.txt +++ b/assets/resources/dolphin_custom/NSFW/Anims/lvl_7/meta.txt @@ -11,4 +11,4 @@ Frame rate: 6 Duration: 360 Active cooldown: 0 -Bubble slots: 0 +Bubble slots: 0 \ No newline at end of file diff --git a/assets/resources/dolphin/nsfw/lvl_8/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_8/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_8/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_8/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_8/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_8/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_8/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_8/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_8/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_8/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_8/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_8/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_8/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_8/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_8/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_8/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_8/meta.txt diff --git a/assets/resources/dolphin/nsfw/lvl_9/frame_0.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_0.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/frame_0.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_0.bm diff --git a/assets/resources/dolphin/nsfw/lvl_9/frame_1.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_1.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/frame_1.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_1.bm diff --git a/assets/resources/dolphin/nsfw/lvl_9/frame_2.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_2.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/frame_2.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_2.bm diff --git a/assets/resources/dolphin/nsfw/lvl_9/frame_3.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_3.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/frame_3.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_3.bm diff --git a/assets/resources/dolphin/nsfw/lvl_9/frame_4.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_4.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/frame_4.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_4.bm diff --git a/assets/resources/dolphin/nsfw/lvl_9/frame_5.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_5.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/frame_5.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_5.bm diff --git a/assets/resources/dolphin/nsfw/lvl_9/frame_6.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_6.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/frame_6.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_6.bm diff --git a/assets/resources/dolphin/nsfw/lvl_9/frame_7.bm b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_7.bm similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/frame_7.bm rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/frame_7.bm diff --git a/assets/resources/dolphin/nsfw/lvl_9/meta.txt b/assets/resources/dolphin_custom/NSFW/Anims/lvl_9/meta.txt similarity index 100% rename from assets/resources/dolphin/nsfw/lvl_9/meta.txt rename to assets/resources/dolphin_custom/NSFW/Anims/lvl_9/meta.txt diff --git a/assets/resources/dolphin/nsfw/manifest.txt b/assets/resources/dolphin_custom/NSFW/Anims/manifest.txt similarity index 100% rename from assets/resources/dolphin/nsfw/manifest.txt rename to assets/resources/dolphin_custom/NSFW/Anims/manifest.txt diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_00.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_00.bm new file mode 100644 index 000000000..d39d7c709 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_00.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_01.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_01.bm new file mode 100644 index 000000000..c3bea7837 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_01.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_02.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_02.bm new file mode 100644 index 000000000..83fb1ac60 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_02.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_03.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_03.bm new file mode 100644 index 000000000..feb5ab082 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_03.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_04.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_04.bm new file mode 100644 index 000000000..8929aaaf6 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_04.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_05.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_05.bm new file mode 100644 index 000000000..2a9700a8e Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_05.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_06.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_06.bm new file mode 100644 index 000000000..d6ceacd02 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_06.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_07.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_07.bm new file mode 100644 index 000000000..b4a87c26b Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_07.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_08.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_08.bm new file mode 100644 index 000000000..4293da705 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_08.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_09.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_09.bm new file mode 100644 index 000000000..b73177b87 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_09.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_10.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_10.bm new file mode 100644 index 000000000..feb5ab082 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_10.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_11.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_11.bm new file mode 100644 index 000000000..8929aaaf6 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_11.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_12.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_12.bm new file mode 100644 index 000000000..2a9700a8e Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_12.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_13.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_13.bm new file mode 100644 index 000000000..d6ceacd02 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_13.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_14.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_14.bm new file mode 100644 index 000000000..b4a87c26b Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_14.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_15.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_15.bm new file mode 100644 index 000000000..4293da705 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_15.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_16.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_16.bm new file mode 100644 index 000000000..b73177b87 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_16.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_17.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_17.bm new file mode 100644 index 000000000..d39d7c709 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_17.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_18.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_18.bm new file mode 100644 index 000000000..c3bea7837 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_18.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_19.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_19.bm new file mode 100644 index 000000000..83fb1ac60 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_19.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_20.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_20.bm new file mode 100644 index 000000000..d39d7c709 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_20.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_21.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_21.bm new file mode 100644 index 000000000..c3bea7837 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_21.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_22.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_22.bm new file mode 100644 index 000000000..83fb1ac60 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_22.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_23.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_23.bm new file mode 100644 index 000000000..feb5ab082 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_23.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_24.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_24.bm new file mode 100644 index 000000000..8929aaaf6 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_24.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_25.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_25.bm new file mode 100644 index 000000000..2a9700a8e Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_25.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_26.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_26.bm new file mode 100644 index 000000000..d6ceacd02 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_26.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_27.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_27.bm new file mode 100644 index 000000000..b4a87c26b Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_27.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_28.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_28.bm new file mode 100644 index 000000000..4293da705 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_28.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_29.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_29.bm new file mode 100644 index 000000000..b73177b87 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_29.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_30.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_30.bm new file mode 100644 index 000000000..feb5ab082 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_30.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_31.bm b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_31.bm new file mode 100644 index 000000000..4e8a8694d Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/frame_31.bm differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/meta b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/meta new file mode 100644 index 000000000..485a421b6 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Animations/Levelup_128x64/meta differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/BLE/BLE_Pairing_128x64.bmx b/assets/resources/dolphin_custom/NSFW/Icons/BLE/BLE_Pairing_128x64.bmx new file mode 100644 index 000000000..4ab6aef41 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/BLE/BLE_Pairing_128x64.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Dolphin/DolphinCommon_56x48.bmx b/assets/resources/dolphin_custom/NSFW/Icons/Dolphin/DolphinCommon_56x48.bmx new file mode 100644 index 000000000..818b00500 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Dolphin/DolphinCommon_56x48.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Infrared/DolphinReadingSuccess_59x63.bmx b/assets/resources/dolphin_custom/NSFW/Icons/Infrared/DolphinReadingSuccess_59x63.bmx new file mode 100644 index 000000000..9dc1e5dcf Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Infrared/DolphinReadingSuccess_59x63.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/NFC/NFC_dolphin_emulation_47x61.bmx b/assets/resources/dolphin_custom/NSFW/Icons/NFC/NFC_dolphin_emulation_47x61.bmx new file mode 100644 index 000000000..03c6304a2 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/NFC/NFC_dolphin_emulation_47x61.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_DB.bmx b/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_DB.bmx new file mode 100644 index 000000000..8af359b94 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_DB.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_bad_46x49.bmx b/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_bad_46x49.bmx new file mode 100644 index 000000000..715815f0c Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_bad_46x49.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_happy_46x49.bmx b/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_happy_46x49.bmx new file mode 100644 index 000000000..715815f0c Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_happy_46x49.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_okay_46x49.bmx b/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_okay_46x49.bmx new file mode 100644 index 000000000..715815f0c Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Passport/passport_okay_46x49.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinReceive_97x61.bmx b/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinReceive_97x61.bmx new file mode 100644 index 000000000..cb92216c4 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinReceive_97x61.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinSend_97x61.bmx b/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinSend_97x61.bmx new file mode 100644 index 000000000..8932c5ed3 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinSend_97x61.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinSuccess_108x57.bmx b/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinSuccess_108x57.bmx new file mode 100644 index 000000000..3eefd86bc Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/RFID/RFIDDolphinSuccess_108x57.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/Settings/Cry_dolph_55x52.bmx b/assets/resources/dolphin_custom/NSFW/Icons/Settings/Cry_dolph_55x52.bmx new file mode 100644 index 000000000..22a76dd4d Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/Settings/Cry_dolph_55x52.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/SubGhz/Scanning_123x52.bmx b/assets/resources/dolphin_custom/NSFW/Icons/SubGhz/Scanning_123x52.bmx new file mode 100644 index 000000000..75f57367c Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/SubGhz/Scanning_123x52.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/U2F/Auth_62x31.bmx b/assets/resources/dolphin_custom/NSFW/Icons/U2F/Auth_62x31.bmx new file mode 100644 index 000000000..a13ee8f9d Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/U2F/Auth_62x31.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/U2F/Connect_me_62x31.bmx b/assets/resources/dolphin_custom/NSFW/Icons/U2F/Connect_me_62x31.bmx new file mode 100644 index 000000000..0f5f60859 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/U2F/Connect_me_62x31.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/U2F/Connected_62x31.bmx b/assets/resources/dolphin_custom/NSFW/Icons/U2F/Connected_62x31.bmx new file mode 100644 index 000000000..e4c689eb6 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/U2F/Connected_62x31.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/U2F/Error_62x31.bmx b/assets/resources/dolphin_custom/NSFW/Icons/U2F/Error_62x31.bmx new file mode 100644 index 000000000..b6bc02baa Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/U2F/Error_62x31.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinMafia_115x62.bmx b/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinMafia_115x62.bmx new file mode 100644 index 000000000..c37cd533d Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinMafia_115x62.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinNice_96x59.bmx b/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinNice_96x59.bmx new file mode 100644 index 000000000..1c7e5c607 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinNice_96x59.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinWait_61x59.bmx b/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinWait_61x59.bmx new file mode 100644 index 000000000..5f5626f35 Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/iButton/DolphinWait_61x59.bmx differ diff --git a/assets/resources/dolphin_custom/NSFW/Icons/iButton/iButtonDolphinVerySuccess_108x52.bmx b/assets/resources/dolphin_custom/NSFW/Icons/iButton/iButtonDolphinVerySuccess_108x52.bmx new file mode 100644 index 000000000..47b611a6a Binary files /dev/null and b/assets/resources/dolphin_custom/NSFW/Icons/iButton/iButtonDolphinVerySuccess_108x52.bmx differ diff --git a/assets/resources/dolphin_custom/WatchDogs/Icons/RFID/rfid_success.bmx b/assets/resources/dolphin_custom/WatchDogs/Icons/RFID/RFIDDolphinSuccess_108x57.bmx similarity index 100% rename from assets/resources/dolphin_custom/WatchDogs/Icons/RFID/rfid_success.bmx rename to assets/resources/dolphin_custom/WatchDogs/Icons/RFID/RFIDDolphinSuccess_108x57.bmx diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 20a72e0ca..4d9a85041 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 13th Jan, 2023 -# Last Checked 13th Jan, 2023 +# Last Checked 31th Jan, 2023 # name: POWER type: raw @@ -1541,4 +1541,78 @@ name: TEMP- type: raw frequency: 38000 duty_cycle: 0.330000 -data: 3110 1567 551 1031 550 356 471 1032 550 356 471 356 445 1084 497 355 472 357 497 356 472 1058 523 1058 523 356 471 356 470 357 469 357 470 357 474 357 470 1063 519 357 470 1063 518 1063 519 1063 518 357 470 357 471 +data: 2320 634 837 637 838 637 838 640 835 642 832 1378 836 645 826 670 809 667 808 1406 806 672 803 674 802 1412 802 1412 800 676 801 675 802 1412 802 674 802 1413 801 1412 801 1413 802 1412 802 50937 2285 671 801 1411 802 51225 2280 696 775 1412 801 51212 2283 671 775 1412 802 +# Model: Daikin FTXM20M. +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 500 393 473 392 473 368 498 368 497 367 499 25050 3533 1662 502 1230 501 392 472 393 471 395 469 1263 467 400 465 401 465 401 465 401 465 1267 465 401 465 1268 464 1268 464 402 464 1268 464 1269 463 1269 463 1292 440 1269 463 404 462 426 439 1293 439 426 440 426 440 426 440 426 440 426 440 427 439 426 440 427 439 427 438 427 439 1294 438 427 439 1294 438 427 439 427 439 428 438 1294 438 1294 438 428 438 428 437 428 438 428 438 1294 438 428 438 428 438 429 437 429 437 429 436 429 437 429 437 429 437 429 436 429 437 430 436 1296 436 1296 436 1296 436 430 436 430 435 1297 435 1297 435 1298 434 35482 3500 1699 464 1268 464 402 463 402 463 403 463 1269 463 426 440 426 439 426 440 426 439 1293 439 426 440 1293 439 1293 439 427 439 1293 439 1293 439 1293 439 1293 439 1294 438 427 438 427 439 1294 438 427 439 428 438 428 438 428 438 427 438 428 438 428 437 428 438 428 437 428 438 428 438 1295 437 429 437 429 437 429 436 429 437 1296 436 429 437 429 436 429 437 430 436 430 436 430 435 430 436 430 435 431 435 431 435 431 435 455 410 456 409 1322 410 456 409 456 410 456 410 456 410 456 410 1323 409 457 409 457 409 1323 409 1323 409 457 409 35483 3500 1699 464 1268 464 402 464 402 463 403 463 1269 463 426 440 426 440 426 440 426 439 1293 439 426 439 1293 439 1293 439 427 439 1293 439 1293 439 1293 439 1294 438 1293 438 427 439 427 438 1294 438 428 438 427 438 428 438 428 438 428 438 428 437 428 438 428 438 428 438 428 438 428 438 428 438 429 437 429 437 429 437 429 437 429 437 429 437 429 437 429 437 430 436 1296 436 430 436 1297 435 430 436 430 436 431 435 431 435 456 410 456 410 456 410 456 409 1323 409 1322 410 456 410 456 409 457 409 457 409 457 409 457 409 457 408 457 409 1324 408 1324 408 1324 408 1324 408 458 408 1325 406 459 407 1351 356 1376 356 1376 356 1376 356 1377 355 510 355 510 356 511 355 511 354 511 355 537 328 537 329 538 328 538 327 538 328 539 327 565 300 566 300 1432 300 1433 298 593 272 594 271 621 245 621 244 622 243 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 500 368 498 369 497 367 499 366 499 367 499 25050 3533 1662 502 1230 501 392 472 393 471 395 469 1264 467 400 465 401 465 401 465 401 465 1267 465 401 465 1268 464 1268 464 402 464 1269 463 1269 463 1269 463 1292 440 1292 440 426 440 426 440 1293 439 426 440 426 439 426 440 426 440 427 439 427 438 427 439 427 439 427 439 427 439 1293 439 427 439 1294 438 427 439 427 439 428 437 1294 438 1294 438 428 437 428 438 428 437 429 437 1295 437 428 437 429 437 429 437 429 436 429 437 429 437 429 437 429 437 429 437 429 437 430 436 1296 436 1297 435 1297 435 431 435 455 410 1298 434 1322 410 1322 410 35482 3500 1700 464 1269 463 403 463 403 463 403 462 1292 440 426 440 426 440 426 440 426 439 1293 439 426 440 1293 439 1293 439 427 439 1293 439 1293 439 1293 439 1293 439 1293 439 427 439 427 439 1294 438 427 439 427 439 427 439 428 438 427 438 428 438 428 438 428 437 428 438 428 438 428 438 1295 437 429 437 429 436 429 437 429 437 1296 436 429 437 429 437 429 437 430 436 430 436 430 436 431 435 431 435 431 435 455 410 456 410 456 410 456 410 1322 410 456 410 456 410 456 409 457 409 456 409 1323 409 457 409 457 409 1323 409 1324 408 458 408 35483 3500 1700 464 1268 464 402 464 403 463 402 464 1292 440 426 440 426 440 426 439 426 440 1293 439 426 440 1293 439 1293 439 427 439 1293 439 1293 439 1293 438 1293 439 1293 439 427 439 427 438 1294 438 428 438 428 438 427 438 428 438 428 438 428 438 428 438 428 438 428 438 428 437 428 438 429 436 429 437 429 437 429 437 429 437 429 437 429 437 1296 436 430 435 430 436 1297 435 431 435 1297 435 431 435 456 409 456 410 456 409 456 410 456 410 456 410 456 410 1323 409 1323 409 457 409 457 409 457 408 457 409 457 409 458 408 458 407 458 408 1325 407 1326 405 1327 406 1351 381 485 356 1376 356 510 355 1377 355 1377 355 1377 355 1378 354 1378 354 512 354 512 354 538 327 538 328 538 328 539 326 565 300 566 300 566 299 567 299 593 272 621 244 596 270 1488 244 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 504 389 477 364 501 364 502 364 501 364 502 25048 3511 1684 505 1228 504 389 475 390 474 392 472 1260 470 396 469 396 470 396 469 397 469 1263 469 397 469 1263 469 1263 469 397 468 1263 469 1263 469 1264 468 1263 469 1264 468 397 468 398 468 1264 468 398 468 398 468 398 468 398 468 398 468 399 467 398 468 399 467 423 443 400 466 1289 443 423 443 1289 443 423 443 423 443 423 443 1289 443 1290 442 424 442 423 442 423 443 424 442 1290 442 424 442 423 443 424 442 424 441 424 442 424 441 424 442 424 442 424 441 424 442 424 442 1291 441 1291 441 1291 441 425 441 425 441 1291 441 1291 441 1291 441 35478 3505 1695 468 1264 468 398 467 398 468 398 468 1265 467 398 467 398 468 398 468 399 467 1265 467 399 467 1266 466 1266 466 423 443 1289 443 1290 442 1290 442 1290 442 1290 442 424 442 423 442 1290 442 423 443 424 442 424 442 424 442 424 441 424 442 424 442 424 441 424 442 424 442 424 442 1291 441 425 441 425 441 424 442 424 441 1291 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 440 426 440 426 440 1292 440 426 440 426 440 426 440 426 439 427 439 1293 439 427 439 427 438 1294 438 1294 438 428 437 35479 3504 1695 468 1264 468 398 468 398 468 398 467 1265 467 399 467 399 467 399 466 399 467 1265 467 399 467 1289 443 1290 442 423 443 1290 442 1290 442 1290 442 1290 442 1290 442 423 443 424 442 1290 442 424 442 424 442 424 441 424 442 424 442 424 442 424 442 424 442 424 442 424 442 424 442 424 442 425 441 425 440 425 441 425 441 425 441 425 441 1291 441 425 441 425 441 1292 440 1292 440 1292 440 426 440 425 441 426 440 426 440 1292 440 426 440 426 440 1292 440 426 440 426 440 426 440 427 439 426 440 426 440 427 438 427 439 427 439 427 439 1294 438 1295 437 1294 438 1319 413 453 413 1319 413 453 412 1320 412 1319 413 1319 413 1319 413 1320 412 453 412 453 413 453 412 454 412 454 411 454 412 454 412 454 412 454 412 454 412 455 411 454 412 455 411 1321 411 1321 411 456 409 456 410 481 384 482 384 482 383 482 359 506 360 507 359 507 359 507 358 1374 358 1374 358 508 357 508 358 509 357 534 332 534 332 534 332 534 332 535 331 535 331 535 331 535 330 536 330 536 330 562 303 563 303 563 302 564 302 1430 302 565 301 564 302 591 274 619 247 619 247 1512 219 1539 190 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 502 390 476 365 501 365 500 365 500 365 501 25049 3535 1660 504 1229 502 390 474 391 473 393 471 1261 469 397 468 398 468 398 468 398 468 1264 468 398 468 1265 467 1265 467 399 467 1265 467 1265 467 1265 467 1266 466 1265 467 400 466 401 465 1266 466 401 465 401 465 401 465 424 442 424 441 424 442 424 441 424 442 424 442 424 442 1291 441 424 442 1291 441 424 442 425 440 425 441 1291 441 1291 441 425 441 425 441 425 440 425 441 1292 440 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 440 426 440 426 440 426 440 1292 440 1293 439 1293 439 426 439 427 439 1293 439 1293 439 1293 439 35480 3503 1696 467 1265 467 399 467 398 468 399 466 1266 466 399 467 399 467 399 467 399 467 1266 466 400 466 1267 465 1290 442 424 442 1290 442 1290 442 1290 442 1290 441 1291 441 424 442 424 442 1291 441 424 442 424 442 425 441 424 442 424 442 425 441 425 440 425 441 425 441 425 441 425 441 1292 440 425 441 425 441 425 440 426 440 1292 440 426 440 426 439 426 440 426 439 426 440 426 440 426 440 426 440 426 440 427 438 427 439 427 439 427 439 1293 439 427 438 427 439 428 438 428 438 428 438 1294 438 428 438 428 438 1295 437 1320 412 453 413 35480 3503 1696 467 1265 467 399 467 399 467 399 467 1266 466 399 467 399 467 400 466 400 466 1290 442 424 442 1289 443 1290 442 424 442 1291 441 1290 442 1290 442 1291 441 1291 441 424 442 424 442 1291 441 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 440 426 440 426 440 426 440 1292 440 426 440 426 440 1292 440 1293 439 1293 439 427 439 426 439 427 439 1293 439 1293 439 1293 439 427 438 1294 438 427 439 427 438 428 438 427 438 453 413 429 437 429 437 429 437 453 412 454 412 1320 412 1320 412 1320 412 1320 412 454 412 1321 411 454 412 1320 412 1321 411 1321 411 1321 411 1321 411 455 410 455 411 455 411 455 411 455 411 456 410 456 410 457 409 481 384 457 409 482 383 483 383 483 358 1374 358 1374 358 508 357 508 358 509 357 509 357 509 357 509 357 510 356 535 330 536 330 536 330 1402 330 1403 329 537 329 536 329 563 302 564 302 564 302 565 300 565 300 592 273 619 246 620 246 619 246 620 245 674 188 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 504 365 500 365 500 365 500 365 501 365 501 25049 3535 1660 504 1229 502 390 474 391 473 393 471 1261 470 397 468 397 469 398 468 398 468 1264 468 398 467 1265 467 1265 467 398 468 1265 467 1265 467 1265 467 1266 466 1266 466 399 466 399 467 1266 466 400 466 400 466 400 465 400 466 424 442 424 442 424 442 424 441 424 442 424 442 1291 441 424 442 1291 441 424 442 424 442 425 441 1291 441 1291 441 425 440 425 441 425 441 425 440 1292 440 425 441 425 440 425 441 425 441 425 441 425 441 425 441 426 440 426 440 426 440 426 439 1293 439 1293 439 1293 439 426 440 427 439 1293 439 1293 439 1293 439 35480 3503 1696 468 1264 468 398 468 398 468 398 467 1265 467 399 467 399 467 399 467 399 467 1267 465 400 466 1266 466 1267 465 424 441 1290 442 1290 442 1290 442 1290 442 1291 441 424 442 424 442 1291 441 424 442 424 442 424 442 424 442 424 441 425 441 425 441 425 441 425 441 425 441 425 441 1292 440 425 441 425 441 425 441 425 441 1292 440 426 440 426 439 426 440 426 440 426 439 426 440 426 440 426 439 427 439 426 440 427 439 427 439 427 438 1293 439 427 439 427 439 427 439 428 438 428 438 1295 437 428 438 429 436 1296 436 1296 436 453 412 35481 3502 1696 467 1265 467 399 466 399 467 399 467 1265 467 399 467 399 467 399 466 400 466 1266 466 400 466 1290 442 1267 465 424 442 1290 442 1290 442 1290 442 1290 442 1291 441 424 442 424 441 1291 441 424 442 424 442 424 442 424 441 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 441 425 440 426 440 425 441 425 441 425 441 426 440 1292 440 426 440 426 440 1292 440 426 440 426 439 1293 439 427 439 427 439 427 439 1293 439 1294 438 1294 438 1293 439 427 439 428 438 428 438 428 438 429 436 429 437 429 437 453 412 453 413 453 412 1320 412 1320 412 1320 412 1320 412 454 412 1320 412 454 412 1321 411 1321 411 1321 411 1321 411 1322 410 455 411 455 411 456 410 456 410 455 410 456 410 456 409 481 384 458 408 482 383 482 384 483 358 508 358 1374 358 1374 358 508 357 509 357 509 357 510 355 535 330 536 330 536 330 536 329 536 330 536 330 1403 329 1430 301 564 302 564 302 564 301 591 274 566 301 592 273 619 247 619 247 620 245 647 219 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 503 365 500 364 501 366 499 365 500 364 502 25049 3535 1660 504 1228 503 390 474 391 473 393 471 1261 469 397 468 397 469 397 469 397 469 1264 468 398 468 1264 468 1264 468 398 468 1265 467 1265 467 1265 467 1265 467 1265 467 399 467 399 467 1266 466 399 467 400 466 400 466 400 466 423 443 423 443 401 465 423 442 424 442 424 442 1290 442 424 442 1290 442 424 442 424 441 424 442 1290 442 1291 441 425 441 424 442 425 441 425 441 1291 441 425 440 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 426 440 1292 440 1292 440 1292 440 426 440 426 440 1292 440 1293 439 1293 439 35480 3503 1696 467 1264 468 398 468 398 467 398 468 1265 467 398 467 399 467 399 466 399 467 1265 467 399 467 1266 466 1267 465 400 466 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 442 1290 442 424 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 425 441 425 441 1291 441 425 441 425 441 425 441 425 440 1292 440 425 441 425 440 426 440 426 440 426 440 426 440 426 440 426 440 426 440 426 439 427 439 426 440 426 440 1293 439 427 439 427 439 427 438 427 439 428 438 1294 438 428 437 428 438 1295 437 1319 413 453 413 35480 3503 1696 468 1265 467 398 468 398 468 398 468 1265 467 398 468 399 466 399 467 399 467 1266 466 399 466 1267 465 1290 442 401 465 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 441 1291 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 424 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 441 1292 440 426 440 426 440 1292 440 426 440 426 440 1293 439 426 440 426 440 1293 439 1293 439 1293 439 427 439 1294 438 427 438 427 439 427 438 428 438 428 438 428 438 428 438 453 413 429 437 453 413 1319 413 1320 412 1320 412 1320 412 454 412 1320 412 454 412 1321 411 1321 411 1321 411 1321 411 1321 411 455 410 455 411 455 411 455 410 456 410 456 410 456 410 481 384 481 385 482 383 482 383 483 358 507 359 1374 358 1374 358 508 358 508 358 508 358 509 357 509 357 535 331 535 331 535 330 535 330 536 330 1403 329 1403 329 563 302 564 301 564 302 564 301 565 301 591 274 619 246 593 273 620 245 620 245 621 245 673 189 +# Model: Mitsubishi SRK63HE. +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3232 1526 463 334 462 1127 464 334 460 334 461 1128 463 336 459 1128 464 359 436 359 436 1133 458 1156 434 1157 434 362 433 1159 432 363 432 1159 432 1159 432 1159 432 363 433 363 432 363 432 363 432 1160 431 1160 432 363 432 1160 431 1160 431 363 432 364 432 1160 431 363 432 363 432 1160 432 363 432 364 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 1160 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 364 432 364 432 364 431 364 431 1160 432 364 432 364 431 364 431 1160 431 1160 431 1160 431 364 431 1161 430 1161 430 1160 431 1161 430 364 432 364 431 365 431 1161 430 364 431 365 431 364 431 365 430 365 431 1161 430 1161 430 1161 430 365 430 1161 430 365 430 365 430 1161 430 365 430 365 431 365 430 1161 430 365 430 1161 430 1161 430 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3229 1528 461 335 461 1128 463 334 461 335 460 1129 463 337 458 1129 463 359 436 360 434 1156 434 1157 433 1159 432 364 431 1161 430 364 431 1161 430 1161 430 1160 431 364 431 364 431 365 430 365 430 1161 430 1161 430 365 430 1161 430 1161 431 365 430 365 431 1161 430 365 430 365 430 1161 430 365 430 365 431 1161 430 1161 430 365 431 1161 430 1161 430 1161 430 1161 430 1161 431 1161 430 365 430 1161 430 1161 430 1161 431 365 430 365 430 365 430 365 430 1162 430 365 430 365 430 365 431 1162 429 1162 429 1162 430 365 430 1162 429 1162 429 1162 429 1162 429 366 430 366 429 366 430 1162 429 366 429 366 430 366 429 366 429 1162 429 366 429 1163 428 366 429 1162 429 366 429 366 429 1162 429 366 430 1162 429 366 429 1163 429 366 430 1163 428 1163 428 367 428 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3230 1526 463 335 460 1128 464 333 461 335 460 1128 463 337 458 1128 463 359 436 359 436 1155 435 1157 433 1158 432 363 432 1160 431 364 431 1161 430 1160 431 1160 431 364 431 364 431 364 431 364 431 1161 430 1161 430 364 431 1161 430 1160 431 365 430 364 431 1161 431 364 431 364 431 1161 430 365 430 365 431 1161 430 1161 431 364 431 1161 430 1161 430 1161 430 1161 431 1161 430 1161 431 365 430 1161 431 1161 430 1162 430 365 430 365 430 365 431 365 430 1161 430 365 430 365 430 365 431 1161 430 1162 430 1162 429 365 430 1162 429 1162 429 1162 429 1162 429 366 429 366 430 366 430 1162 429 366 430 366 429 366 429 366 430 366 429 1162 429 1163 429 366 429 366 429 1163 428 1163 428 1163 429 1163 428 366 429 366 430 1163 428 1163 428 367 428 367 429 366 429 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3231 1526 463 334 461 1127 465 333 461 334 460 1128 463 336 459 1129 463 359 436 359 436 1133 458 1156 434 1157 433 362 433 1159 432 363 432 1159 432 1160 431 1159 433 363 432 363 432 363 432 363 432 1159 433 1159 432 363 432 1159 432 1160 432 363 432 363 432 1159 432 363 432 363 433 1159 432 364 432 363 432 1160 431 1160 432 363 432 1160 431 1160 431 1160 431 1160 432 1160 431 1160 431 364 432 1160 431 1160 431 1160 431 364 431 364 431 364 432 364 431 1160 432 364 431 364 431 364 432 1160 431 1161 430 1161 430 364 431 1161 431 1161 430 1161 430 1161 430 364 432 364 431 364 431 1161 430 365 430 365 430 365 430 365 431 365 430 1161 430 1161 431 365 430 1161 430 365 430 365 431 1161 430 1161 430 365 431 365 430 1162 430 365 431 1161 430 1162 429 365 430 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3230 1526 463 334 461 1128 464 333 461 334 461 1128 463 336 459 1129 463 359 436 359 436 1155 435 1156 434 1158 433 363 432 1159 432 363 432 1159 432 1160 431 1160 431 363 433 363 432 363 432 363 432 1160 432 1160 431 364 431 1160 431 1160 432 364 431 364 431 1160 431 364 431 364 432 1160 431 364 431 364 431 1160 431 1160 431 364 432 1160 431 1160 431 1160 431 1160 431 1160 431 1160 431 364 431 1160 432 1160 431 1160 431 364 432 364 431 364 431 364 431 1161 430 364 431 364 432 364 431 1161 430 1161 430 1161 430 365 430 1161 431 1161 430 1161 430 1161 430 365 430 365 430 365 430 1161 430 365 431 365 431 365 430 365 431 1161 430 1161 430 365 430 365 430 365 430 1162 430 365 430 365 430 365 431 365 430 1162 429 1162 430 1162 429 366 429 1162 429 1162 429 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3234 1525 463 333 462 1127 465 332 462 333 436 1153 518 307 488 1073 518 307 488 308 434 1131 459 1155 435 1156 434 362 433 1159 432 363 432 1159 432 1159 432 1159 433 363 432 363 432 363 433 363 432 1159 433 1159 432 363 432 1159 433 1159 432 363 432 363 432 1159 432 363 433 363 432 1159 432 363 432 363 432 1159 432 1159 432 363 432 1160 432 1160 431 1160 432 1160 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 364 431 364 431 364 431 364 431 1160 431 364 431 364 431 364 431 1160 432 1160 431 1160 432 364 431 1160 431 1160 431 1161 431 1161 430 364 431 364 431 364 431 1160 432 364 431 364 431 364 432 364 431 1161 431 1161 431 364 431 364 431 1161 430 364 432 364 431 1161 430 365 431 365 431 1161 430 1161 430 365 431 1161 430 1161 430 365 430 diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 5a0b18658..ae29a43f0 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 13th Jan, 2023 -# Last Checked 13th Jan, 2023 +# Last Updated 30th Jan, 2023 +# Last Checked 31th Jan, 2023 # name: POWER type: parsed @@ -2002,3 +2002,33 @@ type: parsed protocol: NEC address: 20 00 00 00 command: 50 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 0C 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 47 00 00 00 +# +name: POWER +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 02 00 00 00 +# +name: VOL- +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 05 00 00 00 +# +name: MUTE +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 04 00 00 00 diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index b2c683cba..942c2df13 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 13th Jan, 2023 -# Last Checked 13th Jan, 2023 +# Last Updated 31th Jan, 2023 +# Last Checked 31th Jan, 2023 # name: POWER type: raw @@ -68,6 +68,12 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 1294 371 1351 322 443 1200 1295 346 1297 373 444 1224 445 1198 1300 345 498 1170 473 1171 496 1173 471 8057 1295 372 1297 347 444 1224 1296 347 1296 349 494 1172 470 1174 1293 376 469 1174 469 1200 468 1175 468 8082 1293 351 1318 349 468 1175 1292 377 1294 349 468 1177 491 1175 1293 350 442 1226 468 1175 468 1201 467 8083 1293 350 1268 401 467 1175 1293 351 1318 350 467 1175 442 1226 1293 350 467 1177 466 1200 468 1176 441 8133 1292 351 1267 400 468 1175 1292 351 1292 376 466 1177 467 1202 1291 352 442 1202 465 1203 441 1201 442 8132 1267 376 1267 402 440 1202 1266 377 1290 379 439 1226 416 1253 1241 402 415 1228 439 1229 414 1228 415 8161 1239 403 1240 404 439 1229 1240 403 1240 429 414 1229 414 1231 1264 404 413 1229 414 1255 413 1229 413 8161 1238 404 1239 405 437 1230 1239 404 1238 430 412 1230 412 1232 1262 405 412 1231 412 1256 412 1231 412 8162 1238 406 1237 406 411 1258 1237 406 1237 431 412 1256 387 1256 1213 456 386 1256 386 1257 412 1256 386 8164 1237 431 1212 431 386 1283 1212 431 1212 432 411 1257 386 1257 1211 457 386 1257 386 1258 411 1258 385 8164 1212 431 1212 432 411 1256 1213 431 1236 433 386 1256 387 1257 1238 430 386 1257 386 1282 386 1256 386 +# ON/SPEED+ +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1330 364 1385 320 523 1158 1332 365 1329 364 479 1213 481 1213 481 1213 481 1213 481 1213 1332 390 480 8072 1358 362 1329 364 478 1216 1328 366 1328 367 476 1218 476 1218 476 1218 476 1218 476 1218 1328 367 476 8103 1328 367 1327 367 476 1218 1327 367 1327 367 476 1218 476 1218 476 1218 476 1218 476 1218 1327 367 476 8103 1327 367 1327 367 476 1218 1327 368 1326 367 476 1218 476 1219 475 1219 475 1219 475 1219 1326 368 475 8104 1327 368 1326 368 475 1219 1327 368 1326 368 475 1219 475 1219 475 1219 475 1219 475 1219 1326 368 475 8105 1326 368 1326 368 475 1219 1327 368 1326 368 475 1220 474 1220 474 1220 475 1220 474 1220 1325 368 475 8105 1326 369 1325 369 474 1220 1326 369 1325 369 474 1220 474 1220 474 1220 474 1220 474 1220 1326 369 474 8106 1325 369 1325 369 474 1220 1325 369 1326 369 474 1220 474 1220 474 1220 474 1220 474 1221 1324 370 473 8132 1273 422 1272 422 446 1248 1272 422 1297 397 421 1275 419 1300 419 1276 419 1275 419 1250 1297 398 445 8135 1297 397 1297 397 447 1247 1298 397 1297 397 447 1247 447 1247 447 1247 447 1247 447 1247 1298 397 447 8134 1298 397 1298 397 447 1248 1297 397 1297 397 447 1248 446 1248 446 1248 447 1248 447 1248 1297 397 447 8133 1298 397 1297 397 447 1248 1297 397 1297 397 447 1248 446 1248 447 1248 446 1248 446 1248 1297 398 446 8134 1297 398 1296 398 446 1248 1297 398 1296 398 446 1248 446 1248 446 1248 446 1248 446 1248 1296 398 446 8134 1295 398 1296 398 446 1248 1296 398 1296 398 446 1249 445 1249 445 1249 445 1249 445 1249 1295 399 445 8134 1295 399 1295 399 445 1249 1295 399 1295 399 445 1249 445 1249 445 1250 444 1249 445 1249 1295 399 445 8135 1295 400 1294 400 444 1250 1294 400 1295 400 444 1250 444 1250 444 1250 444 1250 444 1250 1294 401 443 8137 1293 401 1294 401 442 1251 1294 401 1293 401 442 1253 442 1252 442 1252 442 1252 442 1252 1293 427 417 8140 1292 426 1268 427 417 1277 1243 452 1267 427 417 1278 417 1277 417 1278 417 1277 417 1277 1268 427 417 8163 1242 452 1242 452 417 1278 1242 453 1241 453 391 1303 391 1303 392 1303 391 1303 391 1303 1242 453 415 8165 1241 453 1241 453 391 1304 1241 453 1241 454 390 1305 389 1304 390 1304 390 1305 389 1305 1240 480 364 8216 1214 480 1214 480 363 1331 1214 480 1214 480 364 1331 363 1331 363 1331 363 1331 363 1331 1214 481 363 8218 1213 481 1213 481 363 1333 1212 508 1186 508 335 1359 335 1359 335 1359 335 1359 335 1360 1186 508 335 8247 1184 509 1185 535 307 1387 1159 536 1158 589 253 1389 306 1415 278 1416 252 1442 199 1575 1052 # name: POWER type: raw @@ -1215,19 +1221,7 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 1349 364 1321 363 490 1219 1324 364 1294 389 463 1245 1324 363 462 1219 491 1221 462 1223 461 1226 484 8019 1292 393 1292 420 433 1252 1292 393 1292 420 433 1252 1292 393 460 1252 433 1252 460 1226 459 1252 433 8021 1317 393 1292 394 459 1226 1318 393 1292 394 458 1226 1318 394 432 1253 459 1226 459 1253 432 1253 459 -# -name: TEMP+ -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 1355 364 1348 363 462 1189 1355 363 1322 389 436 1245 492 1192 1351 389 436 1221 490 1197 487 1249 434 8019 1319 393 1292 393 459 1252 1292 393 1292 393 459 1252 432 1252 1292 393 459 1252 433 1252 433 1252 460 8020 1291 393 1292 420 432 1252 1292 393 1292 420 432 1253 459 1226 1291 420 432 1253 459 1226 459 1252 432 -# -name: TEMP- -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 1354 363 1322 363 489 1219 1325 364 1295 389 463 1245 464 1219 466 1219 1324 416 435 1223 461 1249 461 8019 1292 393 1318 393 432 1252 1292 393 1318 393 433 1252 460 1225 460 1252 1292 393 460 1225 459 1252 433 8020 1318 393 1292 393 459 1253 1291 393 1291 394 459 1253 431 1253 432 1253 1291 420 432 1253 432 1253 458 -# +# name: TIMER type: raw frequency: 38000 @@ -1287,3 +1281,87 @@ type: parsed protocol: NEC address: 01 00 00 00 command: 8B 00 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2256 695 788 1354 789 1349 789 1340 792 702 762 697 763 692 789 661 788 720 786 693 786 689 785 685 784 681 784 676 784 1334 784 1330 783 102265 2255 695 787 1356 786 1352 785 1348 785 681 783 676 783 671 784 666 784 724 784 696 783 691 784 686 784 681 783 676 784 1335 783 1330 783 +# OSC +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2227 749 733 1382 761 1379 866 1292 841 566 898 591 868 588 866 582 760 1412 867 612 866 576 898 603 867 598 866 1256 759 695 867 1246 759 101611 2335 615 868 1245 899 1268 869 1266 867 566 898 591 760 694 761 689 760 1411 760 720 760 715 759 710 759 705 759 1363 760 696 758 1352 761 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2224 708 755 1419 757 1443 756 685 756 1470 757 709 758 710 784 657 836 708 756 763 785 1468 782 1444 755 737 756 712 754 1471 781 1419 780 101298 2250 656 778 1420 809 1391 753 686 755 1472 779 687 779 687 752 688 831 714 778 741 750 1502 776 1422 752 740 752 741 751 1448 751 1475 749 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2203 675 786 1388 867 1361 786 678 786 1444 758 708 759 707 760 707 786 735 757 760 786 735 757 736 781 711 757 734 759 733 785 734 758 101185 2198 708 757 1416 757 1442 756 685 755 1445 780 685 780 662 776 689 803 742 778 740 753 766 779 715 777 714 779 714 778 690 776 742 752 +# StrengthUp +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2224 685 782 1419 808 1418 779 687 757 1470 757 710 757 684 809 657 809 736 758 1469 758 736 756 1470 757 762 755 1446 782 1418 781 712 755 101352 2223 707 758 1417 834 1392 781 685 781 1446 780 687 754 687 754 713 804 741 779 1447 779 715 778 1447 779 740 752 1448 778 1422 779 690 775 +# StrengthDown +name: SPEED- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2222 685 781 1419 808 1419 780 686 755 1447 781 684 783 686 780 686 807 1470 757 1470 756 1471 756 1497 756 1445 780 1447 780 1421 779 1421 754 101509 2250 684 777 1421 781 1444 754 687 754 1472 779 687 779 688 753 688 830 1448 777 1449 778 1448 752 1501 752 1450 773 1451 778 1422 778 1423 777 +# +name: POWER +type: parsed +protocol: NECext +address: 41 59 00 00 +command: 05 FA 00 00 +# +name: SPEED+ +type: parsed +protocol: NECext +address: 41 59 00 00 +command: 44 BB 00 00 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1332 391 1303 359 485 1241 1304 391 1303 391 452 1242 452 1242 452 1243 451 1243 452 1243 452 1242 1303 7275 1303 391 1303 390 453 1240 1330 364 1328 366 477 1218 476 1218 476 1220 474 1220 474 1220 474 1220 1325 7252 1326 369 1325 369 475 1219 1325 369 1325 369 475 1219 475 1219 475 1219 475 1219 475 1219 475 1219 1326 7254 1326 369 1326 369 475 1219 1326 369 1326 369 475 1219 475 1220 475 1219 475 1219 475 1220 475 1220 1325 7256 1325 370 1325 370 474 1220 1325 370 1325 370 474 1220 475 1220 474 1220 474 1220 474 1221 474 1221 1324 7281 1301 370 1325 370 474 1220 1325 370 1324 370 474 1221 474 1221 473 1221 473 1221 473 1221 474 1220 1325 7256 1325 370 1324 371 473 1221 1324 370 1324 370 474 1221 473 1221 473 1220 474 1220 474 1220 474 1220 1324 7256 1324 371 1323 371 473 1221 1323 371 1323 371 473 1221 473 1221 473 1221 473 1221 473 1221 473 1221 1323 7256 1323 371 1323 371 473 1222 1322 372 1322 372 472 1222 472 1222 472 1222 472 1222 472 1222 472 1222 1322 7281 1297 372 1322 373 471 1246 1298 396 1298 397 447 1247 447 1247 447 1247 447 1247 447 1247 447 1247 1297 7281 1297 397 1297 397 447 1247 1297 397 1297 397 447 1247 447 1247 447 1247 447 1247 447 1248 446 1248 1296 7282 1296 398 1296 398 446 1248 1296 398 1296 398 447 1248 446 1248 446 1248 446 1247 447 1247 447 1248 1295 7281 1296 398 1296 398 446 1248 1296 399 1295 399 446 1248 446 1248 446 1248 446 1248 446 1248 446 1248 1296 7282 1296 399 1295 399 445 1248 1295 399 1295 399 445 1248 446 1249 444 1249 445 1249 445 1249 445 1249 1294 7282 1294 399 1295 400 444 1249 1295 399 1294 400 444 1250 444 1249 445 1250 444 1249 445 1250 444 1250 1294 7282 1294 400 1294 400 444 1250 1294 400 1294 401 443 1251 443 1250 444 1250 444 1250 444 1250 443 1251 1292 7284 1292 401 1293 402 442 1251 1292 402 1291 403 442 1276 418 1252 442 1276 418 1277 417 1277 417 1277 1242 7334 1268 427 1242 452 392 1302 1242 452 1242 452 392 1302 392 1302 392 1302 392 1302 391 1302 392 1302 1242 7335 1241 453 1240 453 391 1302 1241 453 1240 453 391 1303 390 1303 390 1303 390 1304 390 1303 391 1304 1240 7361 1216 479 1216 479 364 1330 1215 479 1215 480 363 1330 364 1330 364 1330 364 1330 364 1330 364 1330 1214 7362 1213 480 1214 480 363 1331 1213 481 1213 482 361 1332 362 1332 362 1331 363 1331 362 1332 362 1332 1212 7391 1185 508 1185 509 334 1359 1185 509 1184 509 334 1359 335 1359 334 1386 307 1386 307 1386 307 1386 1159 7445 1131 562 1131 616 196 1471 1104 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2265 691 792 690 792 684 793 1342 821 1310 821 640 822 634 822 660 792 718 791 690 791 685 791 680 791 675 791 670 790 1330 789 662 788 99517 2230 723 760 721 760 715 761 1374 761 1368 762 699 762 694 762 689 762 747 761 719 761 715 761 710 761 705 761 701 760 1360 760 691 760 +# +name: SPEED+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2312 617 867 641 840 577 899 1269 866 1265 865 622 839 593 864 612 838 670 839 1306 839 611 865 1271 864 627 839 1259 865 590 866 611 840 102129 2316 670 813 667 813 664 811 1323 810 1319 759 702 759 697 759 692 759 750 759 1386 758 717 759 1376 758 706 759 1365 759 696 759 691 760 +# +name: SPEED- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2232 725 759 722 759 717 759 1375 760 1370 760 702 759 697 759 692 788 1384 788 1356 788 1351 788 1347 787 1342 787 1338 786 670 785 1330 784 99591 2229 724 760 721 785 690 785 1349 784 1345 784 677 783 673 782 669 781 1391 781 1363 781 1359 780 1353 781 1349 780 1343 781 675 780 1334 780 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2230 724 760 720 761 715 761 1374 761 1370 760 701 760 696 760 691 786 1385 760 720 787 689 760 710 760 705 786 1339 785 670 785 665 784 98757 2224 729 754 726 755 721 754 1380 754 1375 754 706 754 701 754 696 754 1418 754 726 754 720 755 716 755 710 755 1369 755 700 755 696 755 +# +name: ROTATE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 2256 698 786 695 786 689 787 1348 787 1342 787 673 788 668 787 663 787 722 786 696 784 1353 786 1375 759 706 759 702 783 672 783 1332 782 102265 2310 645 838 668 812 664 811 1323 810 1319 810 651 809 647 808 642 808 701 807 673 807 1332 807 1327 807 658 808 653 807 648 807 1307 807 \ No newline at end of file diff --git a/assets/resources/infrared/assets/projector.ir b/assets/resources/infrared/assets/projector.ir new file mode 100644 index 000000000..e9861de21 --- /dev/null +++ b/assets/resources/infrared/assets/projector.ir @@ -0,0 +1,829 @@ +Filetype: IR library file +Version: 1 +# +# Model: Smart +name: Power +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 8A 00 00 00 +# +# Model: Epson +name: Power +type: parsed +protocol: NECext +address: 83 55 00 00 +command: 90 6F 00 00 +# +# Model: Epson +name: Power +type: parsed +protocol: NECext +address: 81 03 00 00 +command: F0 0F 00 00 +# +# Model: Hitatchi +name: Power +type: parsed +protocol: NECext +address: 87 45 00 00 +command: 17 E8 00 00 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 310 27591 171 27662 241 27731 307 27575 107 27749 306 27551 130 55520 243 27614 217 55584 129 27743 119 27756 115 27747 163 27712 308 27502 243 27650 217 27732 175 27693 167 27698 166 27689 171 27622 215 27712 133 27658 216 27716 129 27732 162 27698 305 27571 131 27753 310 27570 170 27707 162 27707 175 10960 9194 4518 618 542 618 543 725 434 672 1623 671 1647 646 514 592 568 592 568 592 1702 592 568 592 567 593 1702 592 568 618 1676 618 1676 618 1676 618 543 617 543 617 543 617 1677 617 544 616 544 616 544 616 544 616 1678 616 1678 616 1678 616 544 616 1678 616 1679 615 1678 616 1678 616 40239 9196 2250 617 +# +name: Vol_up +type: parsed +protocol: NEC +address: 08 00 00 00 +command: 48 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 08 00 00 00 +command: 49 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 08 00 00 00 +command: 14 00 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 08 00 00 00 +command: 0B 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 40 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 48 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 44 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 83 7C 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 82 7D 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 08 13 00 00 +command: 87 78 00 00 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9055 4338 672 1551 669 1553 618 1603 619 481 617 482 616 481 617 507 591 1605 645 479 619 1577 645 1578 644 1578 644 479 619 480 618 1581 641 480 617 1605 617 1606 616 1606 615 483 615 1608 614 484 614 484 614 484 614 484 614 484 614 484 614 1609 614 484 614 1609 614 1609 613 1609 613 40058 9000 2068 614 95467 9022 2068 614 +# +name: Mute +type: parsed +protocol: NECext +address: 87 4E 00 00 +command: 29 D6 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 87 4E 00 00 +command: 08 F7 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 87 4E 00 00 +command: 04 FB 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 83 55 00 00 +command: 93 6C 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 15 00 00 00 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9032 4462 598 501 627 1604 627 530 598 531 677 423 706 422 706 421 707 451 677 1554 677 451 598 1633 598 1634 597 1634 598 1634 598 1634 625 1606 681 1550 626 502 598 530 599 529 600 1632 600 528 600 528 601 528 601 528 601 1631 600 1631 625 1607 625 504 625 1607 624 1608 624 1608 623 +# +name: Mute +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 02 00 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 1D 00 00 00 +# +# ON +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9096 4436 620 505 647 478 648 501 623 1599 647 1624 623 502 623 503 621 504 619 1628 618 507 617 507 617 1630 617 508 616 1630 617 1630 617 1631 616 508 616 508 617 508 616 1631 616 508 617 508 617 508 616 508 616 1630 616 1630 616 1631 616 508 616 1630 617 1630 617 1630 617 1631 617 509 616 508 616 509 616 509 616 509 616 509 615 509 616 508 617 1631 616 1631 615 1631 616 1631 616 1631 616 1631 616 1631 615 1631 616 14435 9093 2186 615 96359 9095 2184 617 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9091 4465 594 530 595 530 594 530 594 1651 595 1652 595 529 621 504 620 504 619 1628 618 507 617 508 616 1631 616 509 615 1631 616 1631 616 1632 615 509 616 509 616 509 615 1631 616 509 616 508 616 1631 616 509 616 1631 615 1631 616 1631 617 508 616 1631 616 1631 616 508 616 1631 617 508 617 509 616 509 616 509 616 509 616 509 616 509 616 509 616 1631 616 1631 616 1631 616 1631 616 1631 615 1631 615 1631 615 1631 616 14435 9090 2190 615 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9092 4439 620 506 619 506 618 530 593 1627 620 1630 643 504 620 505 618 506 617 1630 617 508 616 508 616 1632 616 508 617 1631 616 1631 616 1631 616 1631 616 509 616 508 616 1631 616 509 616 509 615 1632 616 509 616 508 616 1631 616 1631 616 508 616 1631 615 1631 616 509 615 1632 615 509 616 509 616 509 616 509 616 509 616 510 615 509 616 509 616 1631 616 1631 615 1631 616 1631 615 1631 615 1631 615 1631 615 1631 615 14434 9088 2191 615 96339 9115 2189 616 96343 9117 2189 616 96343 9114 2189 616 +# AV-Mute +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9092 4439 620 506 618 506 618 530 594 1627 619 1629 643 505 619 505 619 506 617 1629 617 508 616 508 616 1631 616 508 616 1630 616 1630 616 1630 617 1630 616 1630 616 1631 616 508 616 508 616 508 616 1631 616 508 617 508 616 508 616 508 616 1630 616 1631 615 1631 616 508 616 1631 616 508 617 508 616 509 615 509 616 508 616 509 615 509 616 508 616 1631 615 1631 615 1631 616 1631 615 1631 615 1631 615 1631 615 1631 616 14433 9088 2191 615 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9014 4332 661 1570 661 471 660 473 658 474 657 476 655 498 633 498 634 502 633 499 633 1599 632 1599 632 1599 632 1599 632 1599 632 1600 631 1603 632 500 632 501 631 501 631 501 631 501 631 501 631 1601 631 504 631 1601 631 1601 631 1601 631 1601 631 1601 630 1601 630 501 631 1601 631 38177 8983 2149 630 +# +name: Vol_up +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 11 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 4C 00 00 00 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9042 4306 690 1541 665 468 664 468 664 469 663 470 662 471 660 495 636 499 636 497 634 1597 634 1598 633 1598 633 1599 633 1599 632 1599 633 1603 632 1599 633 499 633 499 633 500 632 499 633 500 632 1600 632 503 633 500 632 1600 632 1600 632 1600 633 1600 632 1600 632 500 632 1600 632 37912 8986 2145 633 +# ON +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3522 1701 472 426 444 1269 472 426 444 426 443 427 443 427 443 426 444 427 443 426 444 427 442 428 441 429 440 431 438 1304 437 433 437 433 438 433 437 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1305 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 459 411 459 411 459 411 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 459 411 459 411 1330 411 1330 411 460 410 1330 411 1330 411 1331 410 1330 411 74392 3516 1736 436 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 435 435 1305 436 435 435 435 435 1306 435 435 435 435 435 435 435 436 434 436 434 436 434 435 435 436 434 436 434 436 434 1330 411 1331 410 1330 411 1330 411 1330 411 459 411 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 435 436 434 436 1306 435 435 435 435 435 1306 435 435 435 435 435 435 435 435 435 435 435 436 434 436 434 435 435 436 434 435 435 1306 435 1330 411 1307 434 1331 410 1308 433 436 434 436 434 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 435 435 434 436 434 436 434 436 434 436 434 436 1306 435 435 435 435 435 435 435 1306 435 435 435 436 434 1306 435 435 435 436 434 436 434 435 435 436 434 436 434 460 410 460 410 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 434 436 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 435 435 435 435 434 436 1306 435 434 436 435 435 435 435 1306 435 436 434 435 435 1306 435 435 435 436 434 436 434 436 434 436 434 460 410 437 433 459 411 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3514 1736 437 434 436 1304 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 435 435 434 436 434 436 435 435 434 436 1305 436 435 435 435 435 435 435 1306 435 435 435 435 435 1306 435 435 435 436 434 435 435 459 411 436 434 435 435 459 411 459 411 459 411 459 411 1330 411 1306 435 1330 411 1330 411 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 +# ON +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 529 7218 126 6585 219 703 180 5362 427 18618 177 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9069 4362 622 486 621 487 621 491 622 1608 623 1603 622 487 621 487 621 491 622 1604 621 487 622 491 622 1604 621 491 622 1608 622 1609 621 1604 622 486 622 487 621 491 621 1605 621 487 621 491 622 1604 622 491 621 1609 621 1609 621 1604 622 491 621 1609 622 1604 621 491 621 1604 622 487 621 487 622 486 622 487 621 488 621 487 621 488 620 491 621 1609 622 1609 620 1609 621 1609 621 1609 621 1609 621 1609 621 1618 621 14330 9047 2137 620 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9047 4362 621 486 622 463 645 490 622 1609 622 1604 622 487 620 487 621 491 622 1604 622 484 625 490 621 1605 649 463 621 1609 620 1611 621 1608 622 1605 621 486 622 491 622 1604 621 487 621 492 620 1604 621 488 621 492 620 1609 622 1604 621 492 622 1609 620 1605 621 491 622 1603 622 488 621 488 620 488 620 488 621 488 620 487 622 485 621 492 596 1635 621 1609 622 1585 643 1611 620 1608 621 1610 619 1611 620 1619 619 14332 9074 2109 647 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9073 4336 648 461 647 484 624 489 623 1607 623 1603 622 486 622 486 622 491 622 1604 621 487 621 491 622 1604 622 491 621 1609 621 1609 621 1609 621 1608 622 1609 621 1604 621 486 622 486 622 491 622 1604 622 486 622 487 621 487 621 491 622 1608 622 1609 621 1604 622 491 621 1604 621 487 621 486 622 487 621 487 621 487 621 487 621 487 621 491 622 1608 622 1608 622 1609 621 1608 622 1608 622 1608 622 1609 621 1617 622 14330 9047 2137 620 +# ON +name: Power +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 4F B0 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 80 19 00 00 +command: 10 EF 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 80 19 00 00 +command: 1C E3 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 80 19 00 00 +command: 46 B9 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 51 00 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 40 40 00 00 +command: 0A F5 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 4E B1 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 0E F1 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 0D F2 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 4F B0 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 00 30 00 00 +command: 14 EB 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 08 16 00 00 +command: 87 78 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 08 16 00 00 +command: C8 37 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 01 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 02 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 28 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 29 00 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 84 F4 00 00 +command: 0B F4 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 33 00 00 00 +command: 00 FF 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 33 00 00 00 +command: 1E E1 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 33 00 00 00 +command: 1D E2 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 33 00 00 00 +command: 0B F4 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 83 55 00 00 +command: 90 6F 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 83 55 00 00 +command: 99 66 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 83 55 00 00 +command: 98 67 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 1C E3 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 4F B0 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 00 DF 00 00 +command: 4B B4 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 02 00 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 2E 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 52 00 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 41 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 51 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 56 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 5A 00 00 00 +# +name: Power +type: parsed +protocol: SIRC15 +address: 54 00 00 00 +command: 15 00 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 82 7D 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 83 7C 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 14 EB 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 31 00 00 00 +command: 91 00 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 31 00 00 00 +command: 90 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 31 00 00 00 +command: D0 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 31 00 00 00 +command: 89 00 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 86 00 00 00 +command: 00 00 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 86 00 00 00 +command: 30 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 86 00 00 00 +command: 31 00 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 86 00 00 00 +command: 32 00 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 30 00 00 00 +command: 00 00 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 87 4E 00 00 +command: 0D 00 00 00 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9032 4479 597 560 572 558 564 566 566 1666 589 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 1669 596 560 562 1671 594 1666 588 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 566 566 563 569 1664 591 1669 596 1664 590 565 567 1667 598 1661 593 1666 588 1671 594 562 570 560 562 568 564 565 567 563 569 560 562 568 564 565 567 1666 588 1671 594 1665 589 1670 595 1665 590 1669 596 1664 590 1668 597 13983 9029 2222 599 96237 9030 2221 589 96244 9034 2217 594 96244 9033 2218 592 96249 9038 2213 597 96239 9037 2214 596 96238 9028 2223 598 96221 9032 2215 595 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9034 4482 593 563 569 561 571 559 563 1698 566 1694 570 559 563 568 564 566 566 1695 569 560 572 559 563 1671 593 563 569 1692 562 1671 593 1693 571 558 564 567 565 565 567 1693 571 532 590 567 565 1695 569 560 562 1698 566 1694 570 1663 591 539 593 1693 571 1688 566 564 568 1691 563 567 565 565 567 563 569 561 571 559 563 567 565 565 567 563 569 1690 564 1695 569 1691 563 1696 568 1691 563 1697 567 1692 562 1697 567 13988 9030 2223 597 96250 9035 2219 591 96245 9032 2221 589 96240 9038 2215 595 96235 9033 2220 590 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9028 4482 593 563 569 561 571 558 564 1696 568 1690 564 566 566 563 569 561 571 1688 566 563 569 561 571 1688 566 563 569 1690 564 1695 569 1689 565 1668 596 560 562 568 564 1695 569 560 562 568 564 1695 569 560 562 568 564 1695 569 1690 564 566 566 1692 572 1687 567 563 569 1690 564 566 566 564 568 562 570 559 563 567 565 565 567 562 570 560 562 1696 568 1665 589 1670 594 1665 589 1670 594 1664 590 1669 647 1612 590 13987 9031 2220 590 96223 9033 2217 593 96223 9034 2218 592 96225 9032 2219 591 96221 9087 2164 595 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9031 4479 596 560 572 558 564 566 566 1693 571 1688 566 563 569 561 571 559 563 1696 568 561 571 559 563 1697 567 562 570 1689 565 1694 570 1688 566 1693 571 1661 593 1693 571 558 564 566 566 564 568 1691 563 541 591 564 568 562 570 560 562 1697 567 1692 562 1696 568 562 570 1689 565 564 568 561 571 559 563 567 565 564 568 562 570 560 562 567 565 1694 570 1689 565 1694 570 1688 566 1693 571 1688 566 1693 571 1662 592 13987 9031 2220 590 96231 9034 2217 593 96234 9030 2222 588 96247 9037 2215 595 +# +name: Vol_up +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 11 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 14 00 00 00 +# OFF +name: Power +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 4E B1 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 03 00 00 00 +command: 1D 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 03 00 00 00 +command: 11 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 03 00 00 00 +command: 15 00 00 00 +# OFF +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9075 4307 677 433 675 456 651 461 651 1579 650 1576 649 459 649 460 648 465 648 1578 647 461 622 491 622 1604 647 465 647 1583 622 1608 647 1579 647 461 647 466 622 1604 647 465 647 1579 647 461 645 463 648 465 648 1583 646 1580 646 466 647 1579 622 491 647 1583 622 1608 647 1579 647 461 647 461 622 486 622 486 647 461 647 462 646 462 622 491 646 1584 622 1608 647 1584 621 1608 647 1583 646 1584 647 1584 646 1592 622 14330 9047 2137 621 +# +name: Power +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: E6 00 00 00 +# +name: Vol_up +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 07 00 00 00 +# +name: Vol_dn +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 0B 00 00 00 +# +name: Mute +type: parsed +protocol: Samsung32 +address: 07 00 00 00 +command: 0F 00 00 00 +# OFF +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3523 1701 472 426 444 1269 472 426 444 426 442 429 443 427 443 426 444 426 444 426 443 427 442 429 440 430 439 432 438 1304 437 433 437 432 438 432 438 433 437 433 437 433 437 433 437 433 437 433 437 1304 437 433 437 433 437 433 437 1304 437 433 437 433 437 1304 437 433 437 434 436 433 437 434 436 434 436 434 436 433 437 433 437 434 436 1304 437 1305 436 1305 436 1305 436 1305 436 1305 436 434 436 434 436 1305 436 1305 436 1305 436 434 436 1305 436 1305 436 1306 435 1306 435 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 1304 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1306 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 436 434 435 435 1307 434 1331 410 1307 434 1307 434 1330 411 1307 434 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 434 436 433 437 433 437 1304 437 434 436 434 436 434 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 435 435 434 436 1305 436 434 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 1307 434 1306 435 1307 434 1307 434 1307 434 1331 410 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 1304 437 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 437 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1306 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 1307 434 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 +# OFF +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9093 4441 620 507 618 530 594 531 593 1652 595 1653 620 505 620 505 619 506 617 1630 616 508 616 508 616 1632 615 509 615 1631 616 1632 615 1632 615 510 615 509 615 1632 615 509 615 1632 615 510 615 510 614 509 615 1632 614 1633 614 509 615 1633 614 509 615 1632 615 1632 614 1633 614 510 614 510 615 510 615 510 614 510 614 510 615 510 615 510 614 1632 615 1632 614 1632 615 1632 615 1632 615 1632 615 1632 615 1633 614 14439 9088 2192 614 96349 9112 2190 616 +# OFF +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 243 27700 170 27632 246 27694 282 27595 307 27497 241 27696 177 27710 164 27644 245 27629 246 27712 174 27638 211 27736 131 27741 306 27504 214 27727 135 27749 132 27761 126 27744 131 27753 127 27764 121 27767 132 27773 307 27577 131 27706 213 27761 129 27759 128 27770 125 27694 213 27751 307 27578 131 27737 131 27745 304 27575 335 27540 124 27752 132 27749 132 27747 134 27757 134 27758 127 27762 131 27748 131 27750 122 27749 130 27748 125 27772 131 27774 136 27762 135 27686 215 27742 131 27749 132 27756 133 27764 126 24073 9255 4460 672 488 618 541 619 541 619 1675 619 1676 618 542 618 542 618 542 618 1676 618 542 618 543 617 1678 616 568 592 1702 592 1702 592 1703 617 543 617 543 617 1677 617 543 617 1678 615 544 616 544 616 544 616 1678 616 1679 615 544 616 1679 615 545 615 1679 615 1679 615 1679 615 40240 9173 2273 591 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 219 27658 217 27663 216 27658 216 27634 216 27642 215 27646 217 27662 217 27637 216 27649 216 27649 218 27656 217 27658 215 27640 214 27636 217 27649 216 27644 218 27635 217 27630 215 27645 216 27631 215 27632 216 27650 216 27628 217 27630 214 27627 217 27623 215 27632 215 27641 216 27634 214 27633 215 27648 215 27648 217 27651 215 27635 216 27629 216 27630 216 2021 9254 4461 618 542 618 542 618 542 618 1675 619 1676 618 541 619 541 619 542 618 1677 617 543 617 543 617 1678 616 568 592 1702 592 1702 618 1676 618 542 618 542 618 543 617 1677 617 543 617 544 616 1678 616 544 616 1678 616 1678 616 1678 616 544 616 1678 616 1678 616 544 616 1678 616 40239 9200 2247 617 99930 110 27739 119 27738 123 27750 126 27738 175 27617 214 27716 203 27604 213 27639 217 27631 214 27722 136 27753 119 27736 175 27618 246 27683 177 27619 245 27685 171 55486 244 27693 158 27635 241 27695 170 27693 129 27717 340 27530 113 27757 106 27751 124 27728 172 27707 126 27666 215 27708 123 27733 123 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 18 E9 00 00 +command: 49 B6 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 14 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 48 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 40 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 18 00 00 00 +# +name: Power +type: parsed +protocol: NECext +address: B8 57 00 00 +command: 0C F3 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: B8 57 00 00 +command: 0D F2 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: B8 57 00 00 +command: 1E E1 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: B8 57 00 00 +command: 1F E0 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 81 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 8F 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 32 00 00 00 +command: 8C 00 00 00 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9066 4428 608 507 609 1622 609 507 609 507 609 1623 608 1623 609 507 609 506 610 1623 609 507 609 1622 610 1623 608 507 609 506 610 1622 609 1623 609 506 610 1622 610 506 610 1623 637 478 690 425 638 478 637 1594 637 1594 664 451 636 1594 610 506 610 1621 611 1621 610 1621 610 505 611 40183 9065 2156 637 95953 9037 2185 608 +# +name: Power +type: parsed +protocol: NEC +address: 00 00 00 00 +command: A8 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 88 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 9C 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 8C 00 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 87 45 00 00 +command: 17 E8 00 00 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9064 4354 666 1559 666 1562 662 1586 638 475 636 477 635 477 635 478 635 1590 635 1591 634 478 635 1591 634 478 634 478 635 478 634 1591 635 478 634 1591 634 478 635 478 634 478 635 1591 634 478 634 1591 635 478 634 478 634 1591 634 1591 635 1591 634 478 635 1591 634 478 634 1591 635 40957 9035 2144 634 95483 9047 2155 632 95484 9048 2153 633 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 87 45 00 00 +command: 50 AF 00 00 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9034 4385 638 1587 664 1562 663 1587 637 476 635 478 634 478 635 478 635 1591 634 1591 634 478 635 1591 635 478 634 478 635 478 635 1591 635 478 634 478 634 1591 634 478 635 479 634 1591 635 478 634 1591 635 478 634 1592 634 478 634 1591 635 1591 635 478 634 1592 634 478 634 1591 634 40958 9033 2144 635 +# +name: Power +type: parsed +protocol: NECext +address: FF FF 00 00 +command: E8 17 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: FF FF 00 00 +command: BD 42 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: FF FF 00 00 +command: F2 0D 00 00 +# +name: Power +type: parsed +protocol: Kaseikyo +address: 41 54 32 00 +command: 05 00 00 00 +# +name: Vol_up +type: parsed +protocol: Kaseikyo +address: 41 54 32 00 +command: 70 01 00 00 +# +name: Vol_dn +type: parsed +protocol: Kaseikyo +address: 41 54 32 00 +command: 71 01 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 31 00 00 00 +command: 81 00 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 17 E8 00 00 +# +name: Vol_up +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9010 4413 532 1617 532 1617 533 489 533 489 533 489 558 464 558 465 557 1593 557 465 557 466 556 1594 555 467 555 1595 529 1621 554 1595 581 1569 581 441 581 1569 581 441 581 441 581 441 581 441 581 441 581 1569 581 1569 581 441 581 1569 580 1569 580 1570 580 1595 554 1595 555 468 554 42156 8983 2135 556 +# +name: Vol_dn +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9032 4390 556 1592 559 1591 559 463 559 463 558 464 557 465 556 465 557 1593 583 440 581 441 580 1569 581 441 581 1569 580 1569 581 1569 581 1570 580 1596 554 1596 554 468 554 468 554 468 554 442 580 442 580 1596 554 469 553 469 553 1596 554 1596 553 1597 550 1598 553 1598 552 469 551 42155 9008 2107 531 95218 9006 2108 582 +# +name: Mute +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9011 4388 557 1617 532 1617 532 489 533 489 558 464 558 440 582 440 582 1593 556 466 556 466 556 1594 556 467 555 1595 555 1595 529 1620 554 1596 554 467 554 468 555 1595 579 443 581 1569 581 441 581 441 580 442 581 1569 581 1569 581 441 581 1569 580 441 581 1569 581 1569 581 1570 579 42152 8957 2159 556 \ No newline at end of file diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index db90997a7..9f1d8a0a0 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 13th Jan, 2023 -# Last Checked 13th Jan, 2023 +# Last Updated 31th Jan, 2023 +# Last Checked 31th Jan, 2023 # # ON name: POWER @@ -778,3 +778,27 @@ type: parsed protocol: NEC address: 31 00 00 00 command: 81 00 00 00 +# +name: POWER +type: parsed +protocol: NECext +address: 83 F4 00 00 +command: 17 E8 00 00 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9010 4413 532 1617 532 1617 533 489 533 489 533 489 558 464 558 465 557 1593 557 465 557 466 556 1594 555 467 555 1595 529 1621 554 1595 581 1569 581 441 581 1569 581 441 581 441 581 441 581 441 581 441 581 1569 581 1569 581 441 581 1569 580 1569 580 1570 580 1595 554 1595 555 468 554 42156 8983 2135 556 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9032 4390 556 1592 559 1591 559 463 559 463 558 464 557 465 556 465 557 1593 583 440 581 441 580 1569 581 441 581 1569 580 1569 581 1569 581 1570 580 1596 554 1596 554 468 554 468 554 468 554 442 580 442 580 1596 554 469 553 469 553 1596 554 1596 553 1597 550 1598 553 1598 552 469 551 42155 9008 2107 531 95218 9006 2108 582 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9011 4388 557 1617 532 1617 532 489 533 489 558 464 558 440 582 440 582 1593 556 466 556 466 556 1594 556 467 555 1595 555 1595 529 1620 554 1596 554 467 554 468 555 1595 579 443 581 1569 581 441 581 441 580 442 581 1569 581 1569 581 441 581 1569 580 441 581 1569 581 1569 581 1570 579 42152 8957 2159 556 diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index 6126a6239..a7a8c306a 100644 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 13th Jan, 2023 -# Last Checked 13th Jan, 2023 +# Last Updated 19th Jan, 2023 +# Last Checked 31th Jan, 2023 # name: POWER type: parsed @@ -1821,3 +1821,21 @@ type: parsed protocol: NEC address: 28 00 00 00 command: 10 00 00 00 +# +name: CH+ +type: parsed +protocol: RC5 +address: 01 00 00 00 +command: 14 00 00 00 +# +name: CH+ +type: parsed +protocol: SIRC20 +address: 5A 0E 00 00 +command: 10 00 00 00 +# +name: CH- +type: parsed +protocol: SIRC20 +address: 5A 0E 00 00 +command: 11 00 00 00 diff --git a/assets/resources/nfc/assets/mf_classic_dict.nfc b/assets/resources/nfc/assets/mf_classic_dict.nfc index ecb2c54dd..d62d0655b 100644 --- a/assets/resources/nfc/assets/mf_classic_dict.nfc +++ b/assets/resources/nfc/assets/mf_classic_dict.nfc @@ -1,31 +1,41 @@ ########################### # Do not edit, this file will be overwritten after firmware update # Use the user_dict file for user keys -# Last update 19th October, 2022 +# Last updated 25 January 2023 # ------------------------- + # MIFARE DEFAULT KEYS # -- ICEMAN FORK VERSION -- # -- CONTRIBUTE TO THIS LIST, SHARING IS CARING -- # https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_default_keys.dic + # DEFAULTKEY(FIRSTKEYUSEDBYPROGRAMIFNOUSERDEFINEDKEY) FFFFFFFFFFFF + # BLANKKEY 000000000000 + # NFC FORUM MADKEY # MAD ACCESS KEY A (REVERSED) A5A4A3A2A1A0 + # MAD ACCESS KEY B 89ECA97F8C2A + # KEY A WIEN # KEY B WIEN + # ICOPY-X E00000000000 E7D6064C5860 B27CCAB30DBD + # LIB / NAT BIEB D2ECE8B9395E + # NSCP DEFAULT KEY 1494E81663D7 + # KIEV KEYS 569369C5A0E5 632193BE1C3C @@ -34,40 +44,52 @@ D2ECE8B9395E 9DE89E070277 EFF603E1EFE9 F14EE7CAE863 + # KIEV / OV-CHIPKAART B5FF67CBA951 + # RKF # VÄSTTRAFIKEN KEYA, RKF ÖSTGÖTATRAFIKEN KEYA FC00018778F7 0297927C0F77 54726176656C + # VÄSTTRAFIKEN KEYB 00000FFE2488 776974687573 EE0042F88840 + # RKF SLKEYA 26940B21FF5D A64598A77478 + # RKF SLKEYB 5C598C9C58B5 E4D2770A89BE + # RKF REJSKORTDANMARK KEYA 722BFCC5375F F1D83F964314 + # RKF JOJOPRIVAKEYA 505249564141 + # RKF JOJOPRIVAKEYB 505249564142 + # RKF JOJOGROUPKEYA 47524F555041 + # RKF JOJOGROUPKEYB 47524F555042 434F4D4D4F41 434F4D4D4F42 4B0B20107CCB + # TNP3XXX # ACCESS CONTROL SYSTEM 605F5E5D5C5B + # MORE KEYS FROM MFC_DEFAULT_KEYS.LUA 000000000001 000000000002 @@ -82,8 +104,10 @@ F1D83F964314 200000000000 222222222222 27DD91F1FCF1 + # DIRECTORYANDEVENTLOGKEYB 2BA9621E0A36 + # DIRECTORYANDEVENTLOGKEYA 4AF9D7ADEBE4 333333333333 @@ -104,6 +128,7 @@ A00000000000 A053A292A4AF A94133013401 AAAAAAAAAAAA + # KEYFROMLADYADA.NET B00000000000 B127C6F41436 @@ -113,31 +138,41 @@ C934FE34D934 CCCCCCCCCCCC DDDDDDDDDDDD EEEEEEEEEEEE + # ELEVATOR # DATA FROM FORUM FFFFFF545846 F1A97341A9FC + # HOTEL SYSTEM 44AB09010845 85FED980EA5A + # ARD (FR) KEY A 43454952534E + # ARD (FR) KEY B 4A2B29111213 4143414F5250 + # TEHRAN RAILWAY A9B43414F585 1FB235AC1388 + # DATA FROM HTTP://IRQ5.IO/2013/04/13/DECODING-BCARD-CONFERENCE-BADGES/ # BCARD KEYB F4A9EF2AFC6D + # DATA FROM ... # S0 B 89EAC97F8C2A + # S4 A 43C7600DEE6B + # S6 A 0120BF672A64 + # S6 B FB0B20DF1F34 A9F953DEF0A3 @@ -146,6 +181,7 @@ A9F953DEF0A3 21EDF95E7433 C121FF19F681 3D5D9996359A + # HERE BE BIP KEYS... 3A42F33AF429 1FC235AC1309 @@ -179,32 +215,41 @@ D49E2826664F 51284C3686A6 3DF14C8000A1 6A470D54127C + # DATA FROM HTTP://PASTEBIN.COM/AK9BFTPW # LÄNSTRAFIKEN I VÄSTERBOTTEN 48FFE71294A0 E3429281EFC1 16F21A82EC84 460722122510 + # 3DPRINTER # EPI ENVISIONTE 3DPRINTER AAFB06045877 + # GYM # FYSIKEN A 3E65E4FB65B3 + # FYSIKEN B 25094DF6F148 + # CLEVERFIT A05DBD98E0FC + # HOTEL KEYCARD D3B595E9DD63 AFBECD121004 + # SIMONSVOSS 6471A5EF2D1A + # ID06 4E3552426B32 22BDACF5A33F 6E7747394E63 763958704B78 + # 24-7 D21762B2DE3B 0E83A374B513 @@ -218,8 +263,10 @@ F101622750B7 710732200D34 7C335FB121B5 B39AE17435DC + # KEY A 454841585443 + # DATA FROM HTTP://PASTEBIN.COM/GQ6NK38G D39BB83F5297 85675B200017 @@ -245,9 +292,11 @@ FEE470A4CB58 75EDE6A84460 DF27A8F1CB8E B0C9DD55DD4D + # DATA FROM HTTP://BIT.LY/1BDSBJL A0B0C0D0E0F0 A1B1C1D1E1F1 + # DATA FROM MSK SOCIAL A229E68AD9E5 49C2B5296EF4 @@ -274,6 +323,7 @@ C7C0ADB3284F D8A274B2E026 B20B83CB145C 9AFA6CB4FC3D + # DATA FROM HTTP://PASTEBIN.COM/RRJUEDCM 0D258FE90296 E55A3CA71826 @@ -287,16 +337,19 @@ EEB420209D0C 1ACC3189578C C2B7EC7D4EB1 369A4663ACD2 + # DATA FROM HTTPS://GITHUB.COM/ZHANGJINGYE03/ZXCARDUMPER # ZXCARD KEY A/B 668770666644 003003003003 + # DATA FROM HTTP://PHREAKERCLUB.COM/FORUM/SHOWTHREAD.PHP?P=41266 26973EA74321 71F3A315AD26 51044EFB5AAB AC70CA327A04 EB0A8FF88ADE + # TRANSPORT SYSTEM METROMONEY 2803BCB0C7E1 9C616585E26D @@ -305,6 +358,7 @@ EB0A8FF88ADE A160FCD5EC4C 112233445566 361A62F35BC9 + # TRANSPORT SYSTEM SPAIN 83F3CB98C258 070D486BC555 @@ -338,14 +392,18 @@ C52876869800 5145C34DBA19 25352912CD8D 81B20C274C3F + # DATA FROM MALL # PLAYLAND BALIKESIR ABBA1234FCB0 + # A TRIO BOWLING BAHCELIEVLER 314F495254FF 4152414B4E41 + # KARINCA PARK NIGDE 4E474434FFFF + # DATA FROM HTTPS://GITHUB.COM/RADIOWAR/NFCGUI 44DD5A385AAF 21A600056CB0 @@ -383,10 +441,12 @@ CBA6AE869AD5 A7ABBC77CC9E F792C4C76A5C BFB6796A11DB + # DATA FROM SALTO A/B 6A1987C40A21 7F33625BC129 2338B4913111 + # DATA FROM STOYE CB779C50E1BD A27D3804C259 @@ -414,16 +474,22 @@ D9A37831DCE5 C5CFE06D9EA3 C0DECE673829 A56C2DF9A26D + # DATA FROM HTTPS://PASTEBIN.COM/VBWAST74 68D3F7307C89 + # SMART RIDER. WESTERN AUSTRALIAN PUBLIC TRANSPORT CARDS 568C9083F71C + # BANGKOK METRO KEY 97F5DA640B18 + # METRO VALENCIA KEY A8844B0BCA06 + # HTC EINDHOVEN KEY 857464D3AAD1 + # VIGIK KEYS # VARIOUS SOURCES : # * HTTPS://GITHUB.COM/DUMPDOS/VIGIK @@ -432,18 +498,24 @@ A8844B0BCA06 # FRENCH VIGIK # VIGIK1 A 314B49474956 + # VIGIK1 B 564C505F4D41 BA5B895DA162 + # VIGIK MYSTERY KEYS MIFARE 1K EV1 (S50) # 16 A 5C8FF9990DA2 + # 17 A 75CCB59C9BED + # 16 B D01AFEEB890A + # 17 B 4B791BEA7BCC + # BTCINO UNDETERMINED SPREAKD 0X01->0X13 KEY 021209197591 2EF720F2AF76 @@ -452,6 +524,7 @@ D01AFEEB890A 4A6352684677 BF1F4424AF76 536653644C65 + # INTRATONE COGELEC # DATA FROM HTTP://BOUZDECK.COM/RFID/32-CLONING-A-MIFARE-CLASSIC-1K-TAG.HTML 484558414354 @@ -470,6 +543,7 @@ E64A986A5D94 66D2B7DC39EF 6BC1E1AE547D 22729A9BD40F + # DATA FROM HTTPS://DFIR.LU/BLOG/CLONING-A-MIFARE-CLASSIC-1K-TAG.HTML 925B158F796F FAD63ECB5891 @@ -485,8 +559,10 @@ CC6B3B3CD263 703140FD6D86 157C9A513FA5 E2A5DC8E066F + # DATA FROM FORUM, SCHLAGE 9691T FOB EF1232AB18A0 + # DATA FROM A OYSTER CARD 374BF468607F BFC8E353AF63 @@ -517,8 +593,10 @@ A2ABB693CE34 91F93A5564C9 E10623E7A016 B725F9CBF183 + # DATA FROM FDI TAG 8829DA9DAF76 + # DATA FROM GITHUB ISSUE 0A7932DC7E65 11428B5BCE06 @@ -543,14 +621,18 @@ D4FE03CE5B09 D4FE03CE5B0A D4FE03CE5B0F E241E8AFCBAF + # DATA FROM FORUM POST 123F8888F322 050908080008 + # DATA FROM HOIST 4F9F59C9C875 + # DATA FROM PASTEBIN 66F3ED00FED7 F7A39753D018 + # DATA FROM HTTPS://PASTEBIN.COM/Z7PEEZIF 386B4D634A65 666E564F4A44 @@ -582,19 +664,23 @@ F7A39753D018 6F506F493353 31646241686C 77646B633657 + # DATA FROM TRANSPERT 2031D1E57A3B 53C11F90822A 9189449EA24E + # DATA FROM GITHUB 410B9B40B872 2CB1A90071C8 + # DATA FROM 8697389ACA26 1AB23CD45EF6 013889343891 0000000018DE 16DDCB6B3F24 + # DATA FROM HTTPS://PASTEBIN.COM/VWDRZW7D # VINGCARD MIFARE 4K STAFF CARD EC0A9B1A9E06 @@ -608,6 +694,7 @@ B66AC040203A 2E641D99AD5B AD4FB33388BF 69FB7B7CD8EE + # HOTEL 2A6D9205E7CA 2A2C13CC242A @@ -615,25 +702,34 @@ AD4FB33388BF 01FA3FC68349 6D44B5AAF464 1717E34A7A8A + # RFIDEAS 6B6579737472 + # HID MIFARE CLASSIC 1K KEY 484944204953 204752454154 + # HID MIFARE SO 3B7E4FD575AD 11496F97752A + # LUXEO/AZTEK CASHLESS VENDING 415A54454B4D + # BQT 321958042333 + # APERIO KEY_A SECTOR 1, 12, 13, 14, 15 DATA START 0 LENGTH 48 160A91D29A9C + # GALLAGHER B7BF0C13066E + # PIK COMFORT MOSCOW KEYS (ISBC MIFARE PLUS SE 1K) 009FB42D98ED 002E626E2820 + # BOSTON, MA, USA TRANSIT - MBTA CHARLIE CARD # CHARLIE 3060206F5B0A @@ -670,8 +766,10 @@ D80511FC2AB4 BB467463ACD6 E67C8010502D FF58BA1B4478 + # DATA FROM HTTPS://PASTEBIN.COM/KZ8XP4EV FBF225DC5D58 + # DATA HTTPS://PASTEBIN.COM/BEM6BDAE # VINGCARD.TXT 4708111C8604 @@ -688,16 +786,19 @@ FBF225DC5D58 D9BCDE7FC489 0C03A720F208 6018522FAC02 + # DATA FROM HTTPS://PASTEBIN.COM/4T2YFMGT # MIFARE TECHNISCHE UNIVERSITÄT GRAZ TUG D58660D1ACDE 50A11381502C C01FC822C6E5 0854BF31111E + # MORE KEYS: 8A19D40CF2B5 AE8587108640 135B88A94B8B + # RUSSIAN TROIKA CARD 08B386463229 0E8F64340BA4 @@ -753,6 +854,7 @@ EAAC88E5DC99 F8493407799D 6B8BD9860763 D3A297DC2698 + # KEYS FROM MIFARECLASSICTOOL PROJECT 044CE1872BC3 045CECA15535 @@ -808,22 +910,28 @@ FD8705E721B0 00ADA2CD516D 237A4D0D9119 0ED7846C2BC9 + # HOTEL ADINA 9EBC3EB37130 + # MOST LIKELY DIVERSED INDIVIDUAL KEYS. # DATA FROM HTTPS://GITHUB.COM/KORSEHINDI/PROXMARK3/COMMIT/24FDBFA9A1D5C996AAA5C192BC07E4AB28DB4C5C 491CDC863104 A2F63A485632 98631ED2B229 19F1FFE02563 + # ARGENTINA 563A22C01FC8 43CA22C13091 25094DF2C1BD + # OMNITEC.ES HOTEL TIMECARD / MAINTENANCECARD AFBECD120454 + # OMNITEC.ES HOTEL EMERGENCYCARD 842146108088 + # TAPCARD PUBLIC TRANSPORT LA EA1B88DF0A76 D1991E71E2C5 @@ -857,6 +965,7 @@ B81846F06EDF C6A76CB2F3B5 E3AD9E9BA5D4 6C9EC046C1A4 + # ROC HIGHSCHOOL ACCESSCARD B021669B44BB B18CDCDE52B7 @@ -888,6 +997,7 @@ AE43F36C1A9A BE7C4F6C7A9A 5EC7938F140A 82D58AA49CCB + # MELONCARD 323334353637 CEE3632EEFF5 @@ -904,6 +1014,7 @@ A7FB4824ACBF 00F0BD116D70 4CFF128FA3EF 10F3BEBC01DF + # TRANSPORTES INSULAR LA PALMA 0172066B2F03 0000085F0000 @@ -937,6 +1048,7 @@ B1A862985913 3B0172066B2F 3F1A87298691 F3F0172066B2 + # TEHRAN EZPAY 38A88AEC1C43 CBD2568BC7C6 @@ -953,10 +1065,12 @@ D3B1C7EA5C53 604AC8D87C7E 8E7B29460F12 BB3D7B11D224 + # CHACO B210CFA436D2 B8B1CFA646A8 A9F95891F0A4 + # KEYS FROM APK APPLICATION "SCAN BADGE" 4A4C474F524D 444156494442 @@ -976,6 +1090,7 @@ A0004A000036 DFE73BE48AC6 B069D0D03D17 000131B93F28 + # FROM THE DFW AREA, TX, USA A506370E7C0F 26396F2042E7 @@ -992,6 +1107,7 @@ EF4C5A7AC6FC B47058139187 8268046CD154 67CC03B7D577 + # FROM THE HTL MÖDLING, NÖ, AT A5524645CD91 D964406E67B4 @@ -1000,32 +1116,40 @@ D964406E67B4 C27D999912EA 66A163BA82B4 4C60F4B15BA8 + # CAFE + CO, AT 35D850D10A24 4B511F4D28DD E45230E7A9E8 535F47D35E39 FB6C88B7E279 + # METRO CARD, AT 223C3427108A + # UNKNOWN, AT 23D4CDFF8DA3 E6849FCC324B 12FD3A94DF0E 0B83797A9C64 39AD2963D3D1 + # HOTEL BERLIN CLASSIC ROOM A KEY 34B16CD59FF8 + # HOTEL BERLIN CLASSIC ROOM B KEY BB2C0007D022 + # COINMATIC LAUNDRY SMART CARD # DATA FROM: HTTPS://PASTEBIN.COM/XZQILTUF 0734BFB93DAB 85A438F72A8A + # DATA FROM FORUM, CHINESE HOTEL 58AC17BF3629 B62307B62307 A2A3CCA2A3CC + # GRANADA, ES TRANSPORT CARD 000000270000 0F385FFB6529 @@ -1043,6 +1167,7 @@ B385EFA64290 C9739233861F F3864FCCA693 FC9839273862 + # VARIOUS HOTEL KEYS 34D3C568B348 91FF18E63887 @@ -1050,6 +1175,7 @@ FC9839273862 354A787087F1 4A306E62E9B6 B9C874AE63D0 + # DATA FROM OFFICIAL REPO F00DFEEDD0D0 0BB31DC123E5 @@ -1067,18 +1193,23 @@ B8937130B6BA D7744A1A0C44 82908B57EF4F FE04ECFE5577 + # COMFORT INN HOTEL 4D57414C5648 4D48414C5648 + # UNKNOWN HOTEL KEY 6D9B485A4845 + # BOSCH SOLUTION 6000 # FOUND IN TAGINFO APP # RATB KEY C1E51C63B8F5 1DB710648A65 + # E-GO CARD KEY 18F34C92A56E + # LIBRARY CARD MFP - SL1 4A832584637D CA679D6291B0 @@ -1094,6 +1225,7 @@ AADE86B1F9C1 C67BEB41FFBF B84D52971107 52B0D3F6116E + # DATA FROM HTTPS://PASTEBIN.COM/CLSQQ9XN CA3A24669D45 4087C6A75A96 @@ -1102,10 +1234,12 @@ D73438698EEA 5F31F6FCD3A0 A0974382C4C5 A82045A10949 + # DATA FROM HTTPS://PASTEBIN.COM/2IV8H93H # FUNNIVARIUM # FORUM ANKARA 2602FFFFFFFF + # MACERA ADASI # ANKARA KENTPARK # INACTIVE @@ -1113,16 +1247,20 @@ A82045A10949 DFF293979FA7 4D6F62692E45 4118D7EF0902 + # PETROL OFISI # POSITIVE CARD # ODE-GEC 0406080A0C0E + # KONYA ELKART 988ACDECDFB0 120D00FFFFFF + # BOWLINGO # SERDIVAN AVYM 4AE23A562A80 + # KART54 2AFFD6F88B97 A9F3F289B70C @@ -1131,18 +1269,23 @@ DB6819558A25 B16B2E573235 42EF7BF572AB 274E6101FC5E + # CRAZY PARK # KIZILAY AVM 00DD300F4F10 + # KARTSISTEM B FEE2A3FBC5B6 + # TORU ENT # TAURUS AVM 005078565703 + # VING? 0602721E8F06 FC0B50AF8700 F7BA51A9434E + # ESKART # ESKISEHIR TRANSPORT CARD E902395C1744 @@ -1151,6 +1294,7 @@ E902395C1744 D8BA1AA9ABA0 76939DDD9E97 3BF391815A8D + # MUZEKART # MUSEUM CARD FOR TURKEY 7C87013A648A @@ -1182,6 +1326,7 @@ D0DDDF2933EC 240F0BB84681 9E7168064993 2F8A867B06B4 + # BURSAKART # BURSA TRANSPORT CARD 755D49191A78 @@ -1191,18 +1336,22 @@ DAC7E0CBA8FD 0860318A3A89 1927A45A83D3 B2FE3B2875A6 + # PLAYLAND # MALTEPE PARK ABCC1276FCB0 AABAFFCC7612 + # LUNASAN # KOCAELI FAIR 26107E7006A0 + # GAMEFACTORY # OZDILEK 17D071403C20 534F4C415249 534F4C303232 + # NESPRESSO, SMART CARD # KEY-GEN ALGO, THESE KEYS ARE FOR ONE CARD FF9A84635BD2 @@ -1281,15 +1430,20 @@ AE76242931F1 124578ABFEDC ABFEDC124578 4578ABFEDC12 + # PREMIER INN HOTEL CHAIN 5E594208EF02 AF9E38D36582 + # NORWEGIAN BUILDING SITE IDENTICATION CARD. (HMS KORT) 10DF4D1859C8 + # KEY B B5244E79B0C8 + # UKRAINE HOTEL F5C1C4C5DE34 + # DATA FROM MIFARE CLASSIC TOOL REPO # ROTTERDAM UNIVERSITY OF APPLIED SCIENCES CAMPUS CARD BB7923232725 @@ -1314,6 +1468,7 @@ B5ADEFCA46C4 BF3FE47637EC B290401B0CAD AD11006B0601 + # ARMENIAN METRO E4410EF8ED2D 6A68A7D83E11 @@ -1323,6 +1478,7 @@ D3F3B958B8A3 2196FAD8115B 7C469FE86855 CE99FBC8BD26 + # KEYS FROM EUROTHERMES GROUP (SWITZERLAND) D66D91829013 75B691829013 @@ -1338,9 +1494,11 @@ FED791829013 29A791829013 668091829013 00008627C10A + # KEYS FROM NSP MANCHESTER UNIVERSITY UK ACCOMODATION STAFF AND STUDENTS 199404281970 199404281998 + # EASYCARD 310D51E539CA 2CCDA1358323 @@ -1348,6 +1506,7 @@ FED791829013 562E6EF73DB6 F53E9F4114A9 AD38C17DE7D2 + # SOME KEYS OF HTTPS://W3BSIT3-DNS.COM AND HTTPS://IKEY.RU # STRELKA EXTENSION 5C83859F2224 @@ -1358,6 +1517,7 @@ C4D3911AD1B3 CAD7D4A6A996 DA898ACBB854 FEA1295774F9 + # MOSCOW PUBLIC TOILETS CARD 807119F81418 22C8BCD10AAA @@ -1367,6 +1527,7 @@ DBF9F79AB7A2 34EDE51B4C22 C8BCD10AAABA BCD10AAABA42 + # MOSCOW SOCIAL CARD 2F87F74090D1 E53EAEFE478F @@ -1409,10 +1570,12 @@ F750C0095199 82DA4B93DB1C 9CF46DB5FD46 93EB64ACF43D + # KEYS FROM RFIDRESEARCHGROUP PROXMARK3 PROJECT # HTTPS://GITHUB.COM/RFIDRESEARCHGROUP/PROXMARK3/BLOB/MASTER/CLIENT/DICTIONARIES/MFC_DEFAULT_KEYS.DIC 13B91C226E56 5A7A52D5E20D + # IRON LOGIC A3A26EF4C6B0 2C3FEAAE99FC @@ -1431,9 +1594,11 @@ DEC0CEB0CE24 413BED2AE45B D6261A9A4B3F CB9D507CE56D + # MORE KEYS FROM THE PM3 REPO # KEYS OF ARMENIAN UNDERGROUND TICKET A0A1A2A8A4A5 + # https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_keys_bmp_sorted.dic 002DE0301481 004173272D18 @@ -2435,6 +2600,7 @@ EE17C426D25E EE487A4C806E EE5931913A8D EED56840AEBA + # https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_keys_icbmp_sorted.dic 00383D96411D 005307DB7853 @@ -3436,6 +3602,7 @@ EE3029556CEB EE49610E6121 EEB704D69BCA EED69A391464 + # https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_keys_mrzd_sorted.dic 010203040506 013940233313 @@ -3494,6 +3661,7 @@ F83466888612 F89C86B2A961 FFFFAE82366C FFFFD06F83E3 + # Unknown origin 2DEB57A3EA8F 32C1BB023F87 @@ -3577,27 +3745,26 @@ D27058C6E2C7 E19504C39461 FA1FBB3F0F1F FF16014FEFC7 -# + # Cracked by UberGuidoZ # https://github.com/UberGuidoZ -# # BadgeMaker Leaked 1A1B1C1D1E1F 1665FE2AE945 158B51947A8E -E167EC67C7FF -D537320FF9OE +EL67EC67C7FF +D53732OFF9OE 5E56BFA9E2C9 F81CED821B63 C81584EF5EDF 9551F8F9259D -36E1765CE3E8 +36EL765CE3E8 509052C8E42E 776C9B03BE71 -C608E13ADD50 +C608EL3ADD50 BEE8B345B949 -ED0EC56EEFDD -9716D5241E28 +EDOEC56EEFDD +9716D524LE28 05D1FC14DC31 3321FB75A356 F22A78E29880 @@ -3611,9 +3778,9 @@ DB32A6811327 8AA8544A2207 8C5819E780A4 7549E90353A2 -2E52ABE0CE95 +2E52ABEOCE95 E46210ED98AB -61D030C0D7A8 +61DO30COD7A8 18E20102821E DA59354DFB88 040047C12B75 @@ -3622,6 +3789,7 @@ D10008074A6F 446176696453 6F6674776172 6520446F7665 + # Apartment keyfobs in USA from Corvette830 E60F8387F0B9 FFD46FF6C5EE @@ -3630,6 +3798,7 @@ FFD46FF6C5EE 1C5179C4A8A1 16CA203B811B 11AC8C8F3AF2 + # The Westin Jakarta Indonesia from D4DB0D # Peppers Hotel Unknown location from D4DB0D 6E0DD4136B0A @@ -3644,15 +3813,19 @@ FC5AC7678BE3 F09BB8DD142D B4B3FFEDBE0A 540E0D2D1D08 + # Schlage 9691T Keyfob 7579B671051A 4F4553746B41 + # FOOD REPUBLIC 30C1DC9DD040 A9B9C1D0E3F1 + # iGuard Simple (and reverse) keys AAAAAAFFFFFF FFFFFFAAAAAA + # Vigik verified by quantum-x # https://github.com/RfidResearchGroup/proxmark3/pull/1742#issuecomment-1206113976 A00027000099 @@ -3670,19 +3843,20 @@ A00000043D79 A00000000064 A00025000030 A00003000057 -# + # BH USA 2013 conference 012279BAD3E5 + # Vigik ScanBadge App (fr.badgevigik.scanbadge) # Website https://badge-vigik.fr/ - By Alex` 0000A2B3C86F -021200c20307 +021200C20307 021209197507 1E34B127AF9C 303041534956 4143532D494E 41454E521985 -43412d627400 +43412D627400 455249524345 456666456666 45B722C63319 @@ -3701,10 +3875,12 @@ A00003000057 9EB7C8A6D4E3 A22AE12C9013 AFC984A3576E + # Spackular A/B # data from http://www.proxmark.org/forum/viewtopic.php?pid=45100#p45100 7CB033257498 1153AABAFF6C + # iGuard Simple and Reverse Keys D537320FF90E 36E1765CE3E8 @@ -3713,10 +3889,13 @@ ED0EC56EEFDD 9716D5241E28 2E52ABE0CE95 61D030C0D7A8 + # BadgeMaker Leaked from https://github.com/UberGuidoZ E167EC67C7FF + # Schlage 9691T Keyfob from seasnaill Added by VideoMan. 3111A3A303EB + # Transport cards E954024EE754 0CD464CDC100 @@ -3724,17 +3903,13 @@ BC305FE2DA65 CF0EC6ACF2F9 F7A545095C49 6862FD600F78 -#MISC KEYS -36El765CE3E8 -9716D524lE28 -C608El3ADD50 -El67EC67C7FF -# keys for transport cards by novacard.ru 72A0C485D3F7 6A530C91F85B + # RENFE MADRID (TRAIN) Extracted with detect reader 701AA491A4A5 12BA20088ED3 + # MISC KEYS FROM MY OLD ACCESS CARDS F18D91EE3033 0E726E11CFCC @@ -3784,3 +3959,80 @@ E10F0E7A8DD5 F833E24C3F1C FA8CA10C7D59 FE98F38F3EE2 +# +########################################## +# added by colonelborkmundus +# "the more, the marriott" mifare project +# + +# 1k - graduate hotel +C49DAE1C6049 +209A2B910545 + +# 1k - westin +8C29F8320617 +5697519A8F02 +7D0A1C277C05 +2058580A941F +C40964215509 +D44CFC178460 + +# 1k - marriott +7B4DFC6D6525 +23C9FDD9A366 +3119A70628EB +30AAD6A711EF +1330824CD356 +43012BD9EB87 +035C70558D7B +9966588CB9A0 +12AB4C37BB8B + +# 1k - AC hotels marriott +8EA8EC3F2320 +7B56B2B38725 + +# 1k - the ritz-carlton +30FB20D0EFEF +D20289CD9E6E +66A3B064CC4B +D18296CD9E6E + +# 1k - unknown +722538817225 + +# 1k - aria resort & casino +316B8FAA12EF +A18D9F4E75AF + +# 1k - fairfield inn & suites marriott +7AEB989A5525 +7B3B589A5525 +215E9DED9DDF +334E91BE3377 +310308EC52EF + +# 1k - residence inn marriott +F72CD208FDF9 + +# 1k - sheraton +42FC522DE987 + +# 1k - millenium hotels +132F641C948B + +# 1k - moxy hotels +20C166C00ADB +9EE3896C4530 + +# 1k - residence inn marriott +3122AE5341EB + +# 1k - americinn +8AC04C1A4A25 + +# 1k - the industrialist +2158E314C3DF + +# 1k - waldorf astoria +011C6CF459E8 \ No newline at end of file diff --git a/assets/resources/subghz/Jamming/Jam_315.00.sub b/assets/resources/subghz/Jamming/Jam_315.00.sub deleted file mode 100644 index c74aa39ce..000000000 --- a/assets/resources/subghz/Jamming/Jam_315.00.sub +++ /dev/null @@ -1,216 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 315000000 -Preset: FuriHalSubGhzPresetOok650Async -Protocol: RAW -RAW_Data: 124 -73 55 -122 115 -171 97 -54 108 -66 73 -86 63 -58 65 -76 79 -80 59 -331 75 -83 110 -66 71 -62 115 -88 89 -78 303 -205 146 -52 79 -123 310 -107 55 -127 200 -88 130 -183 79 -54 118 -98 75 -445 75 -157 114 -188 121 -205 61 -124 288 -206 97 -154 73 -269 53 -60 192 -78 65 -131 111 -119 180 -134 236 -190 129 -191 67 -164 75 -88 207 -60 164 -87 91 -115 243 -97 326 -80 79 -66 79 -194 61 -135 147 -108 289 -62 67 -134 181 -248 173 -123 67 -101 290 -144 151 -123 85 -184 430 -106 109 -130 186 -99 154 -72 61 -81 73 -69 194 -52 180 -69 334 -74 51 -62 129 -54 51 -264 77 -186 59 -629 114 -414 181 -100 160 -52 72 -94 81 -70 151 -113 342 -92 69 -343 95 -78 87 -94 195 -52 105 -64 129 -193 53 -56 104 -168 175 -52 169 -82 63 -58 67 -254 87 -70 137 -106 200 -90 163 -108 125 -118 53 -120 79 -97 53 -137 85 -119 109 -88 137 -54 87 -72 75 -60 209 -54 51 -178 319 -52 129 -128 130 -177 78 -68 94 -68 53 -90 65 -95 103 -54 498 -85 84 -88 170 -70 155 -135 88 -72 244 -92 115 -141 89 -131 59 -104 53 -79 149 -58 83 -66 117 -54 51 -175 340 -84 61 -223 61 -80 69 -70 208 -64 115 -54 53 -132 130 -183 77 -204 69 -62 77 -62 79 -52 65 -176 256 -240 256 -164 85 -119 125 -237 89 -72 135 -286 103 -95 99 -60 114 -122 87 -56 215 -74 303 -56 57 -217 59 -206 214 -199 75 -60 71 -64 75 -78 89 -82 346 -257 65 -78 53 -173 63 -108 175 -52 136 -241 91 -56 75 -112 264 -64 93 -64 91 -62 51 -104 119 -68 85 -137 222 -52 162 -84 84 -284 93 -247 214 -369 71 -228 226 -108 69 -86 212 -54 213 -93 198 -84 127 -194 59 -90 77 -72 67 -118 278 -60 162 -170 160 -100 107 -204 53 -78 152 -100 219 -166 138 -150 81 -74 113 -78 59 -58 266 -66 71 -154 142 -58 53 -76 71 -169 174 -72 51 -219 63 -152 57 -125 307 -94 85 -122 136 -62 65 -132 111 -338 163 -145 156 -83 127 -162 142 -253 67 -110 65 -94 160 -248 101 -148 71 -400 120 -149 109 -109 297 -317 153 -52 157 -65 97 -239 236 -52 143 -60 59 -98 97 -72 53 -284 77 -191 113 -96 232 -257 92 -78 75 -78 119 -93 107 -126 84 -58 299 -156 179 -144 180 -60 83 -299 231 -157 191 -74 85 -74 102 -111 177 -58 194 -52 180 -60 131 -58 59 -93 427 -66 -RAW_Data: 135 -60 59 -227 95 -70 87 -74 212 -60 125 -88 176 -60 107 -54 155 -85 109 -78 103 -136 65 -119 87 -150 61 -62 83 -130 51 -98 144 -230 81 -456 69 -110 233 -144 83 -116 61 -54 79 -123 51 -70 138 -54 155 -104 305 -76 107 -66 212 -103 187 -253 307 -88 67 -174 162 -98 180 -140 170 -82 69 -167 118 -60 75 -52 51 -80 117 -173 95 -289 131 -126 141 -94 183 -76 202 -171 89 -80 111 -214 177 -94 126 -70 69 -194 103 -96 154 -106 67 -158 127 -60 157 -68 130 -58 77 -102 220 -64 591 -273 222 -60 172 -123 101 -58 257 -108 78 -166 71 -62 204 -52 107 -195 57 -52 79 -72 87 -129 147 -82 90 -70 75 -70 254 -108 171 -197 141 -115 77 -308 142 -84 71 -56 228 -98 95 -64 51 -108 154 -286 89 -137 117 -116 244 -62 265 -119 71 -52 170 -121 63 -385 299 -164 140 -86 79 -190 150 -194 75 -236 177 -106 133 -99 167 -79 55 -298 154 -62 63 -62 121 -96 115 -66 77 -117 73 -197 82 -171 73 -173 53 -111 69 -60 107 -64 427 -84 83 -202 71 -88 123 -152 69 -77 123 -74 81 -113 135 -62 82 -82 257 -170 97 -107 61 -88 96 -174 51 -52 262 -52 61 -60 153 -120 148 -203 243 -90 96 -58 360 -92 167 -99 53 -106 178 -84 75 -116 157 -145 51 -249 71 -54 238 -131 142 -160 112 -88 59 -52 51 -85 69 -98 53 -128 75 -52 112 -224 149 -84 98 -78 93 -132 136 -104 139 -96 139 -110 57 -54 155 -88 67 -102 225 -79 87 -193 246 -84 67 -93 150 -78 422 -224 55 -140 53 -91 61 -149 234 -66 75 -143 186 -139 247 -174 96 -62 226 -52 127 -145 67 -62 130 -267 121 -121 67 -182 97 -152 228 -52 482 -116 89 -131 53 -78 209 -54 149 -54 285 -133 144 -78 370 -88 59 -100 111 -120 53 -76 81 -86 166 -84 115 -81 77 -92 111 -52 71 -107 239 -188 113 -157 59 -115 51 -135 51 -80 51 -162 223 -68 69 -132 212 -149 241 -70 59 -84 199 -74 120 -62 250 -74 97 -78 210 -118 416 -195 77 -126 129 -68 150 -194 77 -112 81 -177 75 -212 131 -375 71 -102 137 -126 57 -66 89 -84 53 -907 363 -560 97 -492 65 -1152 67 -630 131 -402 197 -730 165 -300 99 -934 131 -1092 97 -164 230 -264 231 -462 163 -130 131 -228 99 -130 99 -464 199 -166 365 -298 199 -300 65 -264 197 -134 65 -332 99 -100 97 -666 65 -132 97 -234 163 -166 231 -332 65 -464 165 -266 97 -200 65 -960 -RAW_Data: 331 -164 67 -498 65 -666 97 -500 131 -298 399 -166 199 -332 97 -100 65 -232 99 -132 435 -168 693 -100 131 -232 829 -798 199 -68 99 -66 727 -68 131 -66 623 -98 263 -66 763 -66 65 -132 131 -332 631 -66 99 -164 65 -860 263 -100 267 -528 99 -532 133 -132 467 -134 167 -466 67 -98 499 -168 131 -66 99 -730 65 -132 65 -166 67 -100 893 -166 165 -66 463 -398 65 -464 99 -266 231 -396 67 -794 99 -730 131 -268 63 -132 99 -330 99 -728 197 -396 163 -800 97 -164 65 -1284 427 -430 65 -862 231 -298 97 -696 197 -166 99 -298 263 -1090 129 -494 299 -66 65 -200 65 -266 131 -66 2905 -100 597 -462 131 -428 265 -958 163 -528 65 -1098 99 -398 165 -232 133 -462 133 -428 331 -232 99 -134 65 -462 65 -98 195 -98 229 -856 163 -822 97 -100 65 -130 495 -232 65 -658 461 -394 99 -132 99 -200 131 -334 165 -166 265 -298 99 -100 297 -600 133 -66 97 -662 2157 -230 65 -662 97 -494 131 -164 229 -494 99 -166 97 -134 131 -464 199 -100 131 -830 133 -266 295 -432 131 -166 167 -166 99 -1092 199 -496 133 -198 99 -134 99 -830 131 -200 131 -232 63 -396 97 -268 233 -198 329 -332 65 -132 393 -100 163 -954 131 -660 99 -296 65 -266 163 -398 131 -364 2005 -134 729 -268 65 -100 65 -1788 99 -198 333 -202 1387 -66 555 -332 97 -66 97 -396 67 -266 65 -464 231 -696 65 -2040 131 -132 129 -196 97 -164 65 -196 195 -560 99 -330 163 -686 131 -162 99 -164 297 -100 131 -298 165 -466 131 -364 65 -532 99 -66 99 -1658 167 -432 163 -556 263 -296 65 -296 97 -132 63 -132 97 -164 65 -628 163 -98 97 -230 129 -66 1651 -792 99 -400 65 -562 65 -66 65 -98 97 -200 99 -764 99 -496 99 -100 197 -1026 165 -1392 327 -166 131 -202 165 -134 297 -696 263 -196 131 -462 165 -66 165 -166 363 -166 65 -296 65 -164 65 -920 131 -460 129 -166 97 -264 231 -396 265 -1096 65 -200 99 -132 133 -1262 131 -166 129 -100 131 -856 65 -760 97 -198 129 -560 329 -200 67 -366 65 -598 65 -330 65 -890 327 -166 97 -594 65 -1024 131 -298 97 -398 97 -166 65 -398 133 -632 165 -400 165 -1194 297 -266 233 -564 131 -100 131 -698 265 -134 99 -1028 131 -134 131 -300 263 -562 131 -66 99 -1196 1427 -166 1823 -100 99 -68 97 -198 331 -762 267 -132 99 -198 65 -100 231 -298 199 -132 131 -134 99 -994 97 -166 299 -66 99 -264 97 -564 229 -332 331 -198 99 -168 99 -232 97 -166 -RAW_Data: 65 -460 97 -558 393 -166 97 -162 197 -164 99 -164 131 -366 65 -66 165 -2538 97 -100 131 -298 331 -166 131 -134 65 -198 1319 -98 823 -230 259 -264 99 -790 525 -822 131 -690 65 -364 297 -66 99 -68 495 -66 165 -298 99 -530 665 -132 363 -98 1467 -598 131 -132 331 -132 199 -564 65 -100 65 -66 329 -362 163 -464 359 -264 97 -558 131 -66 65 -100 197 -162 65 -896 65 -830 99 -264 65 -800 131 -996 65 -532 65 -164 65 -266 65 -166 199 -694 99 -592 65 -1384 99 -66 163 -134 131 -200 2123 -332 131 -430 297 -198 65 -168 131 -468 99 -564 197 -366 65 -696 99 -166 99 -164 131 -564 263 -730 167 -828 97 -98 97 -464 65 -1150 97 -790 165 -398 65 -130 65 -66 131 -430 231 -234 99 -464 165 -132 133 -434 131 -430 131 -330 99 -364 99 -66 861 -100 1117 -132 1413 -426 293 -132 263 -596 99 -200 131 -334 199 -64 99 -132 99 -1226 297 -760 65 -198 65 -630 263 -534 663 -1490 99 -296 295 -164 97 -758 163 -396 363 -66 131 -1656 199 -1422 163 -1094 131 -626 163 -130 195 -132 129 -460 165 -166 131 -198 131 -362 163 -264 131 -330 229 -230 161 -428 197 -426 65 -264 65 -658 131 -164 97 -100 197 -66 97 -364 199 -532 2023 -166 931 -694 131 -498 65 -598 133 -264 233 -1620 231 -1892 165 -498 131 -824 265 -954 65 -558 231 -262 99 -426 65 -562 63 -298 263 -428 97 -660 99 -664 131 -202 131 -166 231 -1028 725 -134 1259 -298 397 -132 197 -134 99 -362 99 -528 197 -132 333 -66 633 -694 65 -396 133 -198 133 -730 131 -400 197 -234 199 -528 163 -1644 65 -854 199 -1162 97 -2618 165 -266 131 -166 65 -166 165 -498 99 -100 165 -100 99 -1092 99 -1426 99 -794 163 -68 199 -596 131 -730 233 -232 229 -264 67 -394 65 -658 429 -728 133 -394 97 -200 197 -166 1143 -100 129 -328 695 -134 365 -100 165 -100 197 -200 99 -268 333 -762 131 -1084 99 -264 131 -1218 97 -362 295 -230 97 -164 65 -132 131 -362 131 -166 131 -664 67 -954 67 -334 165 -1028 99 -762 131 -1810 97 -1382 65 -392 65 -230 99 -164 167 -266 229 -558 131 -166 67 -432 65 -230 65 -462 99 -232 165 -234 65 -268 65 -100 97 -164 133 -662 233 -430 227 -262 65 -132 99 -198 65 -200 263 -630 101 -332 65 -1060 731 -98 99 -1592 231 -1060 299 -962 861 -68 263 -166 65 -200 99 -66 763 -100 133 -692 131 -234 263 -296 97 -796 65 -166 131 -464 65 -262 63 -232 129 -232 97 -130 129 -720 65 -198 65 -164 -RAW_Data: 461 -1056 165 -266 99 -232 199 -498 131 -132 131 -234 395 -596 231 -166 99 -860 97 -590 3359 -264 163 -66 129 -692 129 -392 65 -266 97 -832 99 -398 65 -332 265 -166 297 -232 235 -498 99 -530 99 -562 361 -830 65 -98 99 -198 133 -332 97 -232 131 -498 263 -1230 165 -200 163 -334 131 -100 99 -362 65 -198 97 -532 133 -198 65 -996 65 -98 133 -762 65 -100 1325 -166 597 -198 65 -600 131 -232 361 -134 229 -566 429 -1162 131 -230 97 -132 263 -98 131 -462 129 -98 99 -328 99 -98 265 -66 131 -134 131 -564 99 -266 99 -298 163 -732 165 -1428 131 -660 131 -232 201 -168 97 -264 2369 -100 165 -166 199 -264 295 -464 295 -762 231 -462 229 -828 165 -1224 197 -364 99 -98 67 -66 97 -198 65 -398 67 -168 167 -302 131 -498 65 -334 67 -198 97 -132 65 -296 65 -100 97 -230 197 -360 99 -198 99 -200 197 -134 65 -232 99 -298 99 -130 131 -232 97 -164 97 -98 131 -196 165 -164 1419 -64 1643 -134 329 -364 131 -264 361 -558 97 -366 99 -132 393 -528 167 -330 99 -464 99 -532 233 -196 133 -68 201 -66 99 -132 65 -1892 165 -166 99 -334 197 -368 65 -530 65 -100 129 -132 99 -394 197 -558 165 -66 165 -66 363 -98 131 -200 331 -332 97 -168 133 -100 199 -564 165 -736 99 -100 99 -300 231 -826 67 -100 129 -166 229 -262 197 -230 261 -164 99 -560 197 -528 65 -264 131 -462 163 -98 131 -132 99 -66 163 -298 163 -166 393 -132 163 -98 361 -330 263 -164 229 -164 197 -496 163 -100 795 -134 165 -566 99 -164 99 -98 917 -98 165 -1678 199 -854 197 -134 199 -732 1193 -66 565 -98 365 -102 171 -566 131 -98 99 -660 65 -330 99 -634 65 -400 99 -98 99 -728 65 -132 131 -592 131 -400 99 -564 131 -166 99 -366 65 -632 65 -196 65 -886 231 -264 97 -788 129 -100 129 -590 199 -298 263 -296 131 -394 259 -266 199 -432 131 -862 99 -232 265 -2114 165 -134 65 -398 199 -628 133 -268 99 -996 131 -894 263 -230 131 -300 65 -100 99 -100 197 -730 97 -726 99 -132 97 -232 65 -298 99 -1254 65 -428 261 -492 65 -164 163 -164 131 -264 129 -1094 129 -66 395 -198 195 -198 231 -398 131 -2124 65 -98 97 -132 229 -196 131 -330 97 -100 65 -328 397 -562 263 -394 129 -196 65 -330 165 -164 261 -492 133 -132 133 -1122 65 -164 165 -854 65 -196 99 -66 195 -200 131 -632 131 -100 65 -200 133 -400 359 -426 63 -824 63 -232 129 -98 195 -590 99 -1166 65 -1282 65 -626 -RAW_Data: 131 -366 131 -400 961 -166 893 -134 297 -98 133 -134 99 -800 99 -198 131 -564 165 -200 99 -698 295 -664 263 -164 99 -298 133 -100 97 -232 99 -1030 67 -132 393 -166 131 -162 131 -790 65 -528 63 -266 329 -334 361 -300 165 -232 167 -464 65 -164 99 -298 65 -200 295 -592 963 -166 199 -336 165 -200 165 -200 131 -134 133 -298 2091 -168 133 -166 133 -66 299 -264 961 -164 163 -100 65 -98 361 -164 229 -358 131 -66 361 -464 65 -100 197 -66 333 -66 99 -464 65 -266 65 -100 297 -198 229 -100 97 -398 99 -530 99 -530 67 -1522 65 -364 131 -266 101 -500 97 -200 197 -532 67 -1286 131 -1580 97 -360 165 -600 131 -68 197 -364 65 -132 99 -298 229 -132 99 -100 99 -132 1693 -132 1813 -954 195 -394 163 -328 165 -196 99 -164 65 -164 129 -592 65 -332 131 -526 131 -198 167 -202 201 -132 265 -134 165 -132 197 -100 131 -66 99 -132 65 -66 131 -564 65 -200 99 -300 163 -496 65 -662 67 -228 133 -166 99 -232 97 -164 263 -164 295 -522 65 -100 97 -100 65 -428 129 -132 195 -198 263 -360 65 -628 165 -494 65 -264 2503 -66 665 -530 133 -166 97 -630 65 -364 229 -100 65 -362 99 -196 129 -66 263 -164 131 -1288 65 -130 63 -330 99 -166 165 -466 97 -132 165 -1444 263 -134 65 -234 99 -300 65 -300 165 -232 167 -296 361 -726 97 -132 65 -230 63 -132 97 -100 2143 -890 197 -492 263 -132 131 -164 65 -428 65 -230 65 -100 129 -262 99 -64 97 -166 231 -532 131 -270 263 -98 365 -166 165 -930 299 -166 99 -298 431 -266 65 -796 267 -232 65 -200 131 -234 65 -1062 133 -1258 67 -398 65 -1096 65 -398 67 -1590 99 -198 133 -498 99 -66 97 -166 65 -400 233 -166 133 -132 131 -766 65 -334 65 -232 131 -234 131 -266 131 -200 65 -1062 331 -364 65 -798 265 -500 165 -198 131 -1260 523 -858 229 -164 263 -164 65 -194 97 -132 129 -164 131 -492 97 -394 131 -164 131 -330 65 -230 229 -198 65 -328 131 -526 97 -100 131 -164 1089 -198 561 -66 793 -334 461 -130 99 -556 261 -198 97 -462 197 -432 63 -530 131 -496 331 -400 65 -396 65 -566 167 -432 65 -896 133 -66 99 -100 65 -232 97 -98 163 -262 63 -398 197 -924 133 -498 131 -398 97 -730 99 -66 99 -264 131 -134 65 -830 99 -264 65 -730 231 -398 165 -532 199 -132 131 -596 231 -592 99 -296 97 -588 165 -690 97 -228 229 -1686 65 -166 131 -362 197 -66 65 -494 163 -230 231 -100 293 -532 99 -364 167 -1160 -RAW_Data: 65 -134 97 -234 65 -100 131 -132 99 -1028 231 -100 165 -100 265 -328 65 -328 361 -230 131 -502 133 -66 163 -166 65 -398 229 -132 99 -228 97 -66 227 -230 63 -758 97 -134 65 -464 231 -334 263 -528 65 -922 199 -428 1221 -364 99 -198 99 -100 197 -664 197 -466 97 -1096 199 -66 131 -336 65 -164 99 -332 165 -764 361 -920 131 -230 99 -954 295 -592 163 -198 197 -296 131 -98 65 -1452 65 -198 99 -166 165 -964 197 -630 2221 -298 65 -732 197 -396 201 -134 165 -100 99 -234 65 -100 165 -768 97 -826 97 -466 99 -860 67 -230 97 -100 165 -726 293 -66 163 -296 131 -334 97 -134 231 -790 97 -264 99 -626 197 -164 129 -232 97 -98 131 -430 97 -792 65 -2086 2325 -100 665 -232 97 -262 163 -396 195 -958 165 -134 231 -434 131 -232 65 -332 233 -200 99 -302 99 -230 131 -134 165 -200 431 -264 267 -132 263 -530 99 -592 99 -268 231 -100 97 -100 97 -264 199 -134 165 -402 261 -132 1333 -66 231 -134 1163 -398 99 -232 99 -134 165 -466 165 -66 131 -396 165 -298 395 -596 99 -664 131 -302 163 -432 65 -298 133 -1816 99 -1158 131 -66 2345 -132 63 -198 195 -560 197 -858 131 -860 133 -166 99 -200 231 -560 65 -66 197 -198 165 -566 65 -166 99 -298 65 -168 231 -658 99 -196 65 -496 65 -528 163 -230 97 -2384 229 -132 395 -164 65 -592 65 -232 65 -300 165 -232 435 -890 65 -98 299 -334 65 -698 265 -430 231 -626 131 -498 1061 -200 233 -132 165 -166 729 -400 65 -400 65 -930 65 -768 65 -598 131 -660 165 -332 165 -364 65 -1088 99 -198 97 -666 99 -132 65 -166 133 -168 165 -794 65 -1842 97 -232 131 -628 133 -298 131 -430 67 -132 65 -264 63 -262 65 -692 131 -98 99 -360 131 -464 65 -198 99 -1166 99 -266 99 -132 99 -66 65 -698 99 -366 65 -1656 99 -132 65 -168 267 -66 265 -564 65 -732 65 -332 167 -200 97 -98 233 -134 65 -434 197 -368 197 -100 99 -462 99 -466 65 -132 131 -632 131 -266 65 -200 65 -100 397 -1188 261 -132 229 -264 197 -492 163 -98 197 -1118 263 -1714 197 -528 295 -230 261 -758 65 -198 427 -264 65 -230 65 -66 97 -296 65 -132 197 -132 195 -492 99 -230 129 -164 165 -632 65 -998 65 -232 165 -200 133 -666 199 -100 131 -362 131 -560 133 -368 165 -498 527 -296 65 -98 65 -662 165 -532 131 -1184 99 -294 99 -66 527 -132 165 -266 165 -68 499 -860 165 -100 99 -132 65 -994 529 -498 133 -166 99 -630 133 -264 99 -266 -RAW_Data: 131 -332 165 -430 131 -1020 195 -592 97 -164 227 -460 131 -264 131 -1156 1451 -66 621 -332 133 -398 99 -66 199 -330 131 -562 233 -898 97 -662 97 -264 163 -230 463 -132 165 -166 165 -732 131 -100 165 -432 65 -762 65 -334 65 -132 165 -364 99 -862 99 -332 97 -164 229 -130 97 -264 97 -198 397 -1942 2037 -66 361 -66 1187 -230 65 -528 131 -726 131 -658 789 -132 97 -230 97 -232 97 -788 97 -98 197 -590 197 -530 65 -234 65 -530 133 -230 65 -992 65 -396 99 -232 165 -200 67 -394 229 -1230 65 -164 131 -892 229 -590 3025 -264 97 -164 163 -198 131 -362 361 -330 97 -130 65 -262 99 -66 131 -98 329 -98 197 -1284 65 -166 331 -168 199 -398 97 -164 97 -66 99 -398 363 -398 131 -300 233 -964 99 -464 65 -832 199 -396 99 -166 131 -526 65 -594 165 -590 99 -890 131 -200 65 -262 65 -296 1287 -164 589 -100 97 -660 165 -200 297 -132 67 -198 199 -1790 99 -362 99 -196 99 -362 131 -130 163 -98 65 -788 165 -264 263 -328 131 -690 65 -854 199 -200 199 -166 97 -262 131 -426 65 -360 497 -266 99 -266 199 -564 165 -266 65 -498 65 -98 131 -428 67 -464 65 -1192 199 -200 99 -132 267 -166 165 -134 231 -100 133 -98 133 -168 97 -100 99 -994 99 -336 97 -428 65 -364 129 -626 99 -1416 197 -230 131 -132 267 -532 995 -132 67 -530 463 -68 735 -270 65 -564 397 -100 167 -1028 163 -430 65 -166 99 -464 99 -2022 99 -266 65 -168 299 -464 99 -166 263 -1360 99 -564 131 -66 65 -98 99 -330 133 -1744 131 -758 65 -824 99 -990 65 -330 99 -266 99 -98 65 -796 165 -660 131 -330 295 -166 165 -300 297 -98 65 -364 129 -628 99 -434 231 -1028 133 -232 65 -498 197 -930 163 -166 99 -1264 65 -164 263 -362 629 -66 297 -100 133 -132 165 -132 165 -332 395 -134 97 -132 97 -132 263 -130 495 -198 525 -98 429 -398 429 -100 133 -266 133 -66 699 -166 65 -430 265 -132 463 -100 595 -264 131 -198 361 -230 131 -264 97 -364 63 -166 65 -360 361 -200 97 -730 99 -164 163 -198 129 -2146 65 -996 427 -1062 65 -166 97 -628 131 -494 197 -264 489 -198 63 -330 99 -460 65 -692 99 -164 199 -366 99 -1390 199 -132 163 -360 97 -264 97 -396 97 -196 65 -228 65 -294 165 -366 97 -1098 65 -664 199 -100 67 -798 97 -366 65 -166 65 -362 331 -166 65 -634 67 -300 67 -528 67 -496 165 -564 65 -598 99 -302 99 -100 101 -298 99 -400 97 -1550 131 -458 65 -1484 97 -230 -RAW_Data: 99 -656 229 -432 131 -98 131 -366 167 -958 165 -630 767 -98 65 -198 527 -132 363 -132 161 -130 131 -300 165 -134 99 -202 97 -566 97 -732 131 -198 65 -534 65 -298 165 -332 131 -662 199 -68 263 -200 465 -66 167 -134 99 -268 99 -332 167 -232 1229 -66 133 -134 963 -428 99 -68 65 -1224 165 -234 65 -132 233 -332 331 -132 131 -100 65 -1660 131 -100 397 -100 65 -198 65 -596 99 -398 99 -1126 163 -1616 65 -294 65 -330 197 -754 199 -496 133 -928 231 -728 99 -1094 3657 -132 65 -464 133 -532 131 -564 99 -466 97 -168 197 -100 133 -730 63 -300 429 -370 131 -630 267 -532 97 -266 65 -200 67 -132 99 -394 131 -328 165 -1056 165 -198 165 -230 65 -130 65 -198 97 -460 133 -198 99 -232 67 -432 231 -98 67 -758 165 -494 97 -166 3081 -198 63 -198 163 -262 131 -534 99 -498 331 -430 65 -198 99 -498 131 -696 65 -166 165 -500 65 -626 263 -298 97 -100 129 -858 99 -296 97 -560 99 -98 197 -198 163 -200 297 -332 131 -68 65 -100 165 -332 131 -134 363 -232 67 -430 165 -166 101 -364 65 -462 167 -298 97 -200 65 -332 65 -134 1189 -66 295 -100 1127 -266 133 -896 165 -262 197 -1514 197 -360 131 -66 163 -330 97 -726 63 -66 195 -690 297 -928 199 -132 165 -232 97 -132 99 -564 99 -332 165 -268 197 -100 65 -498 67 -464 165 -132 333 -364 99 -100 165 -100 99 -134 97 -632 99 -102 131 -198 97 -466 99 -500 165 -132 99 -164 195 -294 2109 -330 199 -1262 165 -1094 197 -228 263 -658 133 -922 97 -264 97 -556 165 -262 99 -98 425 -986 131 -394 65 -494 131 -98 131 -460 97 -428 295 -792 129 -66 131 -132 65 -328 133 -132 165 -66 265 -200 97 -234 331 -100 65 -100 65 -328 1637 -254 271 -258 279 -282 227 -296 263 -270 641 -314 253 -256 253 -288 247 -238 259 -256 257 -294 233 -302 265 -234 299 -266 233 -300 231 -296 229 -264 255 -290 231 -300 399 -288 243 -5348 273 -274 269 -238 299 -4900 239 -244 271 -400 311 -252 249 -280 237 -266 259 -262 655 -280 255 -254 291 -388 241 -290 255 -254 249 -278 273 -240 301 -230 261 -296 265 -266 231 -264 257 -290 265 -266 231 -264 263 -262 295 -234 299 -234 293 -264 267 -266 233 -262 261 -262 295 -236 299 -266 235 -300 231 -262 263 -262 257 -290 263 -266 231 -266 261 -264 293 -268 273 -268 233 -264 261 -262 287 -266 269 -270 271 -268 231 -262 255 -258 291 -262 269 -268 231 -264 293 -234 301 -266 233 -300 231 -264 261 -262 -RAW_Data: 263 -262 255 -292 265 -266 263 -270 273 -236 259 -260 289 -262 267 -268 265 -236 301 -230 295 -264 233 -300 231 -262 263 -262 257 -258 291 -264 267 -266 265 -234 301 -266 235 -300 229 -264 261 -264 259 -296 229 -296 229 -262 295 -236 299 -264 269 -266 231 -264 261 -264 255 -258 291 -264 267 -274 269 -266 233 -300 231 -264 259 -262 257 -292 265 -266 231 -264 295 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -266 231 -264 263 -264 293 -234 301 -266 267 -266 231 -264 261 -262 255 -292 265 -266 231 -296 263 -270 271 -268 231 -264 263 -262 261 -262 257 -290 265 -266 231 -266 295 -234 299 -266 267 -268 231 -264 261 -260 263 -262 257 -290 265 -266 265 -270 271 -236 261 -292 231 -298 231 -264 295 -270 271 -268 233 -262 261 -262 255 -258 293 -230 293 -264 269 -266 265 -270 271 -270 231 -264 261 -260 257 -290 265 -274 269 -266 235 -268 263 -262 255 -290 265 -234 259 -260 291 -262 267 -274 269 -266 269 -266 231 -262 261 -264 255 -290 265 -232 259 -294 265 -272 269 -266 267 -268 231 -262 261 -262 257 -258 291 -264 267 -268 233 -262 295 -234 299 -264 269 -268 231 -262 261 -264 255 -290 265 -274 269 -234 295 -262 267 -264 233 -264 257 -256 291 -264 267 -268 265 -268 273 -268 231 -264 261 -260 261 -264 295 -270 273 -268 231 -264 255 -290 265 -266 233 -264 261 -262 295 -234 301 -266 267 -266 231 -264 257 -288 265 -234 259 -258 293 -262 269 -266 265 -234 301 -266 267 -266 231 -262 263 -262 263 -262 257 -290 263 -268 231 -264 295 -270 271 -236 259 -292 263 -232 259 -294 265 -264 231 -264 295 -236 299 -264 269 -268 229 -264 261 -262 263 -262 263 -262 261 -264 295 -268 271 -270 231 -264 255 -290 265 -268 265 -270 271 -236 265 -262 255 -290 265 -268 231 -264 261 -262 295 -234 301 -266 269 -232 263 -264 261 -262 255 -292 265 -266 233 -296 269 -272 235 -266 257 -290 263 -232 261 -292 265 -266 265 -236 299 -266 267 -234 263 -264 261 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 263 -262 261 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 257 -256 291 -264 267 -240 303 -266 269 -232 265 -262 261 -262 261 -264 261 -264 261 -262 295 -236 299 -266 267 -268 231 -262 261 -262 261 -264 261 -264 255 -290 267 -266 265 -236 299 -232 295 -262 267 -268 231 -264 261 -262 261 -262 295 -236 299 -266 269 -234 263 -262 257 -290 265 -232 259 -292 267 -264 -RAW_Data: 233 -264 295 -268 273 -268 231 -264 261 -262 261 -264 255 -290 267 -266 231 -296 269 -240 263 -294 265 -266 231 -264 293 -234 301 -266 267 -266 231 -264 261 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -264 261 -262 295 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -268 231 -264 293 -234 299 -266 269 -268 231 -264 261 -260 261 -264 255 -258 293 -262 269 -240 303 -266 267 -234 263 -262 261 -262 257 -290 265 -234 261 -258 291 -262 269 -274 275 -236 265 -262 261 -260 257 -290 265 -268 231 -264 295 -236 299 -264 269 -234 263 -262 257 -258 291 -264 267 -236 263 -264 293 -268 273 -270 231 -264 261 -260 263 -262 263 -262 261 -264 295 -268 273 -268 231 -264 261 -262 255 -258 293 -262 269 -268 231 -264 293 -234 301 -232 295 -262 267 -268 231 -264 259 -262 263 -262 257 -290 265 -274 269 -266 269 -232 265 -262 261 -262 255 -258 293 -270 271 -272 269 -234 265 -262 259 -262 263 -262 257 -290 267 -266 265 -236 301 -264 267 -234 263 -264 261 -262 257 -288 267 -266 233 -264 295 -268 273 -234 261 -290 265 -232 259 -292 265 -266 265 -236 299 -266 267 -234 263 -264 261 -260 263 -262 263 -262 263 -262 295 -236 299 -266 267 -234 263 -264 261 -262 257 -290 265 -268 231 -264 293 -236 299 -266 269 -234 263 -262 261 -294 229 -264 257 -290 265 -274 267 -268 233 -300 231 -264 259 -262 257 -292 265 -266 231 -296 263 -236 299 -266 267 -266 231 -264 261 -264 261 -262 255 -292 265 -266 233 -264 293 -234 299 -266 269 -268 231 -262 261 -294 229 -264 263 -262 257 -290 265 -272 275 -270 233 -262 261 -262 261 -294 229 -264 257 -290 233 -298 265 -236 299 -266 235 -300 231 -262 263 -262 257 -290 265 -266 231 -296 263 -268 273 -268 233 -262 257 -258 289 -264 267 -268 263 -236 301 -264 267 -266 231 -264 257 -290 231 -266 259 -294 231 -300 263 -236 301 -266 233 -300 231 -262 261 -262 257 -258 293 -264 267 -268 263 -236 299 -264 235 -300 231 -264 261 -264 255 -258 291 -262 267 -268 265 -236 299 -266 267 -266 231 -264 261 -264 261 -294 229 -264 257 -290 265 -272 267 -268 235 -300 229 -296 229 -264 255 -290 265 -268 231 -264 257 -290 265 -266 263 -236 301 -266 233 -300 231 -264 261 -264 255 -290 265 -272 269 -266 235 -300 231 -264 261 -294 229 -262 259 -290 231 -298 231 -298 229 -264 293 -268 273 -268 233 -264 261 -262 261 -294 229 -296 229 -296 269 -272 237 -266 257 -290 -RAW_Data: 229 -300 231 -296 263 -268 273 -268 233 -264 259 -294 229 -296 231 -262 257 -290 231 -300 265 -234 301 -266 235 -300 229 -264 261 -294 229 -296 263 -236 299 -264 269 -266 231 -296 229 -262 261 -262 257 -292 231 -266 261 -292 265 -270 269 -266 235 -300 231 -264 261 -294 229 -296 229 -264 261 -264 293 -234 301 -266 233 -300 231 -264 261 -264 261 -262 261 -262 289 -300 241 -274 233 -266 261 -262 259 -262 257 -292 265 -266 263 -236 301 -266 235 -300 229 -264 261 -262 257 -258 291 -230 295 -264 233 -302 263 -234 301 -266 235 -298 231 -296 229 -262 263 -262 257 -290 265 -266 231 -296 265 -234 299 -232 293 -264 267 -234 259 -292 231 -300 263 -236 301 -232 263 -294 267 -266 233 -262 261 -262 257 -258 293 -262 269 -266 265 -234 301 -264 267 -266 231 -264 263 -262 295 -270 271 -268 231 -264 261 -294 229 -264 257 -290 265 -266 265 -236 301 -266 233 -300 231 -262 261 -262 263 -262 257 -258 291 -264 267 -274 273 -270 233 -262 257 -256 291 -262 269 -268 263 -236 301 -264 267 -266 231 -264 261 -264 261 -262 261 -262 257 -292 265 -272 269 -266 269 -266 231 -262 257 -256 291 -230 295 -264 269 -266 265 -236 299 -264 267 -268 231 -262 263 -262 257 -290 265 -266 231 -264 295 -270 271 -270 231 -262 261 -262 261 -264 257 -258 291 -262 269 -274 267 -268 267 -266 231 -262 261 -262 257 -290 265 -234 259 -292 265 -266 265 -236 299 -234 295 -262 267 -264 231 -264 257 -258 293 -228 293 -264 269 -274 275 -270 231 -264 259 -262 255 -292 265 -266 231 -264 257 -290 265 -266 267 -270 271 -270 231 -262 261 -262 255 -258 291 -230 295 -264 269 -272 275 -238 259 -258 291 -260 267 -268 265 -270 273 -268 231 -264 259 -262 263 -262 257 -290 265 -266 231 -264 297 -234 299 -266 267 -268 231 -262 257 -256 293 -268 271 -272 271 -236 263 -262 261 -260 263 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -268 231 -262 257 -290 265 -264 231 -266 263 -262 295 -268 273 -268 231 -264 261 -262 255 -292 265 -266 233 -262 257 -290 265 -266 265 -270 271 -236 261 -290 265 -266 231 -264 261 -264 295 -234 299 -266 267 -266 231 -264 257 -290 265 -264 233 -264 261 -264 295 -234 299 -266 267 -268 231 -262 261 -264 255 -292 263 -266 231 -266 257 -290 263 -274 269 -266 269 -234 263 -262 257 -256 293 -262 269 -268 263 -236 299 -232 293 -264 267 -266 233 -264 261 -262 255 -290 267 -266 231 -264 295 -236 299 -264 269 -266 -RAW_Data: 231 -262 263 -262 289 -264 269 -270 271 -234 265 -262 255 -258 291 -262 269 -268 265 -234 299 -266 269 -266 231 -262 261 -264 261 -262 261 -264 257 -290 265 -272 269 -266 269 -234 259 -258 289 -262 267 -268 265 -236 301 -264 267 -266 231 -264 261 -264 261 -262 257 -258 291 -264 267 -274 267 -266 269 -266 231 -262 257 -290 265 -266 231 -264 263 -262 295 -236 299 -264 269 -266 231 -262 263 -262 261 -264 255 -292 265 -266 265 -270 271 -270 231 -262 261 -262 257 -256 293 -262 269 -268 265 -234 301 -264 267 -268 231 -262 263 -262 257 -290 263 -234 261 -258 291 -262 267 -268 265 -236 301 -264 267 -266 231 -264 261 -264 255 -290 265 -232 261 -292 273 -276 237 -266 263 -264 259 -262 261 -264 255 -290 265 -266 231 -266 295 -234 299 -266 269 -234 263 -262 263 -262 261 -264 255 -290 265 -274 267 -268 269 -234 263 -262 255 -290 265 -268 265 -236 299 -264 269 -234 263 -262 257 -258 291 -230 295 -264 267 -268 265 -234 299 -266 267 -234 263 -262 257 -290 267 -238 301 -268 269 -232 263 -264 261 -262 255 -292 265 -266 233 -264 261 -262 295 -236 299 -264 269 -234 263 -264 255 -290 265 -234 259 -292 233 -298 265 -270 271 -270 231 -264 261 -260 261 -264 257 -292 263 -266 231 -266 263 -262 293 -268 273 -236 261 -258 289 -262 267 -268 265 -236 301 -264 267 -268 229 -264 261 -264 257 -256 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 257 -290 265 -232 259 -294 265 -266 263 -236 301 -266 267 -234 263 -262 263 -262 257 -290 263 -268 231 -264 297 -234 299 -264 269 -266 231 -264 261 -262 257 -290 265 -266 231 -264 263 -262 295 -234 299 -266 269 -266 231 -264 255 -258 291 -230 295 -304 245 -272 235 -264 255 -290 263 -266 231 -264 297 -234 299 -266 269 -232 265 -262 261 -262 257 -290 265 -234 259 -292 265 -266 265 -270 273 -236 263 -264 255 -290 265 -266 265 -234 301 -266 269 -232 265 -262 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -268 229 -264 263 -262 261 -262 263 -262 263 -262 295 -234 301 -264 269 -266 231 -262 263 -262 257 -290 265 -232 259 -292 267 -272 275 -238 265 -262 261 -260 257 -290 265 -234 261 -290 265 -266 265 -270 271 -270 231 -264 261 -262 255 -258 291 -264 267 -268 233 -262 295 -234 299 -264 269 -268 231 -264 261 -262 255 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 263 -262 257 -290 265 -264 233 -264 295 -236 299 -264 269 -234 263 -264 -RAW_Data: 261 -262 263 -262 261 -262 257 -290 265 -274 267 -268 267 -234 259 -290 265 -266 263 -236 301 -266 269 -232 265 -262 261 -262 261 -264 257 -290 265 -266 265 -234 301 -266 269 -232 265 -262 261 -264 261 -264 261 -262 289 -264 277 -272 235 -264 261 -260 257 -290 265 -234 259 -292 265 -272 269 -234 295 -262 267 -266 231 -264 261 -264 261 -262 257 -290 265 -268 265 -268 273 -268 231 -264 261 -262 255 -292 265 -266 231 -264 257 -290 265 -266 265 -236 299 -266 269 -234 263 -262 263 -262 293 -234 301 -266 269 -234 263 -262 263 -262 257 -290 263 -266 231 -266 295 -234 299 -266 269 -234 263 -262 263 -262 257 -290 263 -234 259 -292 267 -266 231 -262 297 -268 271 -270 231 -264 261 -260 257 -290 265 -274 275 -270 233 -262 255 -290 265 -266 231 -264 263 -262 295 -234 299 -266 269 -266 231 -262 263 -262 257 -290 265 -232 261 -292 265 -272 269 -266 269 -232 263 -264 255 -290 265 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -258 291 -262 269 -234 261 -290 265 -264 265 -270 273 -268 231 -264 261 -262 261 -262 295 -270 273 -268 231 -264 261 -260 263 -262 257 -292 265 -232 259 -292 265 -266 265 -268 273 -270 233 -262 261 -262 255 -258 291 -264 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -262 263 -262 257 -290 267 -272 275 -270 233 -262 261 -260 257 -290 265 -234 259 -292 265 -266 265 -270 273 -268 231 -264 257 -256 289 -262 269 -234 261 -292 265 -264 265 -236 299 -266 269 -266 231 -262 263 -262 261 -264 255 -290 265 -266 231 -264 297 -268 273 -268 231 -264 255 -290 265 -266 231 -264 263 -262 295 -236 299 -264 269 -234 263 -264 261 -262 257 -290 265 -232 261 -292 265 -266 265 -234 301 -266 269 -232 263 -264 259 -262 295 -270 273 -270 231 -264 259 -262 255 -258 293 -262 269 -234 261 -290 265 -266 263 -270 273 -270 231 -262 261 -262 261 -264 257 -322 239 -278 239 -268 261 -260 255 -290 265 -266 233 -264 295 -234 299 -266 269 -234 263 -262 263 -262 255 -258 291 -230 295 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 255 -290 265 -268 231 -264 261 -262 295 -234 301 -266 269 -232 265 -262 255 -290 265 -274 269 -268 267 -234 263 -262 261 -262 257 -290 265 -234 259 -292 265 -272 269 -266 269 -234 263 -264 259 -262 263 -262 257 -258 291 -262 269 -268 231 -264 295 -268 271 -270 231 -264 261 -260 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 -RAW_Data: 261 -262 257 -292 265 -266 231 -264 295 -236 299 -264 269 -234 263 -262 257 -290 265 -266 231 -264 263 -296 269 -272 235 -268 255 -290 263 -266 231 -264 263 -262 295 -234 301 -264 269 -266 231 -262 263 -262 257 -290 265 -234 259 -292 265 -272 269 -266 269 -232 265 -262 261 -264 255 -258 291 -262 269 -268 231 -264 293 -234 301 -266 267 -266 231 -264 257 -288 265 -266 231 -266 295 -234 299 -266 269 -234 263 -262 263 -262 257 -256 291 -264 269 -266 265 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -234 259 -292 265 -266 231 -264 295 -268 273 -268 231 -264 261 -262 255 -292 265 -266 265 -236 299 -266 269 -232 265 -262 261 -262 257 -290 265 -268 231 -264 257 -290 263 -272 269 -268 269 -234 263 -262 261 -262 261 -264 261 -296 269 -272 235 -268 255 -290 265 -232 259 -292 265 -274 267 -268 267 -234 263 -264 261 -262 261 -262 257 -290 265 -268 231 -264 295 -270 271 -268 233 -262 261 -262 261 -264 295 -234 301 -266 267 -234 263 -262 261 -262 263 -262 263 -262 261 -264 295 -234 301 -266 269 -232 265 -262 261 -260 257 -258 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 255 -290 265 -268 231 -264 289 -264 269 -268 271 -236 265 -262 255 -290 265 -232 259 -292 265 -266 265 -270 273 -270 231 -262 261 -262 255 -258 293 -262 269 -268 231 -262 295 -234 299 -266 269 -266 231 -264 261 -262 261 -264 255 -292 265 -264 265 -236 301 -266 267 -234 263 -264 261 -262 255 -290 267 -266 233 -264 295 -234 299 -232 295 -262 269 -266 231 -264 257 -256 291 -262 269 -268 231 -262 295 -270 271 -270 231 -262 257 -290 263 -268 265 -270 273 -234 265 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -232 265 -262 261 -262 257 -258 291 -264 267 -268 273 -274 235 -266 255 -256 289 -230 295 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 263 -262 255 -290 265 -268 265 -236 299 -264 269 -266 231 -262 257 -290 265 -234 259 -292 265 -266 265 -236 301 -232 293 -264 267 -266 231 -262 257 -290 265 -266 233 -264 295 -268 273 -268 231 -264 261 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -266 231 -262 263 -262 257 -256 291 -264 267 -236 259 -292 263 -272 269 -266 269 -266 229 -264 261 -264 255 -290 267 -272 269 -266 269 -234 263 -262 261 -262 257 -290 265 -234 261 -292 265 -264 231 -264 295 -270 271 -270 231 -262 257 -256 291 -230 295 -264 269 -266 -RAW_Data: 271 -240 263 -262 291 -228 293 -264 267 -240 303 -266 269 -232 265 -262 259 -262 257 -292 265 -232 261 -292 265 -264 265 -270 273 -268 233 -262 261 -262 255 -292 265 -272 277 -270 231 -264 259 -262 261 -264 255 -292 265 -232 259 -292 267 -264 265 -270 273 -268 231 -264 261 -262 261 -262 263 -262 263 -262 295 -236 299 -264 269 -266 231 -264 261 -264 261 -262 261 -264 255 -292 265 -264 265 -270 273 -270 231 -264 255 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 233 -262 261 -262 255 -290 265 -268 231 -266 255 -290 265 -272 269 -234 295 -228 295 -230 293 -264 269 -266 233 -262 295 -234 297 -266 269 -268 231 -264 261 -260 257 -290 265 -234 261 -290 265 -266 265 -270 271 -270 231 -262 261 -262 289 -266 267 -270 273 -234 265 -262 255 -256 291 -264 267 -268 231 -264 295 -234 299 -266 269 -234 263 -262 263 -262 261 -264 255 -290 265 -266 265 -270 273 -236 261 -290 265 -264 231 -264 295 -236 299 -232 295 -262 269 -266 231 -262 263 -262 257 -258 291 -262 269 -266 265 -236 299 -266 267 -234 263 -262 263 -262 263 -262 261 -262 261 -264 295 -236 299 -266 267 -234 263 -264 261 -262 257 -258 291 -262 269 -240 303 -266 267 -234 263 -264 261 -262 255 -290 267 -266 231 -264 295 -236 299 -266 267 -234 263 -262 257 -258 291 -264 267 -268 265 -236 299 -264 267 -234 263 -264 255 -258 291 -230 295 -264 269 -234 297 -236 299 -264 267 -268 231 -262 263 -262 257 -290 265 -264 233 -264 263 -262 293 -234 301 -266 269 -234 263 -262 261 -262 263 -262 261 -264 255 -292 265 -266 267 -270 271 -236 259 -290 265 -264 233 -264 295 -268 273 -268 231 -264 261 -262 255 -258 293 -230 293 -264 269 -266 265 -268 273 -268 233 -262 261 -262 255 -290 267 -272 269 -268 269 -232 263 -264 255 -290 265 -234 259 -260 291 -262 267 -268 265 -270 271 -236 265 -262 261 -262 255 -292 265 -234 259 -292 265 -272 269 -266 267 -234 263 -264 261 -264 255 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -264 261 -264 255 -290 265 -272 269 -234 295 -262 267 -266 231 -264 257 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -266 231 -264 261 -262 261 -264 255 -290 265 -268 231 -264 295 -236 299 -264 267 -266 231 -264 263 -262 257 -290 265 -264 265 -236 301 -266 269 -266 231 -262 261 -262 261 -264 261 -264 255 -290 267 -266 -RAW_Data: 265 -270 273 -236 263 -264 259 -262 257 -258 291 -304 243 -276 235 -264 255 -288 265 -266 231 -264 263 -262 293 -234 301 -266 269 -234 263 -264 255 -290 265 -232 259 -294 265 -266 263 -236 301 -266 269 -232 259 -290 265 -266 231 -264 295 -268 273 -268 233 -262 261 -262 261 -264 261 -264 261 -262 263 -262 295 -236 299 -266 267 -234 263 -264 261 -264 255 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 261 -262 263 -262 295 -236 299 -264 269 -234 263 -262 257 -290 265 -232 259 -294 265 -266 263 -236 301 -266 269 -232 265 -262 255 -258 291 -264 267 -234 261 -290 265 -266 265 -236 299 -266 267 -234 263 -264 261 -262 263 -262 263 -262 261 -262 295 -270 271 -270 231 -264 261 -260 257 -290 265 -234 261 -292 265 -238 301 -266 269 -234 263 -264 261 -262 257 -256 291 -264 267 -268 233 -262 295 -234 299 -266 269 -232 259 -258 293 -262 267 -274 269 -266 267 -266 231 -262 263 -262 257 -256 293 -230 293 -264 269 -266 263 -236 301 -266 267 -234 263 -262 261 -262 295 -236 301 -266 267 -266 231 -262 257 -290 265 -232 261 -292 265 -266 265 -234 301 -266 267 -266 231 -262 263 -262 263 -262 257 -256 291 -264 269 -272 269 -266 269 -234 263 -262 261 -262 261 -264 261 -264 255 -290 267 -266 231 -262 297 -268 273 -268 233 -262 261 -262 261 -264 295 -268 273 -270 231 -264 259 -262 255 -292 265 -266 233 -264 261 -264 293 -234 301 -266 267 -234 263 -264 261 -262 261 -264 255 -258 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -262 263 -262 261 -264 293 -234 301 -266 269 -232 265 -262 261 -264 261 -262 257 -290 265 -266 231 -264 295 -270 271 -270 231 -264 261 -260 263 -262 263 -294 269 -272 237 -266 261 -262 261 -262 261 -264 261 -264 295 -234 301 -266 269 -232 263 -264 255 -290 265 -234 259 -292 265 -266 265 -234 301 -266 269 -232 265 -262 261 -260 295 -236 301 -266 267 -266 231 -264 255 -290 265 -268 231 -264 257 -290 265 -264 265 -236 301 -266 267 -268 229 -264 255 -258 291 -230 295 -264 267 -268 263 -236 299 -266 267 -266 231 -264 261 -264 261 -262 257 -290 265 -272 269 -268 267 -234 263 -264 255 -290 265 -232 261 -292 267 -264 265 -236 299 -264 269 -266 233 -262 257 -290 263 -234 259 -292 265 -266 265 -236 299 -234 293 -262 267 -268 231 -264 261 -262 261 -262 263 -262 257 -290 265 -274 269 -266 269 -232 259 -290 265 -266 231 -264 257 -290 265 -266 263 -236 -RAW_Data: 301 -266 269 -266 231 -262 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -234 259 -290 265 -266 265 -270 273 -268 233 -262 261 -262 255 -258 293 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -262 263 -262 261 -262 257 -324 239 -276 239 -268 261 -262 255 -290 265 -266 231 -264 263 -262 295 -236 299 -264 269 -266 231 -262 263 -262 261 -262 257 -290 267 -266 267 -234 299 -266 267 -266 231 -264 261 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -232 293 -264 267 -234 259 -292 265 -264 265 -270 273 -270 231 -262 261 -262 257 -290 265 -234 261 -290 265 -266 265 -236 299 -264 269 -266 231 -264 261 -262 257 -258 291 -262 269 -268 231 -264 293 -234 301 -266 267 -266 231 -264 261 -262 263 -262 295 -234 299 -266 269 -266 231 -262 261 -262 257 -292 265 -266 231 -264 295 -234 301 -264 269 -266 231 -262 263 -262 257 -290 265 -266 231 -264 263 -296 267 -272 237 -266 257 -288 265 -264 265 -236 301 -266 269 -266 229 -264 261 -264 261 -262 263 -262 255 -292 265 -266 263 -236 301 -266 267 -268 231 -262 261 -262 295 -236 299 -266 269 -234 263 -262 261 -262 261 -264 261 -264 255 -292 265 -266 263 -236 301 -266 269 -266 231 -262 257 -256 291 -230 295 -264 267 -268 263 -270 273 -268 231 -264 261 -262 255 -292 265 -232 261 -260 289 -262 267 -274 277 -270 231 -262 257 -256 291 -264 267 -268 231 -264 293 -234 301 -264 269 -266 231 -262 263 -262 257 -258 291 -262 269 -268 265 -234 301 -230 295 -264 267 -266 231 -264 261 -262 257 -290 265 -232 259 -294 265 -272 269 -266 269 -232 259 -292 263 -234 259 -292 265 -264 265 -236 301 -232 295 -262 267 -268 231 -262 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 295 -268 273 -268 231 -264 261 -262 261 -264 255 -292 265 -266 263 -236 301 -266 269 -266 231 -262 261 -264 261 -262 257 -290 265 -266 231 -298 269 -272 235 -266 263 -260 261 -262 257 -290 267 -266 265 -234 301 -234 293 -262 267 -268 231 -264 261 -260 263 -262 257 -292 265 -272 267 -268 267 -266 231 -264 261 -262 257 -290 265 -266 231 -264 295 -236 299 -266 267 -268 231 -262 261 -262 261 -264 263 -262 293 -268 273 -270 233 -262 261 -262 261 -264 257 -258 291 -262 267 -274 269 -266 269 -266 231 -262 261 -262 257 -290 265 -234 261 -292 265 -264 265 -236 299 -232 295 -262 269 -266 231 -264 255 -258 291 -230 295 -264 267 -274 273 -270 -RAW_Data: 233 -262 261 -262 255 -290 267 -266 233 -264 257 -288 265 -266 265 -236 299 -266 269 -266 231 -262 257 -258 291 -230 295 -264 267 -272 275 -238 259 -258 289 -262 267 -268 265 -270 271 -268 233 -262 261 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -264 269 -268 229 -264 261 -262 263 -262 295 -236 299 -266 267 -266 231 -262 263 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -266 269 -266 229 -264 261 -262 263 -262 261 -264 261 -262 295 -234 301 -266 267 -268 229 -264 261 -262 263 -262 257 -290 265 -266 265 -270 273 -268 231 -264 255 -290 265 -266 231 -264 297 -234 299 -264 269 -266 231 -264 257 -290 265 -266 231 -264 261 -264 295 -234 299 -266 269 -266 231 -262 261 -264 255 -290 265 -266 233 -264 257 -290 265 -272 267 -268 269 -234 263 -262 255 -258 293 -262 269 -266 265 -234 301 -230 295 -264 267 -268 231 -262 261 -264 255 -292 263 -266 231 -266 295 -234 301 -264 267 -268 231 -264 261 -260 289 -264 271 -270 271 -236 263 -262 257 -256 291 -262 269 -266 267 -234 299 -266 267 -266 231 -264 263 -262 261 -262 261 -264 257 -290 265 -272 269 -266 269 -232 259 -260 289 -262 267 -268 265 -236 301 -264 267 -266 231 -264 261 -264 261 -262 257 -258 291 -262 269 -274 267 -266 269 -266 231 -262 263 -262 261 -260 263 -262 263 -264 295 -234 301 -264 269 -266 231 -264 259 -262 263 -262 257 -290 265 -266 265 -270 273 -270 231 -264 259 -262 261 -264 255 -292 265 -266 265 -236 301 -264 267 -266 231 -264 263 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -232 295 -264 267 -266 231 -264 255 -258 291 -264 269 -266 231 -296 269 -272 235 -266 263 -262 261 -260 261 -264 257 -292 263 -266 231 -264 297 -234 299 -266 269 -266 231 -262 261 -264 261 -262 257 -290 265 -272 269 -234 295 -230 293 -262 269 -268 265 -268 273 -268 231 -264 261 -260 263 -262 257 -258 291 -264 267 -268 265 -234 299 -266 267 -268 231 -262 257 -256 293 -262 269 -272 275 -270 233 -262 255 -258 289 -262 269 -234 261 -292 265 -264 265 -236 301 -266 233 -268 263 -262 261 -262 257 -290 265 -266 233 -264 295 -236 299 -264 269 -266 231 -262 257 -256 291 -264 269 -266 233 -262 295 -234 299 -266 269 -266 231 -264 261 -262 261 -262 261 -264 295 -234 299 -266 269 -266 231 -264 257 -256 291 -230 295 -264 269 -266 263 -236 299 -266 267 -268 231 -262 261 -262 261 -264 263 -262 257 -290 265 -266 265 -268 273 -270 -RAW_Data: 233 -262 261 -262 255 -292 265 -266 233 -262 295 -234 299 -268 267 -266 231 -262 261 -262 257 -292 265 -266 231 -264 263 -262 295 -234 299 -266 269 -266 231 -262 257 -258 291 -230 295 -304 243 -274 235 -264 255 -290 263 -266 231 -264 295 -236 299 -264 269 -268 231 -262 261 -262 257 -290 265 -234 261 -292 263 -266 265 -268 273 -270 231 -264 255 -290 265 -266 263 -236 301 -266 269 -266 231 -262 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -268 229 -264 263 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -262 263 -262 257 -290 265 -264 233 -264 295 -270 271 -268 233 -262 261 -262 257 -290 265 -234 259 -292 265 -266 263 -270 273 -270 231 -264 261 -260 257 -258 291 -264 267 -268 231 -264 293 -234 301 -266 267 -268 231 -262 263 -262 257 -290 263 -268 231 -264 261 -262 295 -268 273 -236 261 -290 265 -232 259 -292 265 -266 231 -264 295 -234 301 -264 269 -266 231 -262 263 -262 257 -290 265 -232 261 -292 265 -272 267 -266 269 -234 259 -290 265 -266 265 -234 301 -266 269 -266 229 -264 261 -264 261 -262 257 -290 265 -266 263 -236 301 -266 269 -266 231 -262 257 -290 263 -266 231 -298 269 -272 235 -266 263 -260 263 -262 261 -264 255 -292 265 -266 267 -234 299 -266 267 -266 231 -264 257 -258 289 -262 269 -268 231 -264 295 -268 273 -268 231 -264 261 -262 261 -262 257 -292 265 -264 233 -264 295 -236 299 -264 269 -266 231 -262 261 -264 261 -264 261 -262 295 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -266 231 -264 297 -234 299 -266 269 -266 231 -262 261 -264 255 -292 265 -232 259 -260 291 -262 269 -266 265 -270 273 -268 231 -262 261 -262 257 -290 265 -266 265 -236 301 -266 267 -266 231 -262 263 -262 263 -262 261 -264 255 -290 265 -266 267 -236 299 -232 293 -264 267 -266 231 -264 263 -262 257 -256 293 -302 243 -274 235 -266 261 -260 257 -256 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 263 -262 261 -264 257 -288 265 -266 265 -270 273 -270 231 -262 261 -262 255 -292 265 -234 259 -260 291 -260 269 -266 267 -236 299 -264 269 -232 259 -260 291 -260 269 -266 267 -236 299 -264 269 -266 231 -262 263 -262 261 -264 261 -262 261 -262 295 -236 301 -266 233 -300 231 -264 259 -262 257 -258 293 -262 269 -234 259 -292 263 -266 265 -270 271 -270 231 -264 261 -262 255 -290 267 -266 263 -236 301 -234 293 -262 267 -266 231 -264 263 -262 257 -290 -RAW_Data: 265 -234 259 -292 265 -272 267 -268 269 -266 231 -262 261 -262 261 -264 295 -268 273 -268 233 -262 261 -262 257 -290 265 -268 265 -236 299 -264 267 -266 231 -264 263 -262 261 -262 257 -290 265 -266 231 -266 295 -268 271 -270 231 -264 255 -290 265 -266 265 -236 299 -266 269 -266 231 -262 261 -264 261 -264 255 -290 265 -268 231 -264 295 -268 273 -268 231 -264 261 -262 255 -260 291 -262 269 -266 231 -264 295 -270 271 -268 231 -264 261 -262 261 -264 257 -290 265 -266 263 -270 273 -270 231 -264 261 -260 263 -262 257 -290 265 -266 231 -264 297 -268 273 -268 231 -264 261 -262 261 -262 257 -258 293 -262 269 -266 263 -236 301 -266 235 -300 229 -264 259 -262 263 -262 257 -258 291 -264 267 -268 265 -270 271 -268 231 -264 261 -262 261 -262 257 -292 265 -266 263 -236 301 -232 295 -262 267 -266 231 -264 257 -258 291 -228 295 -264 267 -268 265 -268 273 -236 261 -258 291 -260 267 -274 269 -266 267 -268 229 -264 255 -258 293 -262 269 -268 231 -262 295 -234 299 -264 269 -268 231 -262 261 -262 263 -262 257 -324 239 -274 239 -266 265 -262 255 -290 265 -264 233 -264 263 -262 293 -236 299 -266 269 -266 229 -264 257 -290 265 -266 231 -264 263 -262 295 -268 273 -268 231 -264 261 -262 261 -264 263 -262 257 -290 265 -266 231 -264 295 -234 299 -266 269 -232 259 -292 265 -266 231 -264 295 -234 299 -266 267 -266 231 -264 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 257 -290 265 -232 259 -292 265 -266 231 -266 295 -268 271 -270 231 -264 261 -260 257 -290 267 -266 265 -236 299 -264 269 -266 231 -264 261 -264 255 -290 265 -266 231 -264 259 -290 265 -266 263 -270 273 -268 231 -264 261 -262 261 -264 261 -296 269 -272 235 -266 259 -288 265 -232 259 -292 265 -272 269 -266 269 -266 231 -262 261 -262 263 -262 257 -292 265 -264 231 -264 295 -270 271 -270 231 -264 261 -262 261 -294 263 -236 299 -266 269 -266 231 -262 263 -262 261 -262 257 -290 265 -266 233 -264 295 -268 271 -270 231 -264 261 -262 255 -292 265 -266 231 -264 295 -236 299 -264 269 -266 231 -262 263 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 257 -290 265 -232 259 -292 265 -266 265 -268 273 -270 233 -262 261 -262 255 -258 293 -262 269 -268 231 -262 295 -234 299 -266 269 -266 231 -262 263 -262 257 -290 265 -232 259 -292 265 -266 265 -236 301 -266 233 -300 231 -264 255 -290 265 -266 -RAW_Data: 231 -264 297 -234 299 -232 293 -264 267 -268 231 -262 257 -258 291 -262 269 -268 231 -262 295 -268 271 -270 231 -264 257 -290 263 -266 265 -270 273 -268 233 -262 261 -262 261 -296 229 -264 257 -290 265 -266 265 -236 299 -266 267 -266 231 -264 263 -262 257 -256 291 -296 239 -278 239 -268 263 -262 255 -290 263 -234 259 -292 265 -266 265 -234 301 -266 235 -300 229 -264 261 -264 255 -258 291 -264 267 -268 265 -234 301 -264 267 -266 231 -264 257 -258 291 -262 267 -236 259 -292 231 -298 265 -236 301 -266 233 -300 231 -262 257 -290 265 -272 269 -266 235 -300 231 -262 261 -262 257 -258 291 -264 269 -266 265 -236 299 -264 269 -266 231 -264 261 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -264 269 -268 231 -264 259 -262 257 -258 291 -262 269 -274 269 -266 235 -300 231 -262 261 -262 257 -290 265 -232 261 -292 265 -266 231 -264 295 -268 271 -270 231 -264 257 -258 289 -230 293 -264 269 -266 273 -238 265 -294 231 -266 257 -292 265 -272 269 -266 235 -300 231 -262 261 -264 257 -290 265 -232 261 -292 231 -298 265 -268 273 -270 233 -262 261 -262 255 -292 265 -272 275 -270 233 -262 261 -262 261 -264 257 -290 263 -234 261 -292 231 -298 265 -270 271 -270 231 -264 261 -262 261 -264 261 -262 263 -262 295 -234 301 -266 233 -300 231 -262 263 -262 263 -262 261 -262 257 -290 267 -264 265 -270 273 -268 233 -264 259 -262 261 -264 257 -290 265 -266 265 -270 271 -270 231 -264 261 -262 261 -264 255 -290 267 -266 265 -236 299 -264 269 -266 231 -264 261 -264 261 -260 263 -262 257 -292 265 -264 265 -270 273 -268 233 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -234 301 -266 233 -300 231 -264 261 -262 257 -290 265 -266 233 -264 261 -264 293 -268 271 -270 233 -264 261 -262 287 -266 269 -270 271 -266 231 -264 255 -258 289 -264 267 -268 231 -264 293 -236 299 -266 235 -300 231 -262 263 -262 261 -264 255 -292 265 -264 265 -270 271 -236 261 -292 229 -300 231 -264 261 -264 295 -268 271 -270 231 -264 261 -262 261 -262 257 -292 265 -264 233 -296 263 -236 299 -264 269 -266 231 -262 263 -262 263 -262 261 -262 261 -264 295 -234 299 -266 269 -268 231 -262 261 -262 255 -258 291 -264 269 -274 267 -266 235 -300 231 -262 261 -262 257 -290 265 -268 231 -264 295 -236 297 -266 269 -266 231 -262 257 -290 265 -232 259 -294 265 -264 265 -236 301 -266 235 -300 229 -264 261 -262 261 -264 257 -290 265 -266 -RAW_Data: 231 -264 295 -268 273 -268 231 -264 261 -294 229 -264 257 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 261 -262 263 -262 257 -290 265 -264 265 -270 273 -236 261 -292 229 -298 231 -296 263 -270 273 -268 231 -264 261 -262 255 -258 291 -230 295 -264 267 -268 265 -268 273 -268 231 -264 261 -262 257 -290 265 -272 269 -266 269 -266 231 -262 257 -290 265 -232 259 -260 293 -262 267 -266 267 -270 271 -270 231 -262 261 -262 257 -290 265 -232 261 -292 265 -272 269 -266 235 -300 229 -264 261 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -264 267 -268 231 -264 261 -262 257 -290 265 -272 269 -234 295 -262 267 -266 233 -264 255 -258 291 -228 295 -264 267 -268 265 -236 299 -264 267 -266 231 -264 263 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 263 -262 257 -290 265 -266 263 -236 301 -266 235 -300 231 -262 257 -290 265 -232 259 -292 265 -266 265 -236 299 -266 235 -300 231 -262 257 -256 291 -264 269 -274 275 -270 231 -262 261 -260 257 -258 291 -264 267 -268 231 -264 293 -234 301 -266 267 -268 229 -264 261 -264 255 -290 265 -234 259 -294 265 -270 275 -236 261 -292 231 -266 259 -290 265 -274 267 -266 269 -266 231 -264 259 -262 257 -292 265 -232 259 -292 265 -266 265 -236 301 -266 233 -300 231 -262 257 -290 265 -232 259 -294 265 -266 263 -236 301 -266 233 -300 231 -264 261 -262 257 -290 265 -272 267 -268 269 -266 231 -262 257 -290 265 -232 259 -294 265 -264 265 -236 301 -266 267 -266 231 -262 257 -258 291 -262 269 -234 261 -290 265 -264 265 -236 301 -266 233 -300 231 -262 263 -262 261 -264 261 -264 261 -262 295 -268 273 -268 233 -262 261 -262 257 -290 265 -268 231 -264 261 -262 295 -234 301 -266 235 -300 231 -262 261 -262 261 -264 257 -290 265 -266 265 -270 273 -236 259 -290 265 -266 229 -264 295 -270 271 -270 231 -264 261 -262 261 -264 257 -290 263 -266 265 -236 301 -266 267 -266 231 -264 261 -262 263 -262 263 -294 269 -272 235 -266 263 -262 261 -260 263 -262 259 -290 263 -266 231 -298 263 -234 301 -264 269 -266 231 -262 263 -262 261 -262 257 -290 267 -272 269 -266 269 -266 229 -264 261 -264 255 -290 265 -234 259 -292 265 -266 265 -236 299 -266 267 -234 259 -258 291 -230 293 -264 267 -274 267 -266 269 -266 231 -262 263 -262 263 -262 261 -264 261 -262 295 -234 301 -232 295 -262 267 -268 231 -264 261 -262 257 -290 265 -264 233 -264 -RAW_Data: 263 -262 295 -234 299 -266 269 -266 231 -262 261 -262 257 -290 267 -266 265 -236 301 -264 267 -266 231 -264 261 -264 259 -262 257 -292 265 -266 231 -264 295 -268 273 -270 231 -264 261 -260 263 -262 263 -294 269 -272 237 -266 261 -262 261 -262 257 -290 265 -266 265 -236 301 -264 269 -266 231 -264 257 -288 265 -266 231 -264 263 -262 295 -268 271 -270 231 -264 263 -260 295 -234 301 -266 267 -266 231 -264 263 -262 257 -256 291 -264 267 -268 231 -264 293 -268 273 -268 233 -264 261 -262 259 -264 257 -258 291 -296 241 -276 239 -268 263 -262 255 -290 263 -266 231 -266 295 -234 301 -264 269 -266 229 -264 263 -262 257 -290 263 -234 261 -292 265 -270 269 -232 295 -264 269 -266 229 -264 257 -258 291 -262 267 -268 231 -264 295 -268 273 -268 233 -262 261 -262 255 -290 267 -272 269 -266 235 -300 231 -262 261 -262 257 -292 265 -266 231 -264 297 -234 299 -264 269 -266 231 -264 261 -264 261 -260 257 -292 265 -264 233 -264 295 -236 299 -232 293 -264 267 -266 231 -264 263 -262 257 -290 263 -268 265 -270 271 -270 231 -262 261 -262 257 -292 265 -232 259 -292 233 -298 265 -236 299 -266 269 -266 229 -264 261 -264 255 -290 265 -266 233 -264 295 -268 273 -268 231 -264 255 -290 265 -266 265 -270 271 -270 231 -264 261 -262 261 -262 263 -262 257 -290 265 -268 263 -270 273 -268 233 -262 261 -262 255 -292 265 -272 269 -266 269 -266 231 -262 263 -262 257 -290 265 -264 233 -296 263 -236 299 -264 269 -266 231 -264 261 -264 261 -262 255 -260 291 -262 267 -274 269 -266 235 -300 231 -262 261 -262 261 -264 257 -258 291 -264 267 -268 231 -264 293 -268 273 -234 261 -258 291 -228 295 -264 267 -268 265 -236 299 -264 267 -268 231 -264 261 -262 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -264 261 -264 261 -262 261 -264 255 -290 265 -266 267 -236 299 -264 269 -266 231 -262 257 -290 265 -266 231 -264 297 -234 299 -264 269 -266 231 -264 261 -264 255 -292 265 -232 259 -292 265 -266 265 -234 301 -266 235 -300 229 -264 261 -294 263 -268 273 -270 231 -264 261 -262 255 -290 267 -266 231 -264 295 -234 299 -266 267 -268 231 -264 255 -258 291 -262 267 -268 233 -262 295 -268 273 -268 233 -262 257 -290 265 -272 267 -268 267 -268 229 -264 261 -264 257 -288 265 -234 259 -292 265 -266 265 -234 301 -266 235 -300 231 -262 257 -256 291 -230 295 -304 243 -274 235 -264 257 -288 265 -264 231 -298 229 -264 293 -234 -RAW_Data: 301 -266 267 -266 231 -264 263 -262 261 -262 257 -290 265 -266 231 -266 295 -234 299 -266 267 -266 231 -264 263 -262 261 -264 261 -262 257 -290 265 -266 265 -234 301 -234 293 -264 267 -266 231 -264 257 -258 289 -230 293 -264 269 -266 265 -270 271 -270 231 -264 255 -290 265 -266 231 -264 257 -290 265 -266 265 -236 301 -264 235 -300 231 -262 261 -262 257 -258 291 -264 269 -266 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 295 -236 299 -266 235 -300 231 -262 261 -294 229 -264 257 -290 265 -266 231 -296 263 -236 299 -266 267 -268 231 -264 255 -258 291 -268 273 -270 269 -268 231 -264 259 -296 229 -262 257 -292 265 -264 231 -298 261 -236 299 -264 269 -268 231 -264 255 -290 265 -266 231 -264 263 -262 295 -268 271 -270 231 -264 261 -262 257 -290 265 -266 233 -262 257 -292 265 -264 265 -270 273 -236 259 -258 291 -262 267 -268 265 -234 301 -266 267 -266 231 -262 263 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 261 -262 255 -292 265 -234 259 -292 265 -266 231 -264 295 -268 273 -268 231 -264 261 -262 257 -290 265 -266 263 -236 301 -266 269 -266 231 -262 261 -264 261 -262 263 -262 257 -290 265 -266 265 -270 273 -268 231 -264 261 -262 261 -262 263 -262 295 -268 273 -268 233 -262 261 -262 257 -290 265 -266 265 -236 301 -266 235 -300 229 -264 261 -262 257 -290 265 -266 231 -264 297 -234 299 -264 269 -266 231 -262 257 -290 267 -272 267 -268 267 -268 229 -264 261 -262 261 -264 257 -290 265 -232 259 -294 265 -272 267 -268 269 -234 263 -262 261 -262 261 -264 257 -256 293 -262 269 -274 267 -266 269 -266 231 -262 261 -264 261 -264 255 -290 265 -266 265 -270 273 -268 233 -262 255 -290 265 -232 261 -258 293 -262 267 -274 269 -266 269 -232 265 -262 255 -258 291 -262 269 -234 261 -292 263 -272 269 -266 269 -234 263 -262 255 -258 291 -230 295 -264 267 -240 303 -232 295 -262 267 -266 231 -264 263 -262 261 -264 255 -290 265 -266 267 -236 299 -264 269 -266 231 -262 263 -262 261 -264 255 -290 265 -266 231 -264 297 -234 299 -266 269 -232 259 -292 265 -266 263 -236 299 -266 269 -234 263 -262 257 -290 265 -232 259 -294 265 -272 267 -268 269 -234 263 -262 261 -262 257 -258 291 -262 269 -268 271 -240 263 -262 291 -228 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 263 -262 261 -262 261 -264 257 -290 263 -274 269 -266 269 -266 231 -262 257 -290 263 -274 269 -268 -RAW_Data: 267 -234 263 -262 261 -262 257 -290 265 -234 261 -292 265 -264 265 -236 299 -266 269 -232 265 -262 261 -264 261 -262 261 -264 261 -264 295 -234 299 -266 269 -234 263 -262 261 -262 263 -262 257 -290 265 -268 265 -270 273 -236 263 -262 257 -288 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 261 -262 263 -262 257 -290 265 -268 231 -264 295 -234 299 -266 267 -268 233 -262 261 -262 255 -290 267 -266 233 -262 263 -262 295 -268 273 -268 233 -262 257 -290 263 -266 231 -264 297 -234 299 -232 295 -264 267 -266 231 -264 261 -262 257 -290 265 -268 231 -264 295 -234 299 -264 269 -268 229 -264 261 -264 287 -266 269 -270 271 -234 263 -262 257 -256 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 263 -262 261 -264 255 -290 265 -274 269 -266 269 -234 257 -258 291 -260 269 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -264 257 -256 293 -262 269 -238 303 -266 269 -232 265 -262 261 -262 261 -264 261 -262 263 -262 295 -236 301 -266 267 -234 263 -262 261 -262 257 -258 291 -264 267 -268 265 -268 273 -268 233 -262 261 -262 255 -258 293 -262 269 -268 263 -236 299 -264 269 -266 231 -264 261 -264 255 -292 263 -234 259 -260 291 -262 267 -268 265 -234 299 -266 235 -300 231 -262 257 -258 291 -264 267 -268 231 -296 269 -270 235 -300 231 -262 259 -296 229 -262 257 -290 233 -298 231 -296 263 -236 299 -264 235 -300 233 -262 261 -294 231 -262 257 -290 265 -272 267 -234 263 -262 295 -262 235 -300 265 -270 271 -268 231 -264 261 -294 229 -264 257 -258 291 -262 235 -300 263 -270 267 -266 235 -300 229 -296 229 -262 257 -292 263 -272 267 -268 235 -300 231 -294 231 -296 227 -262 257 -292 231 -298 265 -270 237 -304 231 -298 227 -262 257 -260 259 -294 233 -300 233 -296 261 -268 271 -270 231 -298 229 -296 227 -262 257 -260 259 -294 233 -300 233 -296 263 -268 231 -298 233 -300 231 -298 229 -296 229 -294 263 -268 265 -266 233 -300 231 -264 257 -260 259 -262 259 -296 235 -300 265 -270 265 -264 235 -300 231 -296 229 -296 229 -296 229 -262 257 -290 231 -300 231 -296 263 -270 235 -304 231 -264 257 -290 231 -300 231 -296 263 -268 265 -264 235 -300 233 -296 229 -262 257 -292 231 -298 231 -296 229 -296 263 -268 265 -264 235 -300 231 -264 257 -258 259 -262 293 -304 243 -272 235 -266 257 -290 231 -298 231 -298 263 -268 231 -298 235 -300 231 -294 231 -262 257 -290 233 -266 259 -292 231 -300 -RAW_Data: 263 -270 237 -302 233 -264 257 -290 231 -300 263 -270 265 -266 235 -300 231 -296 229 -264 257 -258 259 -294 233 -300 265 -270 231 -298 235 -300 231 -296 229 -296 229 -296 229 -294 229 -296 263 -268 265 -264 235 -302 231 -296 229 -262 257 -290 231 -298 231 -298 263 -268 237 -302 233 -296 229 -262 257 -290 231 -266 261 -292 231 -300 263 -270 267 -264 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 231 -296 263 -268 237 -302 233 -296 231 -262 257 -290 231 -298 231 -296 263 -270 265 -264 235 -300 231 -296 229 -264 257 -290 231 -298 231 -298 263 -268 265 -264 235 -300 231 -296 231 -296 227 -294 231 -262 257 -292 231 -298 265 -268 237 -270 261 -292 231 -300 263 -270 265 -266 235 -300 231 -296 229 -296 227 -262 257 -292 231 -300 263 -270 265 -266 235 -300 231 -264 257 -292 231 -298 231 -296 267 -272 235 -300 231 -294 229 -294 229 -262 257 -292 231 -300 265 -268 273 -268 233 -262 261 -294 231 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -264 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -268 267 -266 233 -300 231 -296 229 -296 229 -262 257 -292 229 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -296 229 -296 227 -296 261 -270 265 -264 235 -302 231 -296 229 -294 229 -296 229 -264 255 -290 231 -300 263 -270 267 -266 235 -300 231 -262 257 -290 231 -298 233 -296 269 -272 235 -268 261 -262 261 -294 229 -296 263 -234 301 -266 233 -302 229 -264 257 -258 259 -294 267 -234 261 -292 231 -298 265 -268 273 -268 233 -262 261 -296 229 -296 261 -270 271 -268 231 -298 229 -262 261 -262 257 -290 233 -266 259 -292 233 -298 265 -268 273 -268 233 -296 227 -262 257 -258 259 -296 233 -300 265 -270 265 -266 235 -298 231 -296 229 -296 229 -296 229 -264 257 -290 265 -270 275 -270 233 -262 261 -262 257 -290 231 -266 261 -292 231 -298 265 -270 273 -268 233 -262 257 -258 259 -294 267 -234 261 -292 231 -298 265 -270 265 -264 235 -300 231 -296 229 -296 229 -294 231 -294 229 -296 229 -294 263 -268 271 -270 231 -264 257 -292 231 -266 259 -292 265 -272 267 -266 235 -300 231 -296 229 -264 255 -258 291 -264 233 -302 231 -264 293 -268 271 -270 231 -264 263 -292 229 -296 263 -236 299 -264 235 -300 231 -296 229 -294 229 -296 229 -264 257 -290 231 -298 -RAW_Data: 265 -270 265 -266 235 -300 231 -296 229 -262 257 -258 259 -328 239 -276 237 -302 233 -262 255 -288 231 -298 233 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 265 -268 273 -268 233 -264 261 -262 255 -290 233 -266 259 -292 233 -298 231 -296 263 -268 267 -264 233 -300 231 -264 257 -292 265 -270 269 -266 235 -300 231 -296 229 -262 257 -292 231 -264 261 -292 265 -272 267 -266 235 -300 231 -296 229 -264 261 -262 257 -258 291 -264 267 -268 231 -262 295 -268 271 -270 233 -262 261 -262 257 -290 231 -300 265 -270 267 -266 233 -300 231 -296 227 -296 229 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -302 229 -264 257 -292 229 -300 231 -296 229 -296 269 -272 235 -266 259 -290 231 -298 265 -268 265 -266 235 -302 231 -296 227 -296 229 -294 231 -294 229 -296 263 -268 265 -264 235 -300 233 -296 229 -262 287 -300 241 -272 235 -298 227 -262 257 -258 259 -294 233 -302 231 -298 261 -268 265 -264 235 -302 231 -262 257 -290 231 -268 259 -292 231 -300 263 -270 273 -268 233 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -262 263 -262 257 -258 291 -264 267 -266 231 -296 263 -268 273 -268 231 -264 261 -264 255 -290 231 -266 261 -292 231 -300 265 -234 301 -264 235 -300 231 -296 229 -264 261 -294 263 -234 301 -264 235 -300 231 -294 231 -262 257 -290 231 -300 231 -296 263 -234 299 -266 235 -302 231 -262 257 -290 231 -266 259 -260 259 -296 267 -266 265 -236 299 -264 235 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 271 -272 237 -266 261 -262 261 -262 257 -290 231 -300 265 -270 267 -264 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 231 -300 263 -270 267 -266 233 -268 257 -292 231 -298 231 -298 263 -268 271 -268 233 -296 229 -262 257 -290 231 -266 261 -292 231 -300 231 -296 263 -268 271 -268 233 -296 229 -262 257 -290 231 -266 259 -294 231 -300 263 -236 299 -266 233 -300 231 -296 229 -296 229 -294 229 -296 263 -268 273 -268 231 -264 261 -262 257 -292 231 -266 259 -292 233 -298 265 -270 271 -270 231 -264 261 -294 229 -296 229 -294 229 -296 231 -262 261 -294 263 -234 299 -266 269 -268 231 -262 261 -294 229 -264 257 -258 259 -328 239 -278 237 -270 261 -262 261 -262 255 -292 231 -298 233 -296 231 -262 293 -236 299 -266 235 -300 231 -262 257 -258 291 -230 295 -264 233 -300 265 -234 301 -230 297 -228 295 -262 269 -272 269 -266 -RAW_Data: 235 -300 231 -262 257 -290 231 -266 259 -292 233 -298 231 -296 263 -270 271 -268 233 -264 261 -260 257 -258 291 -304 243 -274 235 -264 263 -260 261 -294 229 -264 257 -290 265 -266 265 -236 299 -266 235 -300 231 -262 261 -294 229 -296 231 -262 261 -294 263 -234 301 -266 235 -300 231 -262 261 -264 255 -292 265 -266 231 -264 263 -262 295 -234 299 -266 267 -268 231 -262 263 -262 261 -262 295 -234 301 -266 269 -266 231 -262 261 -264 255 -290 265 -266 231 -264 297 -234 299 -232 295 -264 267 -266 231 -264 263 -262 255 -290 265 -266 231 -264 263 -262 295 -270 271 -268 233 -262 263 -262 257 -256 291 -262 269 -268 265 -236 299 -264 267 -268 231 -262 263 -262 261 -262 257 -290 265 -268 265 -234 301 -264 269 -266 231 -264 261 -262 263 -262 287 -266 275 -274 235 -264 261 -262 255 -258 291 -262 269 -268 265 -268 273 -268 231 -264 261 -260 257 -290 265 -268 231 -264 263 -262 293 -270 271 -270 231 -264 255 -290 265 -266 265 -236 299 -266 269 -266 231 -262 261 -264 261 -262 261 -264 257 -290 265 -266 265 -270 271 -270 231 -264 261 -260 257 -290 267 -266 231 -264 263 -262 261 -262 295 -234 301 -266 269 -266 229 -264 261 -264 255 -290 265 -274 267 -268 269 -232 265 -262 255 -290 265 -234 261 -290 265 -266 231 -264 295 -270 271 -268 233 -262 257 -256 291 -264 267 -236 259 -290 265 -266 265 -236 299 -266 267 -266 231 -264 261 -262 261 -264 257 -290 265 -266 233 -296 269 -272 235 -266 257 -256 291 -262 269 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -262 257 -290 265 -266 233 -264 261 -262 293 -270 273 -236 261 -258 289 -262 267 -274 269 -266 269 -232 265 -262 257 -290 263 -234 259 -292 265 -266 265 -236 299 -266 269 -234 263 -262 261 -262 257 -258 291 -296 241 -276 239 -268 263 -262 255 -256 291 -264 267 -268 231 -264 295 -234 299 -266 269 -234 263 -262 263 -262 257 -256 291 -262 269 -268 265 -236 299 -264 269 -266 231 -262 257 -290 265 -232 261 -260 289 -264 267 -268 265 -236 299 -264 267 -266 231 -264 263 -262 261 -262 295 -236 299 -266 269 -234 263 -262 261 -262 257 -258 291 -262 269 -268 265 -236 299 -264 269 -232 265 -262 261 -262 257 -290 267 -266 231 -264 257 -290 265 -266 265 -236 299 -266 267 -234 263 -264 257 -288 265 -268 265 -236 299 -232 295 -262 267 -268 231 -262 263 -262 257 -288 265 -268 231 -264 263 -260 295 -270 273 -236 265 -262 261 -262 255 -258 291 -298 -RAW_Data: 241 -278 237 -268 257 -256 289 -262 269 -268 231 -264 293 -268 273 -270 231 -264 261 -262 261 -262 257 -290 265 -268 231 -264 293 -268 273 -270 233 -262 261 -260 263 -262 295 -236 301 -266 267 -234 263 -262 261 -262 261 -264 257 -258 291 -264 267 -268 265 -270 271 -236 265 -262 261 -260 263 -262 263 -262 263 -262 295 -234 299 -232 295 -264 269 -232 265 -262 263 -262 257 -288 265 -234 293 -266 269 -270 269 -234 265 -262 255 -258 291 -230 295 -264 267 -236 297 -270 271 -234 265 -264 259 -262 257 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 257 -290 265 -234 259 -292 265 -266 263 -236 299 -232 295 -264 267 -234 259 -292 265 -232 259 -292 265 -264 233 -264 295 -236 299 -264 269 -232 265 -262 261 -262 263 -262 261 -264 263 -262 295 -270 271 -236 265 -264 255 -288 265 -266 267 -270 273 -236 263 -262 257 -288 265 -268 231 -264 261 -262 295 -234 301 -266 269 -234 263 -262 261 -262 257 -290 265 -268 231 -298 269 -272 235 -266 261 -262 261 -262 263 -262 261 -264 293 -234 301 -266 269 -232 265 -262 261 -262 255 -258 293 -262 269 -268 265 -236 299 -264 269 -232 265 -262 261 -264 261 -264 255 -290 267 -266 231 -262 297 -234 301 -264 269 -232 263 -264 257 -258 291 -262 269 -240 303 -266 267 -234 263 -262 261 -262 261 -264 263 -262 261 -264 295 -234 299 -266 269 -232 265 -262 261 -262 257 -290 265 -234 261 -292 265 -264 265 -236 301 -232 295 -262 267 -266 231 -264 261 -262 261 -264 295 -236 299 -264 269 -234 263 -264 261 -262 255 -292 265 -266 233 -264 257 -288 265 -266 265 -270 273 -268 231 -264 261 -262 255 -290 267 -266 233 -296 269 -238 263 -294 267 -264 231 -264 293 -236 299 -266 269 -234 263 -262 263 -262 255 -258 291 -264 267 -268 233 -262 295 -234 299 -264 269 -268 231 -264 259 -262 295 -236 299 -266 269 -232 265 -262 261 -264 261 -264 255 -290 265 -266 233 -264 295 -268 271 -270 233 -262 261 -262 261 -262 257 -258 291 -264 267 -240 303 -266 269 -232 265 -262 261 -262 255 -292 265 -266 231 -264 257 -290 265 -272 277 -270 233 -262 255 -256 291 -264 267 -268 231 -264 293 -234 301 -266 269 -234 263 -262 257 -256 291 -264 267 -268 231 -264 293 -236 299 -266 269 -234 263 -262 261 -262 263 -262 257 -258 291 -262 269 -274 269 -266 267 -234 263 -264 261 -260 257 -290 267 -266 233 -264 295 -234 299 -232 293 -264 269 -266 233 -262 261 -262 255 -258 291 -264 -RAW_Data: 267 -268 265 -236 299 -266 267 -266 231 -264 255 -290 265 -274 275 -238 263 -264 259 -262 261 -264 257 -290 265 -266 265 -236 299 -266 267 -268 231 -262 261 -264 255 -290 265 -234 261 -290 265 -266 271 -276 235 -266 257 -288 263 -234 259 -292 265 -272 269 -234 295 -262 267 -266 231 -264 261 -264 255 -290 265 -234 259 -292 265 -272 269 -266 269 -234 263 -262 257 -256 291 -264 267 -236 259 -292 265 -264 265 -236 299 -266 269 -234 263 -262 261 -262 261 -264 295 -268 273 -270 231 -264 261 -260 263 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 261 -264 255 -292 265 -232 259 -260 291 -264 267 -268 263 -236 299 -266 267 -234 263 -264 261 -264 255 -290 265 -268 265 -270 273 -268 231 -264 259 -262 257 -290 265 -234 259 -292 265 -266 265 -234 301 -266 269 -232 265 -262 259 -262 257 -292 265 -266 231 -264 295 -270 271 -270 231 -264 255 -290 265 -266 263 -270 273 -270 233 -262 261 -260 263 -262 261 -264 263 -262 261 -264 295 -234 299 -266 269 -232 265 -262 261 -264 295 -234 299 -266 269 -234 263 -264 259 -262 257 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -264 255 -258 293 -262 269 -238 303 -266 269 -232 263 -264 261 -262 261 -264 257 -256 291 -264 269 -266 233 -262 295 -268 271 -238 259 -260 289 -228 295 -262 269 -268 265 -236 299 -264 269 -266 231 -262 261 -262 263 -262 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 263 -262 261 -262 261 -264 257 -290 265 -266 265 -236 299 -266 269 -232 265 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -234 263 -262 263 -262 257 -290 265 -234 259 -292 265 -266 263 -270 273 -270 231 -264 261 -260 257 -258 291 -304 243 -274 235 -266 259 -262 261 -262 257 -290 265 -266 233 -264 293 -234 299 -266 269 -268 231 -264 259 -262 261 -264 257 -258 291 -262 269 -274 275 -236 265 -264 255 -256 291 -262 269 -268 263 -270 273 -236 263 -264 259 -262 257 -258 291 -264 269 -266 233 -262 261 -262 295 -268 273 -270 233 -262 255 -288 265 -234 261 -258 293 -262 269 -232 297 -236 299 -266 269 -232 265 -262 261 -264 261 -264 293 -268 273 -270 231 -264 261 -260 257 -290 265 -234 261 -290 265 -266 265 -270 273 -268 233 -262 261 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -236 299 -264 269 -268 231 -264 255 -288 267 -266 233 -264 255 -290 271 -278 237 -266 263 -262 261 -260 257 -292 265 -266 231 -264 -RAW_Data: 295 -236 299 -232 295 -262 267 -266 233 -262 257 -258 291 -230 295 -264 267 -240 301 -232 295 -230 293 -264 267 -268 265 -268 273 -236 265 -262 261 -262 255 -290 267 -232 259 -292 267 -266 263 -270 273 -236 265 -262 261 -262 255 -290 267 -266 265 -236 301 -264 267 -266 231 -264 261 -262 257 -290 265 -234 259 -292 265 -266 265 -234 301 -266 269 -232 265 -262 255 -290 265 -268 231 -264 263 -262 293 -268 273 -270 231 -264 261 -262 255 -290 265 -268 231 -266 255 -290 265 -266 265 -270 273 -236 259 -258 291 -260 269 -266 267 -236 299 -264 269 -232 265 -262 261 -264 255 -290 265 -268 231 -264 295 -234 299 -266 269 -234 263 -264 259 -262 257 -290 265 -234 261 -292 265 -264 231 -264 295 -270 271 -270 231 -264 261 -262 255 -290 265 -268 265 -236 299 -266 267 -234 263 -264 261 -264 261 -262 261 -262 257 -290 265 -268 265 -270 273 -234 265 -264 259 -262 261 -264 261 -264 295 -268 273 -236 265 -262 261 -262 257 -290 265 -266 267 -236 299 -264 269 -232 265 -262 263 -262 257 -288 265 -234 261 -292 265 -264 265 -270 273 -236 263 -264 257 -288 265 -266 265 -236 301 -264 269 -234 263 -264 261 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -232 265 -262 261 -262 261 -264 263 -262 261 -264 295 -234 301 -264 269 -234 263 -262 263 -262 263 -262 255 -290 265 -240 303 -266 269 -232 265 -262 261 -262 261 -264 261 -264 261 -262 263 -262 295 -268 273 -238 263 -264 259 -262 263 -262 257 -258 291 -262 269 -234 299 -234 299 -266 267 -234 263 -264 263 -262 255 -290 265 -234 261 -292 263 -274 275 -236 265 -262 255 -258 291 -262 269 -268 231 -264 293 -234 301 -266 267 -234 263 -262 263 -262 257 -290 265 -266 233 -264 295 -234 299 -266 267 -234 259 -290 265 -266 265 -236 299 -266 269 -234 263 -262 257 -288 265 -234 261 -292 265 -238 301 -234 295 -262 267 -234 263 -264 257 -256 291 -230 295 -296 241 -278 241 -234 289 -254 289 -230 295 -264 267 -236 297 -236 299 -232 293 -264 267 -234 263 -264 261 -264 255 -258 291 -264 267 -236 297 -270 271 -236 265 -262 261 -262 255 -292 265 -234 259 -292 265 -232 297 -236 301 -266 269 -232 263 -264 261 -262 261 -262 263 -262 295 -270 273 -236 265 -262 261 -262 255 -258 291 -230 295 -264 267 -236 297 -236 299 -264 269 -234 263 -262 263 -262 255 -290 265 -268 231 -264 263 -262 293 -234 301 -266 269 -234 263 -262 257 -256 293 -262 269 -234 299 -234 -RAW_Data: 299 -266 267 -234 263 -264 261 -262 261 -264 257 -290 265 -234 263 -264 295 -236 299 -266 267 -234 263 -264 255 -256 293 -230 295 -296 241 -278 239 -266 257 -256 289 -264 267 -234 299 -236 299 -264 269 -232 265 -262 257 -290 265 -234 259 -292 265 -232 299 -236 299 -264 269 -234 265 -262 255 -290 265 -240 303 -266 269 -232 265 -262 261 -262 261 -262 263 -262 257 -290 265 -240 303 -266 269 -232 265 -262 261 -262 263 -262 261 -264 261 -264 261 -262 295 -234 301 -266 269 -232 265 -262 255 -290 265 -234 259 -292 265 -232 299 -236 299 -266 267 -234 265 -262 257 -256 291 -262 269 -266 233 -264 295 -236 299 -264 269 -234 263 -262 261 -262 257 -258 291 -262 269 -234 265 -264 295 -234 299 -266 269 -232 265 -262 261 -262 261 -264 261 -264 261 -264 295 -234 299 -232 295 -264 267 -234 263 -264 257 -288 265 -268 265 -236 299 -266 267 -234 265 -262 261 -262 261 -264 261 -264 261 -262 295 -236 299 -266 269 -232 265 -262 255 -290 265 -240 303 -268 269 -232 265 -228 289 -288 265 -268 231 -264 297 -234 299 -232 295 -262 267 -234 265 -264 261 -260 257 -290 265 -268 265 -270 273 -236 259 -290 263 -266 231 -264 263 -262 295 -236 299 -266 267 -234 263 -264 261 -262 257 -256 291 -230 295 -264 269 -234 299 -268 273 -234 265 -264 259 -262 261 -264 261 -262 257 -290 265 -234 299 -236 299 -266 267 -234 263 -264 261 -264 255 -290 265 -234 299 -268 273 -236 265 -262 259 -262 257 -290 265 -234 267 -264 295 -234 299 -266 267 -234 263 -264 261 -262 257 -256 291 -264 269 -234 259 -292 265 -232 297 -236 301 -264 269 -234 263 -264 255 -290 265 -234 265 -264 293 -236 299 -264 269 -234 265 -264 259 -262 255 -292 265 -234 265 -264 263 -262 293 -234 301 -266 269 -234 263 -262 261 -262 255 -292 265 -234 299 -270 273 -234 259 -290 265 -264 233 -264 295 -234 301 -264 269 -234 263 -262 255 -258 291 -230 295 -264 269 -234 299 -234 299 -266 267 -234 263 -264 255 -290 265 -240 303 -266 269 -232 265 -262 261 -262 261 -262 263 -262 257 -290 265 -234 299 -236 299 -266 269 -232 265 -230 287 -288 267 -234 259 -292 265 -234 297 -270 273 -236 263 -262 261 -262 261 -262 257 -290 267 -234 265 -264 261 -262 293 -270 273 -238 265 -230 287 -256 291 -262 269 -236 297 -236 299 -264 269 -234 263 -262 257 -256 291 -230 295 -264 269 -234 299 -234 301 -264 267 -234 263 -264 261 -262 257 -290 265 -234 259 -292 265 -266 265 -236 -RAW_Data: 299 -264 269 -266 231 -264 261 -262 255 -258 291 -264 269 -266 265 -236 299 -266 267 -266 231 -264 263 -262 255 -256 293 -262 269 -268 231 -262 295 -236 299 -264 269 -234 263 -264 261 -262 295 -268 273 -270 231 -264 259 -262 261 -264 257 -258 291 -262 269 -268 265 -234 299 -266 269 -232 265 -262 255 -290 265 -234 261 -292 265 -264 273 -240 263 -294 265 -232 259 -292 265 -264 265 -236 299 -266 269 -234 263 -262 261 -262 263 -262 257 -290 265 -268 231 -264 295 -268 273 -268 231 -264 261 -262 255 -258 293 -262 269 -268 231 -264 293 -234 299 -266 267 -268 233 -262 261 -262 261 -262 295 -236 301 -266 267 -234 263 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -264 269 -234 263 -262 257 -258 291 -262 269 -234 261 -290 263 -266 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -290 267 -266 273 -274 235 -264 263 -260 257 -288 265 -266 233 -264 257 -290 265 -266 263 -236 301 -266 267 -234 263 -264 261 -264 255 -290 265 -266 233 -264 295 -234 299 -266 267 -234 259 -290 265 -238 303 -268 267 -234 263 -264 261 -262 255 -292 265 -266 233 -262 295 -236 299 -264 269 -234 263 -262 263 -262 263 -262 295 -268 273 -236 265 -262 261 -262 261 -262 257 -290 267 -266 233 -264 293 -234 301 -264 269 -234 263 -262 257 -290 265 -234 259 -292 265 -266 265 -268 273 -236 265 -264 261 -262 255 -290 265 -234 261 -258 291 -262 267 -268 265 -236 299 -266 267 -234 257 -260 289 -264 267 -268 265 -236 299 -264 269 -232 265 -264 261 -262 261 -262 261 -264 257 -290 265 -268 265 -236 299 -266 267 -234 263 -262 263 -262 257 -258 291 -262 269 -234 265 -264 293 -234 299 -266 269 -232 265 -262 257 -290 265 -266 265 -236 301 -230 295 -264 267 -234 263 -264 255 -290 265 -234 261 -290 265 -238 303 -234 295 -262 267 -234 263 -264 263 -262 261 -262 289 -264 277 -274 235 -264 261 -260 255 -290 265 -268 265 -236 299 -264 269 -234 263 -262 263 -262 263 -262 255 -258 291 -264 267 -268 265 -270 273 -236 263 -262 261 -262 261 -264 295 -234 301 -264 269 -234 263 -264 261 -262 263 -262 257 -288 265 -268 231 -264 297 -268 271 -236 265 -262 261 -262 255 -258 293 -262 269 -268 231 -262 295 -270 273 -234 265 -264 259 -262 261 -264 257 -290 265 -266 265 -270 273 -236 265 -262 261 -262 261 -264 255 -292 265 -266 231 -264 295 -268 273 -236 265 -262 261 -262 261 -264 257 -256 293 -262 269 -234 299 -234 299 -266 -RAW_Data: 267 -234 263 -264 261 -262 261 -264 255 -258 293 -262 269 -234 299 -268 273 -234 265 -264 259 -262 261 -264 257 -290 265 -266 265 -236 299 -232 295 -264 267 -234 263 -264 255 -258 291 -230 295 -264 267 -234 299 -268 273 -236 259 -258 291 -260 269 -240 303 -266 269 -232 263 -264 255 -258 289 -264 267 -268 231 -266 295 -234 299 -266 267 -234 263 -264 261 -262 263 -262 257 -288 273 -276 273 -234 263 -228 287 -288 265 -268 233 -264 261 -262 293 -236 301 -266 267 -234 263 -264 261 -262 261 -262 263 -262 263 -262 295 -270 271 -236 265 -264 261 -260 263 -262 261 -264 255 -292 265 -266 233 -264 293 -234 301 -266 269 -232 259 -290 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 261 -262 255 -258 293 -262 269 -234 297 -236 301 -264 267 -234 263 -264 261 -262 255 -290 267 -234 259 -292 265 -232 265 -264 295 -270 271 -236 265 -262 261 -262 261 -262 263 -262 295 -236 301 -266 267 -234 263 -262 263 -262 255 -290 265 -268 231 -264 257 -290 265 -234 297 -270 273 -236 265 -262 259 -262 261 -264 263 -294 269 -274 235 -266 257 -288 265 -232 259 -292 267 -238 303 -266 269 -232 265 -262 259 -262 263 -262 257 -290 267 -266 265 -236 301 -264 267 -234 263 -264 261 -262 263 -262 261 -264 295 -234 301 -232 295 -262 269 -232 265 -262 261 -262 257 -290 265 -268 231 -264 295 -268 273 -236 265 -262 261 -262 261 -262 263 -262 263 -262 261 -264 295 -234 301 -264 269 -234 263 -262 263 -262 263 -262 287 -266 269 -270 271 -234 265 -262 261 -260 257 -290 267 -234 265 -264 293 -234 301 -266 267 -234 263 -264 255 -256 293 -230 295 -264 267 -234 265 -264 293 -234 299 -266 269 -234 263 -264 261 -260 257 -290 267 -234 259 -292 265 -232 297 -270 273 -236 265 -262 255 -290 265 -266 233 -264 295 -236 299 -230 295 -264 267 -234 263 -264 255 -258 291 -262 269 -234 265 -264 295 -268 271 -238 265 -262 255 -290 265 -266 265 -270 273 -236 263 -264 259 -262 257 -290 267 -266 233 -264 293 -234 301 -266 269 -232 265 -262 259 -262 257 -258 291 -264 267 -268 273 -274 235 -266 255 -256 289 -230 295 -264 269 -234 297 -236 299 -266 267 -234 263 -264 261 -262 257 -290 265 -234 259 -292 265 -232 265 -264 295 -268 273 -236 265 -264 259 -262 255 -258 291 -264 267 -236 297 -236 301 -230 295 -262 267 -234 265 -264 255 -290 265 -240 303 -266 269 -234 263 -262 261 -262 255 -258 291 -264 267 -236 297 -270 273 -236 263 -264 -RAW_Data: 259 -262 261 -264 257 -256 293 -262 269 -234 299 -236 299 -264 269 -232 265 -262 261 -264 261 -262 257 -256 291 -264 269 -240 303 -266 267 -234 263 -264 259 -262 257 -290 265 -234 261 -292 263 -234 263 -264 295 -270 273 -236 265 -230 287 -290 265 -234 259 -292 265 -266 271 -274 237 -266 261 -260 257 -256 289 -264 269 -234 299 -236 299 -264 269 -234 263 -262 261 -264 261 -262 257 -290 265 -268 265 -236 299 -264 269 -234 263 -262 261 -262 295 -236 301 -266 267 -234 263 -262 257 -290 265 -234 259 -292 265 -232 299 -236 299 -266 267 -234 263 -264 261 -262 257 -290 265 -266 233 -264 255 -290 265 -240 303 -268 267 -234 263 -262 261 -262 255 -290 267 -266 265 -270 273 -236 265 -262 261 -262 261 -262 257 -290 265 -268 265 -270 273 -236 263 -264 259 -262 261 -264 261 -264 255 -290 265 -268 265 -236 299 -266 267 -234 263 -264 261 -264 255 -290 265 -234 259 -292 265 -232 299 -270 273 -236 263 -262 257 -256 291 -262 269 -266 233 -264 295 -236 299 -264 269 -234 263 -262 261 -262 257 -290 267 -232 265 -264 261 -264 295 -268 273 -236 265 -262 261 -260 289 -266 269 -272 271 -234 263 -230 287 -258 291 -262 269 -234 265 -264 293 -234 301 -266 269 -232 265 -262 259 -262 263 -262 257 -290 267 -266 265 -270 273 -236 259 -290 265 -232 263 -264 297 -234 301 -230 295 -264 267 -234 263 -264 261 -262 257 -256 291 -264 269 -234 299 -236 299 -264 269 -232 265 -262 261 -262 261 -264 261 -264 261 -264 293 -236 299 -266 269 -234 263 -262 261 -262 255 -258 293 -262 269 -240 303 -266 269 -234 263 -262 261 -260 257 -290 267 -266 233 -264 293 -236 299 -264 269 -234 265 -264 259 -262 255 -292 265 -266 233 -264 263 -262 293 -234 301 -266 269 -234 263 -262 261 -262 255 -292 265 -234 265 -264 293 -268 273 -236 267 -262 261 -260 263 -262 257 -290 265 -234 265 -264 295 -234 299 -266 269 -232 265 -262 261 -264 261 -264 255 -290 265 -266 267 -270 271 -236 261 -288 265 -264 233 -264 295 -268 273 -236 265 -262 261 -262 255 -258 293 -230 295 -262 269 -240 303 -266 267 -234 263 -262 257 -256 291 -262 269 -274 277 -238 265 -228 287 -256 291 -262 269 -236 265 -264 293 -234 299 -266 269 -234 263 -262 261 -262 257 -258 291 -264 267 -234 299 -236 299 -266 267 -234 259 -290 265 -232 297 -236 301 -264 269 -234 263 -264 259 -262 257 -290 267 -234 265 -264 261 -262 293 -236 301 -266 267 -234 263 -264 259 -262 263 -262 -RAW_Data: 257 -258 291 -264 269 -234 265 -262 293 -236 299 -266 269 -232 265 -262 261 -264 255 -290 267 -232 261 -292 265 -238 303 -266 269 -232 263 -264 259 -262 257 -290 267 -234 259 -292 265 -232 297 -236 301 -266 267 -234 263 -262 261 -264 261 -264 261 -262 257 -288 267 -266 265 -270 273 -236 265 -262 261 -260 257 -258 323 -238 279 -276 235 -230 287 -288 265 -234 263 -264 263 -262 295 -270 273 -236 265 -262 259 -262 257 -256 291 -230 295 -264 269 -234 299 -236 299 -264 269 -232 259 -290 265 -232 299 -236 301 -264 269 -234 263 -262 261 -264 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -234 263 -262 263 -262 255 -258 291 -262 269 -234 299 -236 299 -264 269 -234 263 -262 263 -262 261 -262 263 -262 295 -236 299 -266 267 -234 265 -262 255 -290 265 -234 259 -292 265 -234 297 -236 299 -266 269 -234 263 -262 257 -256 291 -262 269 -236 259 -290 265 -232 299 -236 299 -266 267 -234 263 -264 261 -262 261 -264 261 -264 261 -262 295 -270 273 -236 265 -262 261 -260 257 -290 265 -236 265 -262 261 -262 295 -236 301 -266 267 -234 263 -262 261 -262 261 -264 257 -290 265 -234 299 -270 273 -234 259 -290 265 -232 265 -264 295 -270 273 -236 263 -264 259 -262 261 -264 257 -290 265 -234 297 -236 301 -264 269 -232 265 -262 261 -264 261 -262 261 -296 269 -274 269 -232 261 -262 261 -262 261 -264 255 -292 265 -234 265 -264 293 -234 301 -266 269 -232 263 -264 261 -262 263 -262 255 -290 265 -268 231 -264 295 -270 273 -236 263 -264 261 -260 261 -264 255 -290 267 -234 265 -264 295 -234 299 -232 295 -230 293 -230 295 -264 267 -240 303 -266 267 -234 263 -262 261 -262 261 -264 261 -264 261 -262 295 -236 301 -232 295 -262 267 -232 265 -264 261 -262 257 -256 293 -262 269 -234 265 -264 293 -234 301 -266 269 -234 263 -262 255 -258 291 -262 269 -234 299 -270 271 -236 265 -230 287 -290 265 -234 259 -292 265 -238 303 -268 267 -234 263 -262 261 -262 255 -258 293 -230 293 -264 269 -268 271 -274 235 -266 261 -262 261 -260 257 -290 267 -234 299 -234 301 -264 267 -234 265 -262 257 -288 265 -234 261 -292 265 -232 297 -236 301 -266 267 -234 263 -262 261 -262 295 -234 301 -266 269 -234 263 -262 261 -262 257 -290 265 -234 261 -292 265 -232 297 -236 301 -266 267 -234 263 -262 255 -258 291 -230 295 -264 267 -236 297 -236 299 -264 269 -234 263 -262 261 -262 261 -264 257 -290 265 -240 303 -268 267 -234 263 -230 -RAW_Data: 287 -290 265 -234 259 -292 265 -234 297 -236 301 -266 267 -234 263 -262 255 -290 265 -236 259 -260 289 -262 267 -240 305 -232 295 -262 267 -234 263 -264 261 -264 261 -262 257 -256 291 -264 267 -240 305 -266 267 -234 257 -290 265 -232 265 -264 257 -290 265 -234 299 -236 299 -264 269 -234 263 -262 261 -264 255 -258 291 -262 269 -234 299 -236 299 -266 267 -234 259 -290 265 -232 297 -270 273 -236 265 -264 261 -260 257 -256 293 -262 269 -234 299 -236 299 -264 269 -232 265 -262 261 -264 261 -264 261 -262 257 -288 273 -276 273 -234 263 -228 287 -290 263 -268 233 -264 295 -236 299 -264 269 -232 265 -262 261 -264 261 -264 261 -262 263 -262 293 -236 301 -266 267 -234 263 -230 289 -288 265 -268 233 -264 255 -290 265 -234 299 -236 299 -264 269 -232 265 -262 257 -288 265 -268 265 -236 299 -266 269 -234 263 -262 261 -262 261 -264 255 -258 293 -262 269 -240 303 -266 269 -232 265 -262 259 -262 257 -256 293 -262 269 -234 261 -292 265 -232 297 -236 301 -264 269 -234 263 -262 261 -262 255 -292 265 -240 303 -266 269 -232 265 -262 261 -260 263 -262 257 -292 265 -232 291 -260 267 -238 303 -266 269 -232 265 -262 261 -260 263 -262 263 -262 261 -296 271 -272 237 -234 287 -288 265 -232 299 -230 295 -270 273 -236 263 -264 261 -260 261 -264 263 -262 255 -290 267 -234 297 -236 301 -264 269 -232 265 -262 261 -264 295 -234 301 -264 269 -234 263 -262 261 -262 261 -264 263 -262 255 -290 267 -234 299 -236 299 -264 269 -232 265 -262 257 -256 291 -230 295 -264 267 -240 305 -232 295 -262 265 -234 263 -264 263 -262 255 -290 265 -234 265 -264 295 -270 271 -268 233 -262 257 -256 291 -264 269 -266 233 -262 295 -234 299 -264 269 -266 231 -264 261 -264 255 -258 291 -262 269 -268 265 -236 299 -232 293 -264 267 -266 231 -264 261 -264 255 -290 265 -234 259 -292 265 -272 269 -266 269 -234 257 -292 263 -234 259 -292 265 -266 265 -236 299 -232 293 -264 267 -268 231 -264 261 -262 255 -258 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -262 261 -262 297 -268 273 -270 231 -264 261 -260 261 -264 255 -258 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 255 -258 291 -230 295 -296 241 -276 239 -268 257 -256 291 -262 267 -268 231 -264 293 -234 301 -266 269 -232 263 -264 261 -262 261 -264 257 -256 293 -262 269 -268 265 -268 273 -268 231 -262 261 -262 257 -256 293 -262 269 -268 231 -264 295 -234 299 -266 -RAW_Data: 269 -232 265 -262 257 -288 267 -266 265 -270 273 -236 263 -262 261 -262 263 -262 257 -258 291 -262 269 -268 265 -268 273 -268 231 -264 261 -262 255 -258 291 -262 269 -234 261 -292 265 -264 265 -236 301 -264 269 -232 263 -264 261 -264 261 -262 255 -292 265 -274 275 -236 265 -262 261 -262 255 -258 293 -262 269 -234 261 -290 265 -266 263 -236 301 -266 267 -234 263 -264 255 -256 293 -230 293 -264 269 -274 275 -236 259 -258 289 -262 269 -268 265 -268 273 -268 231 -264 261 -260 263 -262 257 -290 265 -266 231 -266 295 -234 301 -264 267 -266 231 -264 257 -258 289 -270 273 -270 273 -234 263 -262 255 -290 265 -232 261 -292 265 -266 263 -236 301 -266 267 -234 263 -264 259 -262 257 -290 265 -268 233 -264 293 -234 301 -266 267 -234 263 -264 261 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -264 261 -264 259 -262 263 -262 297 -234 299 -266 267 -234 263 -264 257 -290 265 -266 231 -264 263 -262 295 -234 299 -266 269 -232 265 -262 261 -264 255 -258 291 -230 295 -264 267 -268 265 -236 299 -264 267 -268 231 -262 257 -258 291 -262 269 -268 265 -234 299 -232 295 -262 269 -266 231 -264 261 -262 257 -290 265 -266 233 -262 295 -236 299 -266 267 -234 263 -262 263 -262 289 -264 269 -270 271 -236 263 -262 255 -258 291 -262 269 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 263 -262 257 -290 265 -272 269 -266 269 -234 259 -290 265 -264 231 -264 297 -234 301 -264 267 -266 231 -264 263 -262 261 -262 257 -258 291 -264 267 -240 303 -266 267 -234 263 -264 261 -260 263 -262 263 -262 263 -262 295 -268 273 -268 233 -262 261 -262 261 -264 257 -258 291 -262 267 -268 265 -270 273 -234 265 -262 261 -262 261 -264 257 -290 265 -268 231 -264 295 -268 271 -270 233 -262 261 -260 263 -262 257 -258 291 -264 267 -268 265 -236 299 -232 293 -262 269 -266 233 -262 257 -256 291 -262 269 -268 231 -296 269 -272 235 -266 263 -260 261 -262 257 -292 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 261 -264 261 -264 261 -262 295 -236 299 -266 269 -234 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 263 -262 257 -256 291 -264 267 -236 259 -292 265 -236 303 -266 269 -232 265 -262 257 -258 291 -262 269 -274 275 -236 265 -262 255 -258 289 -262 269 -268 231 -264 263 -260 295 -236 301 -266 267 -234 263 -262 257 -256 291 -264 267 -268 233 -262 295 -268 271 -270 233 -262 261 -262 -RAW_Data: 255 -258 293 -262 269 -268 231 -262 295 -234 301 -266 267 -234 263 -264 261 -262 255 -290 267 -266 233 -264 261 -264 293 -268 273 -268 233 -262 261 -262 257 -256 293 -262 269 -268 265 -234 301 -232 293 -262 267 -268 231 -264 261 -262 255 -292 265 -266 233 -264 295 -236 299 -264 267 -266 231 -264 261 -264 261 -262 295 -234 301 -266 267 -234 263 -264 261 -262 257 -290 265 -268 231 -264 255 -290 265 -274 269 -266 267 -234 263 -264 255 -258 291 -230 295 -304 243 -274 235 -264 257 -288 263 -266 231 -266 295 -234 301 -264 269 -234 263 -262 263 -262 257 -256 291 -230 295 -264 267 -268 265 -270 271 -268 231 -264 255 -290 265 -266 265 -236 299 -266 269 -234 263 -262 263 -262 261 -264 255 -290 265 -266 267 -236 299 -264 269 -266 231 -262 261 -262 263 -262 257 -292 265 -264 265 -236 301 -266 267 -234 263 -264 261 -264 255 -290 265 -266 233 -264 295 -268 273 -268 231 -264 261 -260 257 -290 265 -234 261 -290 265 -266 265 -270 273 -268 231 -264 261 -262 255 -258 291 -264 267 -268 233 -262 295 -234 299 -266 269 -232 265 -262 261 -264 255 -292 265 -266 231 -264 263 -262 293 -268 273 -270 231 -264 261 -262 255 -258 291 -264 269 -266 265 -236 299 -232 295 -262 267 -268 231 -264 261 -260 263 -262 257 -292 263 -266 265 -270 273 -236 261 -258 289 -262 267 -268 265 -236 299 -266 267 -234 263 -264 261 -262 263 -262 261 -262 261 -264 263 -262 295 -236 299 -264 269 -234 263 -262 263 -262 257 -258 289 -264 267 -268 233 -264 293 -234 299 -266 269 -234 263 -262 263 -262 261 -264 261 -262 295 -270 273 -268 233 -262 261 -262 261 -262 257 -290 265 -266 231 -298 263 -234 301 -264 267 -268 231 -264 261 -260 257 -290 267 -234 259 -292 231 -298 265 -236 301 -264 235 -300 231 -262 263 -262 261 -264 255 -292 265 -264 271 -274 237 -266 261 -262 257 -256 293 -230 293 -230 295 -264 267 -266 265 -268 273 -268 233 -264 259 -262 257 -292 231 -298 231 -298 229 -262 295 -268 273 -268 233 -262 257 -290 265 -264 233 -296 263 -236 299 -264 269 -266 231 -264 261 -264 261 -262 255 -292 265 -266 231 -296 263 -270 271 -268 231 -264 261 -264 255 -258 291 -262 267 -268 233 -264 295 -234 299 -264 269 -266 233 -262 261 -262 257 -290 265 -266 265 -270 273 -268 231 -264 261 -262 261 -264 257 -258 291 -262 269 -266 265 -236 299 -264 269 -266 231 -264 261 -262 257 -258 291 -264 267 -268 231 -262 295 -234 299 -266 235 -300 -RAW_Data: 231 -264 261 -262 255 -258 293 -262 269 -272 269 -266 235 -300 231 -262 261 -294 229 -264 257 -258 291 -262 267 -268 265 -236 301 -264 267 -266 231 -264 257 -290 265 -266 231 -264 263 -294 269 -272 235 -266 259 -288 265 -264 265 -236 301 -266 233 -300 231 -264 261 -262 261 -262 263 -262 257 -290 265 -266 265 -270 271 -270 233 -262 261 -262 295 -234 301 -266 267 -266 231 -264 261 -264 255 -290 265 -266 233 -264 257 -290 263 -266 265 -270 273 -268 233 -262 261 -262 257 -256 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 261 -262 257 -290 265 -266 233 -262 297 -268 271 -268 233 -262 257 -258 291 -264 267 -268 263 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -232 259 -292 267 -266 263 -236 301 -266 233 -300 231 -262 263 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -266 233 -268 259 -290 265 -232 259 -292 265 -266 265 -234 301 -266 235 -300 231 -262 261 -262 257 -258 291 -230 295 -264 267 -274 267 -266 235 -300 231 -262 261 -294 229 -296 263 -270 271 -270 231 -264 261 -262 255 -290 267 -232 259 -260 293 -262 267 -268 263 -270 273 -268 231 -264 261 -262 255 -258 291 -264 267 -268 273 -272 235 -266 257 -256 291 -260 269 -266 267 -236 299 -264 269 -266 231 -262 263 -262 257 -258 291 -262 269 -266 265 -236 299 -232 293 -264 267 -268 231 -262 263 -262 261 -262 263 -262 257 -258 293 -262 267 -274 267 -234 295 -262 267 -266 233 -262 261 -262 263 -262 257 -290 265 -266 265 -236 301 -264 269 -266 231 -262 263 -262 261 -262 257 -290 265 -266 267 -236 299 -264 269 -266 231 -264 261 -262 261 -262 257 -258 291 -264 267 -274 269 -266 235 -300 231 -262 261 -262 289 -264 269 -270 271 -266 231 -262 263 -262 257 -290 265 -234 259 -260 291 -262 267 -266 267 -268 273 -270 231 -262 261 -262 257 -256 293 -262 269 -268 271 -272 235 -266 257 -258 289 -228 295 -264 267 -268 265 -236 299 -264 269 -266 231 -264 261 -264 255 -258 291 -262 269 -266 265 -236 299 -266 267 -266 231 -264 263 -262 257 -256 291 -262 269 -268 263 -236 299 -232 295 -264 267 -266 231 -264 261 -262 257 -290 265 -272 269 -266 269 -266 231 -262 263 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 261 -260 257 -258 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 257 -288 265 -266 263 -236 301 -266 269 -266 231 -262 261 -264 257 -290 265 -232 259 -292 -RAW_Data: 265 -266 231 -264 297 -268 271 -268 233 -262 261 -262 257 -258 291 -262 269 -268 271 -274 235 -266 257 -288 265 -264 233 -264 295 -236 299 -264 267 -266 231 -264 263 -262 257 -290 265 -232 259 -294 265 -266 263 -236 301 -264 269 -266 231 -264 261 -262 295 -234 299 -266 269 -266 231 -262 263 -262 263 -262 257 -256 291 -264 267 -268 265 -270 271 -268 231 -264 261 -262 261 -262 259 -290 265 -232 261 -292 231 -300 263 -236 301 -266 233 -300 231 -262 263 -262 261 -264 255 -290 265 -266 233 -264 295 -234 299 -266 269 -266 231 -262 257 -258 291 -230 295 -264 267 -272 269 -266 267 -266 231 -264 261 -264 255 -290 265 -232 261 -292 265 -266 263 -236 301 -232 295 -262 267 -268 229 -264 257 -258 291 -230 295 -296 241 -276 239 -266 257 -290 263 -234 259 -258 293 -262 269 -272 269 -266 235 -300 229 -264 261 -264 259 -262 257 -258 293 -262 269 -266 265 -236 299 -264 269 -234 257 -292 265 -266 263 -236 301 -266 235 -300 229 -264 261 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -264 269 -268 231 -264 257 -256 291 -230 293 -264 269 -268 265 -234 299 -266 267 -266 231 -264 263 -262 257 -288 265 -266 265 -268 273 -270 233 -262 257 -288 265 -234 259 -292 265 -266 265 -236 299 -266 235 -298 231 -264 261 -262 263 -262 263 -262 257 -290 265 -264 265 -236 301 -266 235 -300 229 -264 261 -262 261 -264 257 -290 265 -266 233 -264 293 -268 273 -236 259 -292 231 -266 259 -258 293 -262 267 -268 265 -234 299 -266 267 -268 229 -264 263 -262 261 -294 229 -264 261 -264 295 -268 271 -270 231 -264 255 -290 265 -266 265 -270 273 -268 233 -262 257 -290 265 -232 259 -292 265 -266 265 -234 301 -266 269 -266 229 -264 261 -264 261 -262 261 -262 263 -296 269 -272 237 -266 261 -262 261 -262 261 -264 261 -262 295 -236 299 -266 267 -268 229 -264 261 -262 257 -290 265 -234 261 -292 231 -298 265 -236 299 -266 235 -300 231 -262 257 -290 263 -266 231 -264 259 -290 265 -266 265 -236 299 -266 235 -266 259 -258 291 -262 267 -274 269 -266 235 -300 231 -262 261 -262 261 -264 263 -262 261 -264 295 -234 299 -266 267 -268 231 -262 261 -264 255 -290 265 -234 261 -258 291 -262 267 -274 269 -266 267 -266 231 -264 261 -262 263 -262 261 -264 295 -234 299 -266 269 -266 231 -264 261 -260 257 -258 293 -262 269 -234 261 -290 231 -298 265 -270 271 -270 231 -264 261 -262 255 -290 267 -266 233 -296 267 -238 265 -294 233 -298 -RAW_Data: 231 -262 263 -262 295 -270 271 -268 233 -262 263 -262 261 -262 257 -290 265 -268 231 -264 293 -234 301 -266 267 -268 229 -264 257 -290 263 -274 269 -266 269 -266 231 -262 261 -264 255 -292 265 -232 259 -292 265 -272 269 -232 295 -262 267 -268 231 -264 257 -256 291 -230 295 -264 269 -272 267 -266 269 -266 231 -262 261 -262 257 -292 265 -266 231 -264 257 -290 265 -272 275 -272 231 -264 255 -256 291 -264 267 -268 231 -264 293 -236 299 -264 269 -266 231 -262 257 -258 291 -264 267 -268 233 -262 295 -232 299 -266 269 -268 231 -264 259 -262 257 -258 291 -264 267 -236 259 -292 263 -272 267 -268 269 -266 231 -262 257 -290 263 -266 231 -266 295 -234 301 -232 295 -262 269 -266 231 -262 261 -264 257 -256 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 295 -268 271 -270 231 -264 261 -264 259 -262 257 -292 265 -266 265 -236 301 -264 267 -266 231 -264 261 -262 257 -290 265 -266 231 -264 297 -268 273 -268 231 -264 261 -262 255 -292 265 -266 267 -234 299 -266 267 -266 231 -264 263 -262 261 -262 261 -264 261 -262 295 -236 299 -266 269 -266 231 -262 257 -258 291 -230 295 -264 267 -266 265 -234 301 -230 295 -264 267 -266 231 -264 263 -262 261 -260 295 -236 301 -266 267 -266 231 -264 261 -262 261 -264 257 -258 291 -262 269 -274 267 -268 267 -266 231 -262 261 -262 263 -262 257 -258 291 -264 267 -268 265 -236 299 -230 295 -262 267 -268 231 -264 261 -262 257 -258 291 -264 267 -274 275 -270 231 -262 261 -262 255 -292 265 -234 259 -260 291 -260 267 -274 269 -268 267 -266 231 -264 261 -262 257 -290 265 -266 233 -264 293 -268 273 -268 233 -262 257 -290 263 -266 265 -270 273 -270 231 -264 261 -262 259 -262 263 -262 263 -262 263 -262 295 -236 299 -264 269 -268 231 -262 261 -262 295 -236 299 -266 269 -266 231 -262 261 -262 257 -290 265 -266 233 -264 261 -264 295 -234 299 -266 267 -268 229 -264 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -266 231 -264 263 -262 255 -292 265 -232 259 -292 267 -264 265 -270 273 -236 259 -258 291 -228 293 -264 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 257 -290 265 -266 267 -236 299 -264 267 -268 229 -264 263 -262 257 -288 265 -234 259 -292 265 -266 265 -236 299 -266 269 -266 231 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -266 233 -262 261 -262 255 -258 291 -230 295 -264 269 -266 265 -236 299 -264 269 -266 -RAW_Data: 231 -262 263 -262 295 -268 273 -268 233 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -264 269 -266 231 -264 261 -264 255 -290 265 -234 259 -292 265 -272 269 -266 269 -266 231 -262 257 -290 265 -266 265 -236 299 -266 267 -266 231 -264 263 -262 261 -262 261 -264 257 -290 265 -272 269 -266 269 -266 231 -262 257 -258 289 -264 267 -268 233 -264 293 -234 299 -266 267 -268 231 -264 261 -262 255 -290 267 -266 233 -264 293 -268 273 -268 233 -262 261 -262 257 -290 265 -234 261 -290 265 -272 269 -266 269 -266 231 -262 261 -262 257 -258 291 -264 269 -266 233 -262 295 -234 299 -266 267 -268 231 -262 261 -262 257 -258 291 -230 295 -264 267 -268 271 -272 235 -266 263 -260 261 -262 257 -258 291 -264 267 -268 265 -236 299 -232 293 -264 267 -266 231 -264 257 -290 265 -232 259 -294 265 -272 269 -232 295 -230 293 -264 267 -268 265 -268 273 -268 231 -264 261 -260 257 -290 265 -234 261 -292 265 -264 265 -236 299 -266 269 -266 231 -262 257 -256 291 -230 295 -306 243 -272 235 -264 257 -288 265 -264 233 -264 257 -290 265 -266 265 -236 301 -264 269 -234 263 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -262 257 -290 267 -266 231 -264 295 -234 301 -230 297 -262 267 -268 231 -264 259 -262 295 -236 299 -234 295 -262 267 -266 233 -262 257 -258 289 -262 269 -268 265 -234 299 -266 267 -268 233 -262 261 -262 255 -258 291 -264 269 -266 233 -262 295 -268 271 -270 233 -262 261 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -264 269 -266 231 -264 261 -262 257 -290 265 -232 261 -292 265 -266 265 -268 273 -268 233 -262 261 -262 263 -262 257 -290 263 -274 275 -270 233 -262 257 -256 291 -262 269 -266 267 -236 299 -264 267 -268 229 -264 261 -264 255 -290 265 -268 231 -264 295 -236 297 -266 269 -266 231 -262 257 -290 265 -272 269 -234 295 -262 267 -266 231 -264 263 -262 257 -290 263 -234 259 -292 265 -274 267 -268 267 -266 231 -264 261 -260 263 -262 263 -262 261 -264 295 -236 299 -264 269 -266 231 -264 261 -264 261 -260 261 -264 257 -290 265 -272 275 -272 231 -264 259 -262 257 -290 265 -234 261 -290 265 -272 269 -266 269 -266 231 -262 261 -262 257 -292 265 -232 259 -292 267 -264 265 -236 301 -266 267 -266 231 -262 263 -262 261 -264 255 -258 291 -264 267 -274 267 -266 269 -266 231 -264 255 -258 291 -262 269 -266 231 -264 295 -236 299 -264 267 -268 231 -262 -RAW_Data: 263 -262 261 -262 263 -262 261 -264 295 -236 299 -264 269 -234 259 -290 265 -266 265 -236 299 -266 267 -266 231 -264 255 -290 267 -232 259 -292 265 -274 267 -234 295 -262 267 -266 231 -264 257 -258 291 -230 295 -296 241 -276 237 -268 257 -258 289 -262 267 -234 261 -292 265 -264 265 -236 299 -266 267 -266 231 -264 263 -262 257 -256 291 -230 295 -264 267 -268 263 -270 273 -268 231 -264 261 -262 255 -290 265 -234 259 -260 291 -262 269 -266 265 -236 299 -232 295 -264 267 -266 231 -264 295 -234 299 -266 267 -268 229 -264 261 -264 255 -290 265 -266 231 -266 295 -234 299 -266 267 -268 229 -264 261 -264 261 -262 257 -258 291 -264 267 -268 231 -264 295 -268 271 -268 233 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 257 -258 291 -262 269 -268 231 -264 293 -234 301 -266 267 -266 231 -262 257 -290 265 -234 259 -324 239 -276 237 -268 263 -262 261 -262 255 -292 265 -264 233 -264 295 -236 299 -264 267 -268 231 -262 263 -262 257 -258 291 -262 269 -268 231 -264 293 -268 273 -268 233 -262 261 -262 255 -292 265 -234 261 -292 263 -266 231 -264 295 -236 299 -264 269 -232 259 -260 289 -262 267 -268 265 -236 301 -264 267 -266 231 -264 257 -290 265 -232 259 -292 265 -266 265 -236 301 -264 269 -266 231 -262 263 -262 257 -290 265 -234 259 -292 265 -266 231 -262 297 -268 271 -270 231 -264 261 -260 263 -262 263 -262 295 -234 301 -266 267 -268 229 -264 261 -264 255 -258 291 -262 269 -234 259 -292 265 -272 267 -266 269 -268 229 -264 255 -258 291 -264 267 -274 275 -270 231 -264 255 -290 263 -266 231 -266 295 -236 299 -264 269 -266 231 -262 261 -264 261 -262 257 -258 291 -264 267 -268 265 -270 271 -268 231 -264 261 -262 261 -262 297 -234 299 -266 267 -266 231 -264 263 -262 257 -256 293 -262 269 -234 259 -292 231 -298 265 -270 271 -270 231 -262 261 -262 257 -258 291 -230 295 -264 269 -266 263 -236 299 -266 267 -268 231 -262 261 -264 261 -262 295 -236 299 -266 269 -266 231 -262 261 -264 257 -288 265 -266 231 -264 297 -234 299 -266 267 -268 229 -264 261 -264 257 -288 265 -268 231 -264 257 -290 265 -266 263 -236 301 -266 269 -266 231 -262 261 -262 257 -258 291 -264 267 -268 271 -274 235 -264 263 -260 257 -258 291 -262 269 -268 265 -234 299 -232 295 -262 267 -268 231 -264 261 -262 255 -258 293 -262 269 -268 265 -268 271 -236 261 -290 231 -298 265 -236 299 -266 269 -266 -RAW_Data: 231 -262 261 -262 257 -290 267 -264 231 -264 295 -236 301 -266 267 -266 231 -262 263 -262 261 -264 261 -296 269 -272 235 -266 263 -260 261 -262 257 -258 291 -264 267 -268 265 -270 271 -268 231 -264 261 -262 257 -290 265 -266 233 -264 261 -262 293 -270 273 -268 233 -264 261 -260 263 -262 257 -290 265 -268 231 -264 261 -262 293 -236 301 -266 267 -234 259 -258 291 -262 267 -268 265 -234 301 -264 267 -266 231 -264 263 -262 261 -262 261 -264 261 -264 295 -234 301 -264 267 -268 233 -262 261 -260 263 -262 257 -258 293 -262 269 -266 233 -262 295 -268 271 -270 231 -264 261 -262 261 -262 263 -262 295 -236 299 -264 269 -268 231 -262 261 -262 255 -292 265 -234 261 -258 291 -262 267 -274 269 -266 267 -266 231 -264 261 -262 263 -262 263 -294 269 -272 237 -266 261 -262 261 -262 255 -292 265 -272 269 -266 269 -266 231 -262 263 -262 257 -290 263 -234 261 -292 265 -264 265 -270 273 -268 231 -264 261 -262 261 -262 297 -268 271 -270 231 -264 261 -264 259 -262 257 -292 265 -264 233 -264 263 -262 293 -268 273 -270 231 -264 261 -262 255 -258 291 -264 269 -266 233 -262 295 -268 271 -270 233 -262 261 -262 255 -292 265 -234 261 -292 263 -272 275 -270 233 -262 261 -262 255 -290 267 -232 259 -292 265 -266 265 -270 273 -268 231 -264 255 -258 291 -264 267 -234 261 -292 263 -266 263 -236 301 -266 267 -266 231 -264 261 -260 257 -292 265 -232 259 -294 265 -266 263 -236 301 -266 267 -234 259 -258 289 -262 267 -268 233 -264 293 -234 301 -266 269 -266 229 -264 261 -264 255 -258 291 -230 295 -264 267 -266 265 -270 271 -270 231 -264 255 -290 263 -274 269 -266 269 -266 231 -262 261 -262 257 -258 293 -262 269 -268 265 -234 299 -264 269 -266 231 -264 255 -290 265 -232 259 -292 267 -266 271 -274 237 -266 261 -262 255 -290 263 -266 231 -266 295 -234 299 -266 269 -266 231 -262 263 -262 261 -264 261 -262 263 -262 295 -268 271 -270 233 -264 261 -260 257 -258 291 -264 267 -268 231 -264 293 -236 299 -264 269 -268 231 -262 261 -262 261 -264 261 -264 295 -268 271 -270 233 -264 261 -260 261 -262 257 -290 267 -266 231 -264 295 -234 301 -264 269 -266 231 -264 259 -262 257 -258 293 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -264 261 -262 255 -258 293 -262 269 -274 267 -266 269 -266 229 -264 261 -264 261 -262 255 -258 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 257 -290 265 -264 233 -264 263 -294 -RAW_Data: 269 -270 237 -266 257 -258 289 -262 269 -274 269 -266 267 -268 229 -262 261 -262 263 -262 263 -262 257 -290 265 -266 265 -270 273 -268 233 -262 261 -262 295 -234 301 -266 267 -266 231 -262 263 -262 257 -290 265 -266 231 -264 259 -290 263 -266 265 -270 271 -270 233 -262 261 -262 257 -290 265 -266 231 -264 295 -236 299 -266 269 -266 231 -262 261 -262 261 -264 257 -290 265 -266 231 -264 297 -268 271 -270 231 -264 255 -290 265 -232 259 -292 267 -272 267 -234 295 -262 267 -266 231 -264 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 257 -290 265 -234 259 -290 265 -266 265 -236 301 -266 233 -268 259 -290 265 -232 259 -292 265 -266 265 -234 301 -266 269 -266 231 -262 261 -264 255 -258 291 -264 267 -268 231 -264 293 -236 299 -264 269 -266 231 -264 257 -290 265 -272 275 -270 233 -262 261 -262 255 -290 267 -266 231 -264 257 -290 265 -266 265 -268 273 -270 231 -264 261 -262 255 -258 291 -264 267 -268 273 -272 235 -266 257 -288 265 -232 259 -292 265 -266 265 -270 273 -268 231 -264 261 -262 255 -292 265 -232 261 -292 265 -264 265 -236 301 -266 267 -266 231 -262 261 -262 263 -262 257 -292 265 -264 233 -264 295 -234 299 -266 269 -266 231 -262 257 -290 265 -272 269 -266 269 -266 231 -262 261 -262 263 -262 263 -262 257 -290 265 -274 267 -268 267 -266 231 -264 261 -262 261 -262 259 -258 291 -262 267 -268 265 -236 299 -264 269 -266 231 -262 257 -258 291 -262 269 -268 231 -264 293 -268 273 -268 233 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -236 299 -264 269 -266 231 -264 257 -288 265 -234 259 -292 265 -266 265 -234 301 -234 293 -264 267 -268 263 -234 299 -266 267 -268 231 -264 257 -288 265 -232 261 -258 293 -262 269 -266 263 -270 273 -268 231 -264 261 -262 257 -256 293 -304 243 -274 235 -264 261 -262 261 -262 261 -264 257 -290 265 -264 265 -236 301 -266 269 -266 229 -264 261 -264 255 -290 265 -266 231 -264 297 -234 299 -266 267 -268 229 -264 261 -264 255 -290 265 -266 231 -264 263 -262 295 -236 299 -264 269 -268 231 -264 259 -262 261 -264 295 -234 299 -266 269 -266 231 -264 261 -262 257 -258 291 -264 267 -268 231 -264 293 -234 301 -266 267 -266 231 -262 263 -262 257 -290 265 -266 231 -264 297 -234 299 -264 269 -266 231 -264 255 -258 291 -264 267 -268 231 -264 293 -236 299 -266 269 -266 229 -264 261 -264 261 -262 257 -290 265 -266 233 -264 -RAW_Data: 295 -268 271 -270 231 -262 261 -262 257 -258 293 -302 243 -274 235 -266 255 -256 289 -230 295 -264 267 -268 265 -270 271 -270 231 -262 261 -262 261 -264 255 -258 293 -262 269 -274 267 -268 233 -300 231 -262 261 -262 295 -236 299 -264 269 -266 231 -262 263 -262 263 -262 257 -290 265 -266 233 -264 295 -268 271 -270 231 -262 261 -262 257 -292 265 -264 273 -274 235 -266 263 -262 259 -262 255 -260 291 -264 267 -268 265 -236 299 -264 267 -266 231 -264 263 -262 257 -258 291 -230 293 -264 269 -272 269 -264 269 -266 231 -262 263 -262 257 -290 265 -232 259 -294 265 -266 263 -236 301 -266 233 -268 259 -290 265 -264 265 -236 301 -266 267 -266 231 -264 261 -262 261 -264 255 -292 265 -264 265 -236 301 -266 267 -268 229 -264 261 -262 255 -292 265 -234 261 -290 265 -266 265 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -268 263 -236 301 -264 267 -266 231 -264 263 -262 255 -290 265 -234 261 -260 291 -260 267 -268 265 -270 273 -268 231 -264 261 -260 257 -258 291 -264 267 -268 273 -238 263 -294 231 -266 259 -292 263 -274 267 -268 233 -300 231 -264 261 -262 257 -258 291 -230 295 -262 269 -266 265 -268 273 -268 233 -262 261 -262 257 -290 265 -274 275 -270 231 -264 259 -262 261 -264 257 -290 265 -266 231 -264 263 -262 295 -270 271 -268 233 -262 261 -262 261 -264 261 -264 261 -262 295 -236 299 -266 235 -300 231 -262 261 -262 261 -264 263 -262 257 -290 265 -266 263 -270 273 -268 233 -262 261 -262 263 -262 257 -290 265 -266 265 -236 301 -266 267 -266 231 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -266 235 -300 231 -262 257 -256 291 -230 293 -264 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 257 -288 265 -266 231 -264 297 -234 299 -266 267 -268 229 -264 263 -262 257 -288 265 -268 231 -264 261 -262 295 -268 273 -270 233 -262 261 -262 287 -264 269 -270 273 -268 231 -262 255 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -268 231 -262 255 -290 265 -232 261 -292 265 -266 231 -296 269 -240 263 -294 231 -300 231 -262 263 -262 295 -268 273 -268 233 -262 261 -262 261 -264 263 -262 261 -264 261 -262 295 -236 299 -264 269 -266 231 -264 261 -262 261 -262 263 -262 263 -262 295 -236 299 -266 267 -266 231 -264 261 -262 257 -258 291 -264 267 -274 269 -266 267 -266 231 -262 263 -262 257 -290 265 -266 231 -264 297 -234 299 -264 269 -266 231 -264 261 -264 255 -258 291 -264 -RAW_Data: 267 -268 229 -264 295 -236 299 -264 269 -266 231 -264 261 -262 261 -264 261 -264 261 -262 295 -270 271 -270 231 -264 261 -262 261 -262 257 -258 291 -264 267 -268 263 -236 299 -266 267 -268 229 -264 255 -258 293 -230 293 -264 269 -274 267 -266 269 -232 259 -290 265 -266 263 -236 301 -266 267 -266 231 -264 255 -290 265 -268 231 -264 257 -290 263 -266 265 -236 301 -266 267 -266 231 -264 255 -290 265 -272 269 -268 235 -268 263 -262 255 -290 265 -266 231 -264 257 -292 265 -266 263 -270 273 -268 233 -262 261 -262 255 -292 265 -234 259 -292 265 -272 269 -266 269 -266 231 -262 261 -262 261 -264 257 -292 265 -264 231 -264 263 -262 295 -270 271 -270 231 -264 255 -258 289 -264 267 -274 269 -234 293 -264 267 -266 231 -262 263 -262 257 -258 291 -262 269 -266 265 -236 299 -266 267 -266 231 -262 263 -262 261 -264 257 -256 293 -262 269 -268 265 -234 299 -266 267 -266 231 -262 263 -262 257 -290 265 -266 263 -236 301 -266 269 -266 231 -262 257 -290 265 -232 261 -292 265 -266 263 -236 301 -266 233 -300 231 -264 255 -258 291 -262 269 -274 275 -270 231 -262 261 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 261 -264 257 -290 265 -232 261 -290 265 -272 277 -270 233 -262 261 -260 257 -290 265 -266 265 -270 273 -268 233 -264 259 -262 257 -290 265 -234 261 -290 265 -266 265 -236 299 -266 267 -266 231 -264 255 -258 291 -230 295 -264 267 -268 229 -264 295 -234 299 -266 269 -266 231 -262 261 -262 263 -262 297 -268 273 -268 231 -264 261 -262 255 -292 265 -234 259 -292 265 -266 263 -270 273 -268 233 -262 261 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -266 267 -266 231 -262 263 -262 257 -290 265 -234 259 -292 265 -266 271 -274 237 -266 261 -260 257 -256 291 -264 267 -268 233 -262 295 -234 299 -264 269 -268 231 -262 261 -262 257 -258 293 -262 269 -266 265 -234 301 -232 295 -262 267 -266 233 -262 295 -268 273 -268 233 -262 261 -262 257 -290 265 -266 233 -264 261 -262 295 -268 273 -270 231 -264 261 -260 257 -290 265 -234 293 -266 267 -270 271 -268 229 -264 261 -262 255 -290 267 -266 233 -262 297 -234 299 -264 269 -266 231 -264 261 -264 261 -262 257 -290 265 -264 265 -236 301 -266 269 -266 229 -264 261 -264 255 -290 265 -234 259 -260 291 -262 267 -268 265 -270 271 -268 233 -262 261 -262 261 -264 295 -268 273 -268 231 -264 261 -262 261 -264 261 -264 261 -262 -RAW_Data: 263 -262 295 -234 301 -266 267 -268 229 -264 261 -262 263 -262 263 -262 257 -290 265 -266 231 -264 295 -268 273 -268 231 -264 261 -262 257 -290 265 -266 265 -236 301 -264 267 -266 231 -264 263 -262 261 -264 257 -256 291 -262 269 -266 265 -270 273 -268 231 -264 261 -262 261 -262 263 -294 269 -272 237 -266 263 -260 261 -262 257 -258 291 -264 269 -272 269 -264 269 -266 231 -264 261 -262 257 -290 265 -266 233 -264 257 -290 263 -272 269 -266 269 -266 231 -262 257 -290 265 -266 265 -270 273 -270 231 -262 261 -262 261 -264 257 -256 293 -262 269 -266 265 -236 299 -264 269 -266 231 -264 255 -290 265 -266 231 -264 263 -262 295 -234 299 -266 269 -268 231 -264 261 -260 261 -264 295 -234 299 -266 269 -266 233 -262 255 -290 265 -234 259 -292 265 -266 263 -236 301 -266 235 -300 229 -264 255 -292 263 -234 259 -260 291 -262 267 -268 265 -236 299 -266 267 -266 231 -264 261 -294 229 -264 257 -258 291 -264 267 -272 269 -266 235 -300 229 -264 255 -292 265 -232 261 -292 231 -298 265 -234 301 -266 235 -300 231 -262 261 -264 255 -258 293 -262 269 -266 263 -236 301 -264 235 -266 259 -292 231 -300 263 -270 273 -268 231 -264 261 -262 257 -258 291 -264 267 -268 265 -234 299 -266 267 -266 231 -264 261 -264 261 -262 257 -258 291 -296 241 -276 237 -268 263 -264 255 -288 265 -266 231 -298 263 -234 299 -266 233 -300 231 -264 263 -262 261 -294 229 -264 255 -292 265 -272 269 -266 235 -300 231 -262 261 -264 255 -258 293 -262 267 -268 265 -236 299 -264 267 -268 231 -264 261 -262 261 -296 229 -262 263 -262 295 -268 273 -268 233 -262 261 -262 257 -258 291 -230 293 -264 269 -274 269 -266 233 -300 231 -262 261 -264 255 -258 293 -262 267 -236 259 -292 231 -298 265 -234 299 -266 235 -300 231 -262 257 -258 293 -262 267 -274 267 -234 293 -264 267 -266 233 -262 263 -262 257 -258 289 -262 269 -268 231 -296 263 -268 271 -268 233 -296 229 -264 261 -294 229 -262 257 -324 239 -274 239 -266 259 -258 257 -294 267 -266 267 -270 271 -270 231 -264 259 -296 229 -294 231 -262 257 -290 231 -300 263 -270 267 -266 235 -298 231 -264 257 -290 265 -272 267 -268 235 -300 229 -296 229 -262 257 -258 261 -294 267 -234 261 -292 231 -298 263 -236 301 -264 235 -300 231 -296 229 -296 229 -294 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -268 291 -300 241 -272 235 -266 261 -262 259 -262 257 -292 231 -300 -RAW_Data: 265 -236 299 -266 233 -300 231 -296 229 -264 261 -294 229 -296 263 -234 299 -266 235 -300 231 -296 229 -262 261 -296 229 -294 229 -296 263 -268 273 -268 231 -296 231 -262 257 -290 231 -298 231 -298 229 -296 261 -268 265 -266 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 265 -268 267 -266 233 -300 231 -296 231 -262 293 -268 271 -270 233 -296 229 -262 261 -262 257 -290 231 -266 261 -292 231 -300 263 -270 267 -266 235 -300 229 -296 229 -264 255 -258 259 -296 267 -272 275 -270 231 -264 257 -290 229 -300 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 259 -262 295 -264 233 -300 265 -270 271 -268 233 -264 257 -290 229 -266 261 -258 261 -294 233 -302 265 -234 299 -266 233 -300 231 -298 227 -296 229 -296 229 -294 263 -270 271 -268 231 -296 231 -294 229 -262 257 -258 259 -296 267 -274 267 -266 235 -300 231 -294 229 -296 229 -296 227 -262 257 -260 259 -296 233 -302 265 -234 299 -264 235 -300 231 -264 257 -258 259 -294 233 -300 267 -268 271 -270 231 -296 229 -264 255 -258 259 -294 233 -268 261 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -274 275 -236 261 -292 229 -298 231 -296 263 -270 265 -264 235 -300 231 -296 229 -264 255 -258 259 -296 233 -300 265 -270 265 -264 235 -300 231 -264 257 -258 291 -270 269 -272 235 -302 231 -296 227 -296 229 -262 257 -292 231 -298 231 -296 263 -270 265 -266 233 -300 231 -264 257 -290 231 -298 231 -298 231 -294 263 -234 299 -266 233 -300 231 -296 229 -296 229 -264 255 -290 233 -298 265 -270 265 -266 235 -300 231 -296 229 -296 227 -296 229 -296 261 -270 265 -264 235 -300 231 -264 257 -258 259 -294 233 -302 231 -296 263 -266 265 -266 235 -302 231 -264 261 -260 257 -258 261 -294 233 -268 261 -292 263 -272 267 -268 235 -300 229 -264 257 -258 259 -294 235 -300 231 -296 263 -234 299 -266 233 -302 231 -296 229 -262 255 -292 231 -300 229 -298 263 -268 265 -266 235 -300 231 -262 257 -258 291 -270 271 -270 237 -302 231 -264 255 -258 257 -294 267 -268 265 -270 267 -264 235 -298 231 -296 229 -296 229 -294 229 -296 229 -296 263 -234 299 -266 233 -268 259 -292 231 -300 231 -296 263 -268 265 -264 235 -302 231 -296 227 -296 229 -262 257 -258 259 -296 267 -272 269 -266 233 -300 231 -296 231 -294 229 -296 229 -296 227 -296 229 -296 263 -268 265 -266 233 -300 231 -296 231 -262 257 -290 231 -300 -RAW_Data: 263 -270 273 -268 231 -296 231 -294 229 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -296 231 -294 229 -262 257 -258 259 -296 233 -302 265 -234 299 -232 263 -296 233 -300 231 -264 257 -290 231 -298 231 -298 229 -296 269 -272 235 -298 231 -262 255 -290 231 -266 259 -260 261 -294 267 -274 267 -268 233 -300 231 -296 229 -294 229 -296 229 -262 257 -292 265 -272 267 -234 263 -262 261 -296 233 -300 265 -268 265 -266 235 -302 231 -264 261 -260 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -264 257 -258 259 -294 269 -272 275 -270 231 -296 229 -262 255 -292 231 -300 231 -296 229 -296 263 -234 299 -264 235 -302 231 -262 257 -258 291 -230 293 -264 235 -300 265 -270 271 -268 231 -264 261 -262 257 -290 231 -266 261 -292 231 -298 231 -298 263 -234 299 -266 233 -268 259 -260 259 -294 233 -300 265 -236 299 -264 235 -300 233 -262 261 -262 257 -290 233 -298 231 -298 263 -234 299 -232 295 -264 233 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 265 -234 301 -264 235 -300 231 -296 229 -264 261 -294 263 -234 301 -264 235 -300 231 -296 229 -262 257 -258 291 -262 269 -234 261 -290 265 -272 267 -266 235 -300 231 -262 257 -290 265 -232 293 -266 269 -268 271 -268 233 -262 255 -258 291 -264 267 -268 231 -264 261 -262 295 -268 273 -268 231 -264 261 -262 257 -258 291 -230 295 -264 267 -266 265 -236 299 -264 267 -268 231 -262 263 -262 257 -258 291 -262 269 -268 231 -264 293 -268 273 -268 231 -264 257 -256 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 261 -262 257 -258 291 -264 269 -266 265 -236 299 -232 293 -264 267 -266 231 -264 261 -264 255 -258 291 -264 267 -268 233 -262 295 -268 271 -270 231 -264 261 -260 263 -262 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -258 293 -262 269 -240 301 -266 267 -234 263 -264 255 -290 265 -240 303 -266 269 -232 265 -262 261 -264 261 -262 255 -292 265 -266 265 -270 271 -270 231 -262 261 -262 257 -258 293 -262 267 -268 231 -264 293 -268 273 -270 231 -264 261 -262 261 -264 295 -234 299 -266 269 -266 231 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -258 291 -230 295 -262 269 -266 263 -236 301 -264 267 -268 231 -262 263 -262 263 -262 261 -262 295 -268 273 -270 233 -262 261 -260 257 -290 265 -234 261 -292 265 -264 265 -270 273 -268 233 -262 261 -262 -RAW_Data: 255 -290 267 -234 259 -260 289 -262 267 -268 265 -236 301 -264 267 -268 229 -264 261 -264 261 -262 257 -290 265 -266 273 -274 235 -266 261 -262 255 -258 291 -262 269 -234 261 -290 265 -264 265 -236 301 -266 267 -234 263 -262 257 -258 291 -262 269 -268 231 -264 293 -268 273 -236 261 -258 289 -262 267 -268 265 -236 301 -264 267 -266 231 -264 261 -262 255 -292 265 -266 233 -264 261 -262 295 -268 273 -270 231 -264 261 -260 257 -290 265 -274 275 -270 233 -262 261 -262 261 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 263 -262 261 -262 261 -262 263 -262 263 -262 295 -236 299 -266 269 -232 263 -264 261 -264 255 -290 265 -232 261 -260 291 -262 267 -268 265 -270 271 -268 233 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -264 269 -266 231 -264 257 -256 291 -264 269 -234 259 -292 263 -266 265 -236 299 -266 269 -232 265 -262 257 -256 291 -264 269 -266 233 -262 295 -268 271 -270 231 -264 255 -290 265 -266 265 -236 299 -266 269 -234 263 -262 263 -262 257 -288 267 -266 231 -264 261 -262 295 -270 273 -268 231 -264 261 -260 289 -264 271 -270 271 -236 263 -262 261 -260 257 -258 291 -264 267 -236 259 -292 265 -266 263 -270 273 -268 231 -264 261 -262 255 -290 267 -266 233 -264 293 -234 299 -266 269 -234 265 -262 261 -262 261 -264 255 -258 293 -262 269 -268 263 -270 271 -268 233 -262 257 -290 265 -232 259 -292 265 -272 269 -266 235 -300 231 -262 261 -262 257 -292 265 -266 231 -264 261 -264 295 -234 299 -266 269 -266 231 -262 261 -294 229 -264 263 -262 257 -290 265 -272 269 -266 269 -268 229 -264 255 -290 265 -234 261 -292 263 -266 265 -234 301 -266 269 -266 229 -264 261 -262 257 -290 265 -266 233 -264 261 -262 295 -270 271 -270 231 -262 261 -262 295 -236 299 -266 269 -266 231 -262 257 -290 265 -266 231 -264 263 -262 295 -268 271 -270 231 -264 261 -262 261 -262 263 -262 257 -290 265 -268 265 -270 271 -270 231 -264 255 -288 265 -266 267 -236 299 -232 293 -264 267 -266 231 -264 263 -262 255 -290 265 -234 261 -292 265 -266 263 -270 273 -268 233 -262 261 -262 255 -290 267 -266 233 -262 263 -262 295 -234 299 -266 269 -266 231 -264 261 -262 263 -262 293 -236 299 -266 269 -234 263 -262 257 -288 265 -234 261 -292 265 -266 263 -270 273 -268 233 -262 261 -262 261 -264 255 -290 267 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -262 261 -262 257 -258 291 -264 -RAW_Data: 267 -240 303 -266 267 -268 229 -264 261 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -268 231 -262 257 -290 263 -234 259 -292 265 -266 265 -236 299 -234 295 -262 267 -264 231 -264 295 -270 271 -270 231 -264 255 -290 265 -232 259 -260 293 -262 267 -268 265 -268 273 -268 233 -262 259 -262 257 -258 293 -304 243 -274 235 -264 261 -262 255 -290 265 -232 259 -294 265 -266 263 -236 301 -266 269 -232 265 -262 259 -262 257 -290 265 -268 231 -266 295 -234 299 -264 269 -266 231 -264 261 -262 257 -290 265 -266 231 -264 263 -262 295 -234 299 -266 269 -234 263 -264 261 -262 261 -264 295 -234 299 -266 269 -266 231 -262 261 -264 257 -256 293 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -262 261 -264 255 -258 293 -262 269 -268 231 -264 293 -268 271 -270 233 -262 261 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -264 261 -262 257 -258 291 -230 295 -262 269 -274 273 -238 263 -262 261 -262 255 -258 293 -304 243 -274 235 -266 255 -256 289 -230 295 -264 267 -268 265 -270 271 -268 233 -262 261 -262 255 -292 265 -266 231 -264 263 -262 295 -268 273 -268 233 -262 257 -288 265 -266 267 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -232 259 -292 267 -266 263 -236 301 -266 267 -234 263 -264 261 -262 261 -262 263 -262 263 -262 295 -236 299 -264 269 -266 231 -264 261 -262 261 -264 257 -290 263 -274 269 -266 269 -234 263 -262 257 -290 265 -232 259 -292 267 -266 263 -270 273 -268 231 -264 261 -262 255 -292 265 -266 233 -264 257 -288 265 -266 265 -236 301 -264 269 -234 263 -262 263 -262 261 -262 261 -264 263 -262 295 -268 273 -268 233 -262 257 -256 291 -262 269 -234 261 -290 265 -266 265 -236 299 -264 269 -234 263 -264 255 -292 263 -266 231 -266 263 -262 293 -268 273 -236 261 -292 263 -266 263 -236 299 -266 269 -266 231 -262 263 -262 261 -264 255 -290 265 -268 265 -236 299 -264 269 -266 231 -264 261 -264 259 -262 257 -290 265 -274 275 -238 265 -262 261 -262 255 -258 293 -262 269 -234 259 -292 263 -266 265 -236 299 -266 269 -234 263 -262 261 -262 257 -258 291 -262 269 -274 269 -266 267 -234 263 -264 261 -262 261 -264 255 -258 293 -262 269 -268 231 -262 295 -234 299 -266 267 -268 231 -262 261 -262 295 -270 271 -270 231 -264 261 -262 255 -290 267 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 261 -262 257 -290 265 -268 -RAW_Data: 231 -264 295 -234 299 -266 269 -266 231 -262 261 -264 261 -264 261 -262 295 -236 299 -264 269 -234 263 -264 261 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -268 233 -262 261 -262 257 -258 291 -296 241 -278 239 -266 263 -260 257 -288 265 -268 231 -264 295 -268 273 -268 233 -262 261 -262 255 -292 265 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 261 -264 295 -268 273 -268 233 -262 261 -262 255 -292 265 -234 259 -292 265 -266 263 -270 273 -268 233 -262 261 -262 261 -264 261 -264 255 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -264 255 -258 291 -262 269 -240 303 -266 267 -234 263 -264 261 -260 257 -290 267 -266 233 -264 293 -234 299 -266 269 -266 231 -264 261 -262 261 -262 257 -290 265 -268 265 -236 299 -232 295 -262 267 -268 231 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -234 259 -292 263 -232 259 -260 293 -262 267 -266 265 -236 301 -264 267 -234 263 -264 261 -262 263 -262 257 -290 265 -266 265 -236 299 -266 267 -234 259 -292 265 -264 265 -270 271 -270 231 -264 255 -258 291 -262 269 -234 261 -290 265 -264 265 -270 273 -268 233 -262 261 -262 261 -264 261 -264 261 -296 267 -274 235 -266 261 -262 261 -262 261 -264 261 -264 295 -234 301 -264 269 -266 231 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 255 -290 265 -234 261 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 255 -258 291 -264 267 -240 303 -266 267 -234 263 -264 261 -262 261 -264 261 -264 261 -260 295 -236 301 -266 267 -234 263 -264 261 -262 257 -290 265 -232 261 -258 293 -262 267 -268 265 -234 299 -266 269 -234 263 -262 261 -262 263 -262 295 -236 299 -266 269 -234 263 -262 261 -262 261 -264 257 -290 265 -234 259 -292 265 -266 263 -270 273 -270 231 -264 261 -260 263 -262 261 -264 261 -296 269 -272 237 -266 261 -262 261 -260 263 -262 297 -268 273 -268 233 -262 261 -262 261 -264 255 -292 265 -264 233 -264 295 -236 299 -264 269 -234 263 -264 261 -262 295 -236 299 -264 269 -234 263 -264 261 -262 261 -262 257 -290 267 -266 231 -264 295 -236 299 -266 267 -266 231 -264 255 -290 265 -232 261 -292 265 -266 265 -234 301 -266 269 -232 265 -262 261 -264 255 -258 291 -262 269 -268 265 -268 273 -268 231 -264 255 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -264 255 -258 291 -264 267 -268 231 -264 293 -234 -RAW_Data: 299 -266 269 -266 231 -264 261 -262 257 -258 291 -262 269 -234 261 -290 263 -272 269 -266 269 -234 263 -264 261 -262 255 -292 265 -266 267 -236 299 -232 293 -262 267 -268 231 -264 261 -262 255 -258 293 -262 269 -268 265 -234 301 -264 267 -266 231 -264 261 -264 295 -268 273 -268 231 -264 261 -262 261 -262 257 -290 267 -266 263 -236 301 -266 267 -234 263 -264 261 -262 257 -290 265 -232 261 -292 265 -272 275 -270 233 -262 261 -262 255 -290 265 -268 265 -270 273 -268 231 -264 259 -262 257 -290 265 -234 259 -292 265 -266 265 -234 301 -266 269 -232 265 -262 257 -256 291 -230 295 -264 267 -268 231 -262 297 -234 299 -266 267 -266 231 -264 261 -264 261 -262 295 -234 299 -266 269 -234 263 -264 261 -262 261 -262 257 -258 291 -264 267 -274 269 -266 269 -232 263 -264 261 -264 261 -262 255 -258 293 -262 269 -268 265 -234 299 -232 295 -262 269 -266 231 -262 263 -262 257 -258 291 -262 269 -274 275 -236 263 -264 259 -262 257 -290 265 -234 261 -258 291 -262 267 -268 265 -270 273 -268 231 -262 261 -262 257 -290 265 -234 261 -290 265 -274 275 -270 231 -264 255 -288 265 -266 265 -270 273 -268 231 -264 261 -262 261 -264 261 -262 263 -262 263 -262 295 -234 299 -266 269 -266 231 -264 261 -262 289 -266 267 -270 273 -234 263 -262 261 -262 255 -292 265 -268 231 -262 263 -262 295 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -266 267 -236 299 -264 267 -268 231 -262 263 -262 261 -264 261 -262 255 -258 291 -264 269 -266 265 -270 273 -236 259 -258 291 -260 269 -266 233 -262 295 -234 299 -266 269 -234 263 -264 255 -290 265 -234 259 -292 265 -266 265 -236 299 -232 295 -262 269 -266 231 -262 263 -262 263 -262 261 -262 295 -236 299 -266 269 -266 231 -262 261 -264 255 -290 265 -266 231 -264 297 -234 299 -266 269 -266 231 -262 261 -264 257 -256 293 -262 269 -268 231 -264 293 -234 299 -264 269 -266 231 -264 263 -262 289 -264 269 -268 273 -268 231 -262 255 -290 265 -232 259 -294 265 -266 263 -236 301 -266 267 -266 231 -262 263 -262 263 -262 257 -290 263 -266 265 -270 273 -268 233 -262 257 -290 263 -266 231 -266 295 -268 273 -268 231 -264 261 -262 261 -264 255 -292 265 -232 259 -292 267 -264 265 -270 273 -268 233 -262 261 -262 261 -264 257 -290 265 -266 263 -236 301 -232 295 -262 267 -268 229 -264 263 -262 263 -262 293 -268 273 -270 233 -264 261 -260 257 -290 265 -234 259 -292 265 -272 267 -268 -RAW_Data: 267 -266 231 -264 261 -262 263 -262 257 -290 265 -266 233 -264 293 -234 299 -266 267 -268 233 -262 261 -262 257 -258 291 -230 295 -264 267 -266 271 -274 235 -266 261 -262 261 -262 257 -258 291 -264 267 -268 233 -262 295 -232 299 -266 269 -266 231 -264 255 -292 265 -232 259 -292 265 -274 267 -234 263 -262 293 -262 269 -268 263 -270 271 -268 231 -264 261 -262 257 -290 265 -234 259 -292 231 -300 263 -236 301 -266 235 -300 229 -264 255 -258 291 -230 295 -304 243 -274 233 -266 255 -256 293 -262 267 -234 259 -292 265 -266 263 -236 301 -266 233 -302 229 -264 261 -262 257 -290 265 -266 231 -296 263 -270 271 -268 231 -264 263 -262 261 -262 257 -290 265 -266 231 -264 297 -234 299 -232 295 -264 267 -266 231 -264 261 -264 261 -262 295 -234 301 -266 233 -300 231 -262 257 -258 293 -228 295 -264 267 -266 265 -236 299 -266 267 -268 229 -264 261 -262 261 -264 257 -258 291 -262 267 -268 231 -264 295 -268 271 -270 233 -262 257 -288 265 -268 231 -264 295 -268 271 -268 233 -264 261 -264 261 -262 257 -256 291 -264 269 -266 265 -236 299 -264 269 -266 229 -264 263 -262 257 -258 291 -230 295 -304 243 -274 233 -266 255 -288 265 -266 231 -264 297 -234 299 -266 267 -266 231 -264 263 -262 255 -290 265 -266 233 -264 295 -234 299 -264 269 -266 231 -264 261 -264 261 -262 295 -234 301 -264 269 -268 229 -264 261 -262 257 -290 265 -268 231 -264 257 -290 263 -266 265 -270 273 -270 231 -264 259 -262 261 -264 255 -292 265 -266 231 -264 295 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -272 275 -272 231 -262 261 -262 255 -292 265 -234 259 -292 265 -272 267 -268 269 -234 263 -262 261 -262 255 -292 267 -232 259 -292 265 -266 265 -236 299 -266 267 -266 231 -264 261 -262 257 -290 265 -268 231 -264 261 -264 293 -268 273 -270 231 -264 255 -256 291 -264 267 -268 233 -262 295 -234 299 -264 269 -268 231 -264 259 -262 261 -264 263 -262 261 -264 295 -234 301 -266 269 -232 259 -290 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 263 -262 257 -290 263 -268 265 -236 299 -266 267 -266 231 -264 255 -258 291 -230 295 -296 241 -276 239 -268 257 -290 263 -232 259 -292 267 -264 265 -236 301 -232 295 -262 267 -266 231 -264 257 -256 291 -230 295 -264 267 -268 263 -270 273 -268 231 -264 261 -262 255 -258 291 -264 267 -268 231 -264 295 -234 299 -266 269 -266 231 -262 261 -264 255 -290 267 -266 263 -236 301 -266 -RAW_Data: 267 -234 263 -264 255 -290 265 -266 233 -264 261 -264 293 -234 301 -266 267 -268 229 -264 261 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 257 -288 265 -266 231 -266 295 -234 299 -266 269 -234 263 -262 263 -262 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -266 231 -264 257 -258 289 -230 295 -296 241 -278 239 -268 261 -262 255 -288 265 -266 267 -236 299 -264 269 -266 231 -264 257 -256 291 -264 269 -234 259 -290 265 -272 269 -266 269 -234 263 -262 255 -290 265 -274 269 -266 269 -234 263 -262 261 -262 257 -258 291 -264 267 -234 261 -290 265 -266 265 -270 271 -270 231 -264 259 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -266 267 -234 265 -262 261 -264 255 -290 265 -234 291 -268 275 -272 235 -264 261 -262 259 -262 257 -292 265 -266 233 -262 295 -268 273 -268 233 -262 257 -288 265 -266 233 -264 257 -288 267 -266 265 -236 301 -264 267 -266 231 -264 261 -264 261 -262 257 -256 291 -264 269 -266 233 -262 295 -268 273 -236 259 -260 289 -230 293 -262 269 -268 265 -270 271 -270 231 -262 261 -262 255 -258 291 -230 295 -232 293 -264 269 -238 303 -266 267 -234 263 -264 255 -290 265 -274 267 -266 269 -234 263 -264 255 -290 265 -234 259 -292 265 -272 269 -234 295 -262 267 -266 231 -262 257 -290 265 -266 231 -266 261 -296 269 -238 263 -296 265 -232 263 -264 261 -264 295 -234 299 -232 295 -264 267 -266 231 -264 255 -258 291 -264 269 -266 233 -262 295 -268 271 -270 231 -264 261 -262 255 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -262 257 -290 265 -268 265 -270 273 -268 231 -264 259 -262 257 -290 265 -268 231 -264 295 -234 299 -266 267 -268 231 -262 261 -262 261 -264 257 -292 263 -234 259 -292 265 -266 263 -236 301 -266 269 -232 263 -264 261 -264 261 -262 261 -262 295 -236 301 -266 267 -234 263 -262 263 -262 257 -256 291 -264 267 -268 231 -264 295 -234 299 -266 267 -268 229 -264 261 -264 261 -262 263 -262 263 -294 269 -272 237 -266 261 -262 261 -262 293 -236 301 -266 267 -266 231 -264 257 -288 265 -234 261 -292 265 -266 263 -236 301 -264 269 -234 263 -262 261 -262 295 -236 301 -266 267 -234 263 -262 261 -262 257 -290 265 -234 261 -292 263 -266 265 -270 271 -270 231 -264 261 -262 255 -290 267 -232 259 -260 291 -262 269 -274 267 -268 267 -234 263 -262 257 -288 267 -266 233 -264 255 -290 265 -266 265 -270 -RAW_Data: 273 -268 233 -262 261 -262 255 -292 265 -266 233 -264 293 -268 273 -268 233 -262 261 -262 257 -258 291 -262 269 -268 265 -234 301 -230 295 -264 267 -266 231 -264 261 -262 255 -258 291 -264 269 -266 233 -264 293 -268 273 -270 231 -264 261 -260 263 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 261 -262 263 -262 257 -258 291 -264 269 -238 303 -266 267 -234 263 -264 261 -262 261 -262 295 -270 273 -268 231 -264 261 -262 261 -262 263 -262 257 -290 265 -266 231 -264 297 -268 273 -268 231 -264 255 -258 291 -230 295 -264 267 -268 271 -274 233 -266 257 -256 289 -262 269 -268 265 -236 299 -266 267 -234 263 -262 263 -262 261 -264 255 -258 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 257 -256 291 -262 269 -268 231 -264 293 -236 299 -266 267 -234 263 -264 261 -264 255 -290 265 -274 269 -266 269 -232 265 -262 255 -290 265 -234 261 -290 265 -266 265 -236 299 -266 269 -234 263 -262 263 -262 255 -290 265 -266 233 -264 261 -264 293 -234 301 -266 267 -266 231 -264 261 -262 261 -264 255 -290 267 -266 273 -274 235 -266 261 -260 257 -256 293 -262 269 -234 259 -292 265 -264 265 -236 301 -264 269 -234 263 -262 257 -256 293 -262 269 -268 231 -264 293 -234 299 -266 269 -234 259 -290 265 -272 267 -268 267 -234 265 -262 255 -290 265 -268 231 -264 261 -262 295 -236 299 -266 269 -232 265 -262 261 -262 261 -264 289 -264 277 -274 235 -264 261 -260 261 -262 257 -290 265 -268 231 -264 295 -234 299 -264 269 -268 231 -262 261 -262 261 -264 257 -290 265 -266 265 -270 273 -268 233 -262 261 -262 255 -290 267 -266 233 -264 255 -290 265 -266 265 -236 299 -266 269 -232 259 -260 289 -230 293 -264 269 -266 265 -270 271 -270 231 -264 261 -260 261 -264 261 -264 261 -262 295 -236 299 -266 269 -232 265 -262 261 -264 255 -258 291 -264 267 -236 259 -290 265 -266 265 -270 271 -270 231 -264 261 -260 257 -290 265 -268 231 -264 295 -234 299 -266 267 -268 231 -262 263 -262 257 -256 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 295 -270 273 -268 233 -262 261 -262 255 -258 291 -264 267 -274 269 -234 293 -262 267 -268 231 -264 257 -288 265 -268 231 -264 263 -260 295 -270 271 -270 231 -264 261 -262 261 -262 295 -236 299 -266 269 -232 265 -262 261 -262 257 -290 265 -234 261 -292 265 -264 265 -270 273 -236 263 -264 259 -262 257 -290 265 -268 231 -264 263 -262 293 -234 301 -266 -RAW_Data: 269 -234 263 -262 263 -262 257 -256 293 -262 269 -238 303 -266 267 -234 263 -264 261 -262 257 -290 265 -266 231 -264 297 -268 273 -268 231 -264 261 -262 259 -262 263 -264 255 -292 265 -266 233 -264 295 -234 299 -264 269 -234 263 -264 261 -262 257 -258 291 -264 267 -236 297 -270 271 -268 231 -264 255 -290 265 -232 259 -260 293 -262 269 -268 263 -236 299 -264 269 -232 265 -262 257 -258 291 -262 269 -268 231 -264 293 -268 273 -236 259 -260 289 -262 267 -240 303 -266 269 -232 265 -262 255 -258 291 -264 267 -268 233 -262 295 -234 299 -264 269 -234 265 -262 261 -262 257 -258 291 -296 241 -276 273 -234 263 -262 255 -256 291 -262 269 -268 231 -264 293 -234 301 -266 269 -232 265 -262 261 -262 261 -264 257 -290 265 -266 265 -270 273 -268 233 -262 261 -262 257 -290 265 -234 259 -292 265 -266 231 -262 295 -236 299 -266 269 -234 263 -262 263 -262 261 -262 295 -236 299 -266 269 -232 265 -262 261 -264 255 -258 291 -262 269 -266 267 -236 299 -264 269 -266 231 -262 263 -262 255 -290 265 -234 261 -258 291 -262 269 -240 303 -232 295 -262 267 -266 233 -262 261 -262 261 -264 295 -234 301 -264 269 -234 263 -264 261 -260 257 -292 265 -266 233 -264 257 -288 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 289 -266 269 -270 271 -234 265 -262 261 -262 259 -262 257 -292 265 -268 265 -234 301 -264 267 -268 231 -262 263 -262 257 -290 263 -268 231 -264 295 -236 299 -264 269 -234 263 -262 263 -262 257 -290 265 -266 231 -264 263 -262 295 -234 299 -266 269 -234 259 -290 265 -266 231 -262 263 -262 295 -236 299 -264 269 -234 265 -262 261 -262 257 -290 265 -268 231 -264 261 -262 295 -234 301 -266 269 -232 265 -262 261 -262 257 -290 265 -266 233 -264 263 -262 293 -268 273 -270 231 -264 255 -258 289 -262 269 -268 265 -236 299 -264 269 -234 263 -264 261 -262 261 -262 257 -290 265 -268 231 -264 295 -268 273 -268 233 -262 261 -262 257 -258 291 -304 243 -274 235 -264 255 -290 263 -234 259 -292 265 -266 265 -270 273 -268 233 -262 261 -262 255 -290 267 -232 261 -292 265 -266 263 -270 273 -236 265 -262 255 -290 265 -266 265 -236 301 -264 267 -268 229 -264 261 -262 257 -258 291 -230 295 -264 269 -266 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 261 -262 263 -262 257 -290 267 -272 269 -266 269 -234 263 -262 255 -290 267 -234 259 -292 -RAW_Data: 265 -264 265 -270 271 -270 233 -262 261 -262 255 -290 267 -266 233 -264 255 -290 265 -266 265 -236 301 -264 269 -232 265 -262 261 -264 261 -262 263 -262 261 -262 295 -270 273 -268 233 -262 255 -258 291 -262 269 -234 261 -290 265 -234 297 -236 299 -264 269 -234 263 -262 263 -262 261 -264 261 -264 261 -262 295 -270 271 -236 261 -290 265 -264 265 -236 299 -266 269 -232 265 -262 261 -264 261 -264 255 -290 265 -266 265 -236 301 -266 233 -300 231 -262 263 -262 261 -262 257 -290 265 -274 275 -270 231 -264 261 -262 255 -290 265 -234 261 -292 231 -298 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 257 -258 291 -262 267 -274 271 -266 235 -298 231 -264 261 -262 261 -262 259 -258 289 -262 267 -268 233 -264 293 -236 299 -264 269 -266 231 -264 263 -262 293 -268 273 -270 231 -264 261 -262 255 -290 267 -234 259 -292 265 -266 263 -270 273 -268 231 -264 261 -262 255 -258 291 -264 267 -236 259 -292 231 -298 265 -236 301 -266 267 -266 231 -262 261 -262 263 -262 261 -264 295 -234 301 -266 269 -266 229 -264 261 -264 261 -262 255 -292 265 -264 233 -264 295 -270 271 -268 233 -262 261 -262 257 -256 293 -296 241 -276 239 -268 263 -262 261 -260 261 -264 261 -264 295 -268 271 -270 233 -262 261 -262 255 -290 267 -232 259 -294 265 -266 265 -236 299 -264 267 -268 231 -262 263 -262 295 -234 299 -266 269 -266 231 -264 261 -260 257 -290 267 -232 261 -292 265 -266 263 -270 273 -268 233 -262 261 -262 261 -262 257 -260 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -262 255 -258 291 -264 269 -274 267 -268 267 -234 263 -262 261 -262 255 -258 293 -262 269 -268 265 -236 299 -264 269 -266 231 -262 261 -264 261 -264 255 -290 265 -268 265 -234 301 -232 295 -262 267 -266 231 -264 263 -262 255 -290 265 -268 231 -264 295 -236 299 -264 269 -232 259 -292 265 -232 259 -260 291 -262 267 -268 265 -236 299 -264 269 -266 231 -264 261 -264 261 -262 255 -290 267 -266 265 -236 301 -264 267 -234 259 -290 265 -266 265 -270 271 -270 231 -264 255 -290 265 -232 259 -292 267 -264 265 -236 301 -266 267 -234 263 -264 261 -262 261 -262 263 -262 261 -296 269 -272 237 -266 261 -262 261 -262 261 -264 261 -264 295 -234 301 -264 269 -266 231 -262 263 -262 261 -264 261 -262 263 -262 295 -236 299 -264 269 -266 231 -264 261 -262 261 -264 261 -264 261 -262 257 -290 265 -266 265 -236 301 -264 269 -232 259 -292 265 -266 -RAW_Data: 263 -236 301 -266 267 -234 263 -264 261 -262 261 -262 263 -262 261 -264 295 -234 301 -266 269 -232 265 -262 259 -262 257 -292 265 -234 259 -260 291 -260 269 -266 267 -236 299 -264 269 -266 231 -262 263 -262 261 -264 293 -234 301 -266 267 -266 231 -264 261 -264 255 -290 265 -266 231 -264 263 -264 293 -234 301 -266 269 -234 263 -262 261 -262 261 -264 261 -264 261 -296 269 -272 235 -266 259 -288 265 -264 231 -264 295 -270 273 -268 231 -264 261 -262 261 -262 257 -290 267 -266 231 -262 297 -234 301 -266 267 -234 263 -264 261 -262 295 -234 301 -266 269 -232 263 -264 261 -262 261 -262 257 -290 267 -266 233 -262 295 -234 299 -266 267 -268 231 -264 257 -256 291 -230 295 -264 267 -238 303 -266 267 -268 229 -264 261 -262 257 -258 291 -262 269 -234 261 -290 265 -272 275 -238 265 -262 255 -258 289 -262 269 -268 231 -264 295 -236 299 -264 269 -266 231 -262 261 -262 257 -258 291 -264 267 -268 233 -262 295 -234 299 -266 269 -234 263 -262 263 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 267 -268 231 -262 257 -290 265 -266 265 -236 299 -232 295 -262 269 -266 231 -264 261 -264 255 -258 291 -262 269 -268 265 -234 299 -266 267 -268 229 -264 261 -264 293 -268 273 -270 231 -264 261 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 257 -290 265 -234 259 -292 265 -272 275 -270 233 -262 255 -256 291 -264 267 -268 265 -236 301 -264 267 -234 263 -262 263 -262 263 -262 261 -264 261 -262 295 -234 301 -266 267 -234 263 -264 255 -258 291 -230 295 -264 267 -266 231 -264 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 295 -234 301 -264 269 -234 263 -262 261 -262 263 -262 257 -290 267 -266 231 -264 295 -268 273 -268 231 -264 261 -262 257 -290 265 -232 261 -292 265 -266 263 -270 273 -268 233 -262 261 -262 255 -292 265 -234 259 -292 265 -266 263 -270 273 -270 231 -264 261 -260 257 -290 265 -234 261 -258 291 -262 267 -268 265 -270 273 -268 231 -264 259 -262 257 -290 265 -234 259 -292 265 -272 275 -238 261 -290 263 -232 259 -292 265 -266 231 -264 297 -234 299 -264 269 -266 231 -262 263 -262 257 -258 291 -230 295 -264 267 -266 265 -270 271 -270 231 -264 255 -256 291 -262 269 -234 261 -290 265 -266 265 -236 299 -266 267 -234 263 -264 261 -264 261 -262 263 -262 295 -268 273 -268 231 -264 261 -262 255 -258 291 -230 295 -264 269 -238 305 -232 295 -262 267 -266 -RAW_Data: 231 -262 263 -262 257 -290 265 -266 233 -264 261 -262 293 -236 301 -266 267 -234 263 -264 255 -258 291 -262 269 -274 269 -232 295 -262 267 -266 231 -264 263 -262 261 -262 255 -292 265 -266 233 -264 295 -268 271 -270 231 -264 261 -260 263 -262 257 -258 291 -296 241 -276 239 -268 257 -258 289 -262 267 -268 265 -270 273 -268 231 -262 261 -262 261 -264 261 -264 255 -292 265 -266 263 -236 301 -266 267 -234 263 -264 255 -290 265 -274 269 -266 269 -234 263 -262 261 -262 255 -292 265 -234 259 -258 293 -262 267 -274 269 -266 269 -232 263 -264 255 -290 265 -266 231 -264 263 -264 295 -234 299 -266 267 -234 263 -264 261 -264 255 -258 291 -262 269 -268 265 -270 271 -268 231 -264 259 -262 263 -262 257 -292 265 -264 233 -264 295 -268 273 -268 231 -264 261 -262 261 -264 255 -290 267 -266 231 -264 295 -234 301 -264 269 -266 231 -264 261 -262 255 -258 293 -262 269 -268 263 -236 299 -266 267 -234 259 -290 265 -234 259 -258 291 -264 267 -268 265 -234 299 -266 267 -266 231 -264 261 -264 261 -262 261 -264 261 -264 295 -234 299 -266 267 -268 231 -262 261 -264 295 -234 299 -266 267 -268 231 -262 263 -262 257 -288 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 257 -258 291 -262 269 -268 231 -296 269 -270 237 -266 257 -288 265 -232 259 -260 293 -262 267 -268 265 -234 299 -266 267 -268 229 -264 255 -258 293 -262 269 -268 231 -264 293 -234 299 -266 267 -268 231 -264 259 -262 263 -262 257 -292 265 -264 265 -236 301 -266 269 -232 263 -264 261 -262 261 -262 295 -270 273 -270 231 -262 261 -262 257 -256 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 257 -288 265 -266 231 -264 259 -288 265 -266 265 -236 301 -266 267 -234 263 -262 257 -290 265 -266 233 -264 295 -234 299 -266 267 -268 231 -262 261 -262 257 -290 265 -234 261 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -262 257 -258 291 -262 269 -274 275 -238 259 -290 265 -264 231 -264 295 -236 299 -264 269 -234 263 -264 255 -258 291 -230 295 -264 267 -268 263 -236 299 -266 267 -266 231 -264 255 -258 293 -268 271 -272 271 -234 263 -262 261 -262 261 -264 255 -258 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 255 -292 263 -266 231 -264 263 -262 295 -270 271 -270 231 -264 259 -262 257 -258 291 -264 267 -236 259 -290 265 -266 265 -270 271 -270 231 -264 261 -260 263 -262 263 -262 295 -236 299 -264 269 -266 231 -262 -RAW_Data: 257 -258 291 -264 267 -268 233 -262 295 -234 299 -264 269 -266 231 -262 263 -262 263 -262 257 -290 265 -232 259 -292 267 -266 263 -270 273 -270 231 -262 261 -262 257 -290 265 -268 231 -264 293 -234 301 -266 267 -268 229 -264 261 -262 263 -262 263 -262 261 -264 295 -234 299 -266 269 -266 231 -262 257 -256 293 -268 273 -270 271 -234 265 -262 261 -260 257 -290 267 -266 265 -236 299 -266 267 -266 231 -264 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 267 -234 259 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 261 -264 261 -260 263 -262 259 -290 263 -266 231 -266 295 -268 273 -268 233 -262 261 -262 261 -264 261 -264 261 -262 263 -262 295 -268 273 -268 233 -262 261 -262 261 -264 263 -262 295 -268 273 -268 231 -264 261 -262 257 -290 265 -266 231 -264 263 -264 293 -268 273 -270 231 -264 261 -260 263 -262 261 -264 255 -292 265 -266 265 -236 299 -234 293 -262 267 -266 231 -264 263 -262 263 -262 261 -264 261 -296 269 -272 235 -266 263 -260 257 -288 265 -268 231 -266 255 -290 265 -266 265 -234 301 -266 269 -232 263 -264 261 -264 261 -262 263 -262 295 -234 301 -232 293 -264 267 -234 259 -292 265 -272 267 -268 267 -234 263 -264 261 -262 255 -292 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 295 -268 273 -268 233 -262 261 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -264 255 -292 263 -234 259 -292 265 -266 265 -270 271 -270 231 -264 261 -260 257 -290 265 -234 261 -260 289 -262 267 -268 265 -236 301 -264 267 -234 259 -258 291 -262 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 257 -288 265 -268 265 -236 299 -266 267 -266 231 -264 263 -262 257 -288 265 -266 231 -264 259 -288 265 -266 265 -270 273 -270 231 -264 259 -262 261 -264 261 -264 295 -234 299 -266 269 -266 231 -262 261 -262 263 -262 257 -290 265 -234 259 -292 265 -274 267 -266 269 -234 263 -262 257 -290 265 -266 265 -270 273 -268 233 -262 261 -262 261 -262 263 -262 295 -236 299 -264 269 -266 231 -264 261 -262 263 -262 257 -258 291 -262 269 -268 265 -268 273 -268 231 -264 261 -260 263 -262 295 -236 299 -266 269 -232 265 -262 261 -262 261 -264 255 -258 293 -262 269 -268 263 -236 299 -266 267 -266 231 -264 257 -288 265 -234 259 -292 265 -266 231 -264 297 -234 299 -264 269 -266 231 -262 263 -262 257 -290 265 -274 275 -270 231 -264 259 -262 -RAW_Data: 257 -256 293 -262 269 -268 231 -264 293 -268 273 -270 231 -264 261 -260 263 -262 257 -290 265 -268 231 -262 295 -236 299 -264 269 -268 229 -264 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 261 -262 263 -262 257 -290 265 -266 265 -236 301 -232 295 -262 267 -266 231 -264 261 -264 255 -258 291 -264 267 -268 265 -270 271 -234 261 -292 263 -266 263 -236 301 -266 267 -234 263 -264 261 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 263 -294 269 -272 237 -266 261 -262 261 -262 261 -264 255 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 263 -262 263 -262 261 -264 295 -268 273 -268 231 -264 261 -262 261 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -266 269 -232 259 -292 263 -266 231 -264 295 -236 299 -264 269 -266 231 -264 261 -262 261 -264 261 -262 263 -262 295 -236 299 -266 269 -234 263 -262 261 -262 261 -264 263 -262 257 -290 265 -266 231 -264 295 -268 273 -268 233 -264 259 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -232 259 -260 293 -262 267 -274 269 -266 267 -234 263 -262 261 -262 261 -264 263 -294 269 -274 235 -266 257 -290 263 -234 259 -292 265 -272 269 -266 269 -232 265 -262 261 -262 257 -290 265 -266 233 -264 261 -264 293 -268 273 -270 231 -264 261 -262 259 -262 295 -236 301 -266 267 -266 231 -264 261 -264 255 -258 291 -262 269 -268 231 -264 293 -268 273 -270 231 -264 261 -260 257 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -232 261 -258 291 -268 273 -270 273 -234 263 -262 261 -262 255 -290 267 -266 233 -264 293 -234 299 -266 269 -268 231 -264 255 -256 291 -262 267 -268 233 -264 295 -234 301 -264 267 -266 231 -264 261 -264 261 -262 261 -262 263 -262 295 -270 271 -270 231 -264 261 -262 263 -262 257 -290 263 -266 231 -266 295 -234 301 -264 269 -234 263 -262 263 -262 257 -290 263 -234 259 -292 267 -264 265 -270 273 -268 231 -264 257 -288 265 -266 265 -270 273 -268 233 -262 261 -262 257 -256 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 257 -290 265 -232 259 -292 265 -266 273 -272 237 -264 257 -256 291 -228 295 -264 269 -268 263 -236 299 -266 267 -234 265 -262 261 -262 261 -264 257 -290 265 -268 265 -270 271 -268 233 -262 261 -260 257 -258 291 -264 267 -268 231 -264 295 -234 299 -266 269 -234 263 -262 -RAW_Data: 263 -262 261 -264 261 -264 293 -270 271 -270 231 -264 261 -260 261 -264 257 -258 291 -264 267 -268 265 -236 299 -264 267 -266 231 -264 261 -264 261 -264 255 -290 265 -266 233 -264 295 -234 299 -266 267 -268 229 -264 261 -264 255 -258 291 -264 267 -240 303 -266 269 -232 263 -264 259 -262 263 -262 263 -262 257 -290 265 -266 265 -236 299 -266 269 -266 231 -262 263 -262 257 -256 291 -264 269 -266 273 -272 235 -266 263 -262 259 -262 255 -292 265 -266 267 -236 299 -264 267 -268 231 -262 263 -262 257 -258 289 -230 295 -264 267 -268 265 -236 299 -264 267 -268 229 -264 257 -290 265 -232 259 -260 293 -262 269 -266 265 -234 301 -264 269 -266 231 -262 261 -264 261 -264 295 -234 299 -266 267 -268 229 -264 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 261 -264 255 -292 265 -264 233 -264 257 -290 265 -266 265 -270 271 -270 231 -264 259 -262 257 -290 267 -266 265 -236 299 -266 267 -266 231 -262 263 -262 263 -262 257 -290 265 -266 231 -264 261 -264 295 -234 301 -264 269 -266 231 -262 261 -264 255 -258 293 -270 271 -270 271 -234 263 -262 257 -288 267 -232 261 -260 289 -262 267 -268 265 -270 273 -268 233 -262 261 -260 257 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 263 -262 257 -256 291 -264 269 -266 265 -236 299 -264 269 -266 231 -262 263 -262 263 -262 295 -234 299 -232 295 -262 267 -268 233 -262 257 -258 289 -264 267 -268 231 -264 295 -234 299 -266 269 -234 263 -262 261 -264 261 -264 255 -290 265 -266 231 -264 297 -268 271 -270 231 -264 261 -260 263 -262 257 -292 265 -264 265 -236 301 -266 267 -234 263 -264 261 -262 261 -264 261 -264 261 -262 263 -262 295 -268 273 -268 233 -262 261 -262 255 -258 291 -306 243 -274 235 -264 255 -290 263 -234 259 -292 265 -266 265 -270 273 -268 231 -264 261 -262 255 -290 265 -234 261 -292 265 -264 265 -270 273 -268 233 -262 257 -288 265 -266 265 -236 301 -266 267 -266 231 -262 263 -262 257 -256 291 -230 295 -264 269 -266 265 -234 299 -266 267 -268 231 -262 263 -262 261 -262 257 -290 265 -266 265 -236 301 -266 267 -234 263 -264 261 -262 261 -264 255 -290 265 -274 269 -266 269 -234 263 -262 257 -290 265 -232 261 -292 265 -264 265 -270 273 -270 231 -262 261 -262 255 -290 267 -266 233 -264 255 -290 265 -266 265 -236 299 -266 269 -234 263 -262 261 -264 261 -264 261 -262 263 -262 295 -268 271 -270 233 -262 -RAW_Data: 261 -262 255 -292 265 -266 233 -264 261 -262 295 -234 301 -264 269 -266 231 -264 261 -262 261 -262 257 -292 265 -264 265 -270 273 -236 261 -290 265 -264 265 -236 299 -266 269 -234 263 -262 263 -262 261 -264 261 -262 261 -262 295 -236 299 -266 269 -266 231 -262 261 -264 261 -264 261 -296 267 -274 235 -266 263 -260 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -266 231 -264 261 -260 257 -290 267 -232 259 -292 267 -272 269 -266 267 -266 231 -262 263 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -266 269 -232 259 -258 289 -230 293 -264 269 -266 265 -270 273 -268 231 -264 261 -262 261 -262 263 -262 261 -264 261 -264 293 -236 299 -266 267 -268 231 -262 263 -262 261 -264 255 -290 265 -266 231 -264 297 -234 299 -266 269 -232 265 -262 261 -264 261 -264 261 -262 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 257 -290 263 -268 231 -264 295 -268 271 -270 233 -264 261 -260 257 -290 265 -266 271 -274 237 -266 263 -260 261 -262 261 -264 261 -264 295 -268 271 -270 231 -264 261 -262 255 -290 267 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -260 295 -236 301 -266 267 -234 263 -264 261 -260 257 -290 267 -232 261 -292 265 -266 263 -236 301 -266 267 -234 263 -264 255 -258 291 -230 295 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -262 261 -262 257 -290 265 -274 269 -266 269 -232 265 -262 257 -256 293 -228 295 -264 269 -266 263 -236 299 -266 269 -234 263 -262 261 -262 261 -264 257 -292 265 -264 265 -236 301 -232 295 -262 267 -266 231 -264 261 -264 255 -290 265 -266 233 -264 295 -234 299 -266 269 -232 259 -292 265 -232 259 -260 291 -262 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -234 259 -290 265 -266 265 -268 273 -270 231 -264 255 -290 265 -232 259 -292 267 -266 263 -236 301 -266 267 -234 263 -264 259 -262 263 -262 263 -262 261 -296 269 -272 237 -266 261 -262 255 -290 265 -268 231 -264 295 -236 297 -266 269 -266 231 -262 263 -262 261 -264 261 -262 261 -264 295 -234 301 -266 267 -234 263 -264 261 -262 257 -290 265 -266 233 -264 261 -262 295 -234 299 -266 269 -266 231 -262 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 261 -264 263 -262 295 -234 299 -266 269 -266 231 -264 261 -262 257 -290 265 -266 231 -264 257 -290 265 -266 265 -236 301 -266 267 -234 -RAW_Data: 263 -262 257 -290 265 -266 265 -236 301 -264 267 -266 231 -264 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 261 -264 255 -290 265 -234 261 -292 265 -272 275 -270 231 -262 261 -262 255 -292 265 -266 265 -236 301 -264 267 -268 231 -262 261 -264 261 -262 257 -290 265 -266 231 -264 297 -234 299 -266 267 -268 231 -262 261 -262 295 -236 301 -266 267 -234 263 -262 261 -262 257 -290 265 -268 231 -264 263 -260 295 -236 299 -266 269 -234 263 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -266 267 -268 231 -262 263 -262 261 -262 261 -264 289 -266 275 -272 235 -264 261 -262 261 -262 257 -290 265 -266 265 -236 301 -266 267 -266 231 -262 263 -262 257 -256 291 -230 295 -264 269 -266 265 -236 299 -264 267 -268 231 -262 263 -262 261 -264 255 -290 265 -266 231 -266 295 -234 299 -232 295 -264 267 -234 259 -292 263 -266 265 -236 299 -266 267 -268 229 -264 257 -288 265 -234 259 -260 291 -262 269 -266 267 -268 273 -268 231 -264 261 -260 257 -290 265 -274 275 -270 233 -262 261 -262 255 -290 265 -234 261 -292 265 -264 265 -236 301 -232 295 -262 267 -266 231 -264 257 -256 291 -230 295 -296 241 -276 239 -268 257 -256 291 -262 267 -268 231 -264 295 -234 299 -266 267 -268 231 -262 261 -262 263 -262 257 -258 293 -262 267 -266 265 -270 273 -268 233 -262 261 -262 255 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 257 -290 265 -266 263 -270 273 -270 233 -262 261 -262 255 -292 265 -232 259 -292 267 -264 231 -264 295 -236 299 -264 269 -266 231 -264 261 -264 255 -290 265 -266 231 -264 263 -264 295 -268 271 -270 231 -264 261 -260 263 -262 257 -290 265 -274 275 -270 233 -262 261 -262 255 -290 267 -266 231 -262 257 -290 267 -266 263 -270 273 -268 233 -262 261 -262 255 -292 265 -234 261 -292 265 -264 271 -240 265 -260 293 -228 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 263 -262 259 -262 263 -262 263 -262 295 -236 301 -264 269 -266 231 -262 257 -290 263 -274 269 -268 267 -234 263 -262 261 -262 257 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -264 261 -262 263 -262 263 -262 295 -234 299 -266 269 -266 231 -262 263 -262 261 -264 255 -290 265 -266 267 -270 271 -270 231 -264 255 -290 265 -264 233 -264 295 -234 299 -266 269 -266 231 -262 263 -262 261 -262 257 -290 265 -266 231 -266 295 -234 299 -266 269 -266 231 -262 -RAW_Data: 263 -262 255 -290 265 -268 231 -264 261 -262 295 -236 299 -266 269 -232 259 -292 265 -264 231 -264 295 -236 299 -232 295 -264 267 -266 231 -264 261 -262 255 -292 265 -268 231 -264 293 -234 301 -264 269 -266 231 -264 261 -264 287 -266 269 -270 271 -234 263 -262 257 -256 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -264 261 -262 257 -290 267 -272 267 -268 269 -232 259 -258 291 -260 269 -268 265 -236 299 -264 269 -266 231 -262 263 -262 263 -262 257 -256 291 -264 267 -274 269 -266 269 -232 265 -262 255 -290 265 -266 233 -264 263 -262 293 -234 301 -266 269 -234 263 -262 261 -262 255 -258 293 -262 269 -268 263 -270 273 -268 233 -262 261 -262 255 -258 293 -262 269 -268 263 -236 299 -264 269 -266 231 -264 261 -262 261 -262 257 -290 267 -266 231 -264 295 -234 299 -266 269 -266 231 -264 261 -262 257 -258 289 -264 267 -268 265 -270 273 -268 231 -262 261 -262 261 -264 261 -264 257 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 261 -262 261 -264 257 -290 265 -272 269 -234 295 -228 293 -264 267 -268 263 -270 273 -268 233 -262 261 -262 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -272 269 -266 269 -234 263 -262 263 -262 261 -264 255 -290 265 -266 265 -236 301 -266 267 -234 263 -262 257 -258 291 -264 267 -268 231 -262 295 -268 273 -270 231 -264 261 -260 263 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -268 231 -262 261 -260 263 -262 297 -234 299 -266 267 -268 233 -262 255 -258 291 -230 295 -264 267 -266 265 -234 301 -266 267 -234 263 -264 261 -262 263 -262 261 -264 255 -290 265 -268 231 -264 295 -270 271 -268 233 -262 255 -290 265 -266 231 -264 297 -234 299 -266 267 -268 229 -264 261 -264 255 -290 267 -266 231 -262 263 -262 295 -236 299 -264 269 -266 231 -264 255 -258 291 -230 295 -306 243 -274 233 -264 257 -288 265 -264 231 -266 295 -236 299 -264 269 -266 231 -264 261 -262 255 -292 265 -234 259 -292 265 -266 263 -270 273 -268 233 -262 257 -290 265 -264 265 -236 301 -266 267 -234 263 -264 261 -262 255 -258 291 -230 295 -264 269 -238 303 -266 267 -266 231 -264 261 -262 261 -264 261 -262 263 -262 295 -236 301 -264 269 -234 263 -262 261 -262 263 -262 257 -290 265 -266 265 -236 299 -266 267 -266 231 -264 263 -262 257 -290 263 -266 231 -266 295 -268 273 -268 233 -262 261 -262 255 -290 -RAW_Data: 267 -266 233 -264 261 -264 293 -234 299 -268 269 -232 265 -262 261 -260 257 -292 265 -266 231 -264 263 -262 295 -268 273 -268 233 -262 261 -262 255 -290 267 -266 233 -264 295 -234 299 -266 267 -266 231 -264 261 -264 261 -262 257 -290 265 -266 231 -264 295 -236 299 -266 267 -234 259 -292 263 -266 265 -236 301 -264 269 -234 263 -262 261 -262 257 -258 291 -230 295 -264 267 -240 303 -266 267 -234 263 -262 261 -262 263 -262 295 -270 273 -268 231 -264 261 -262 255 -258 291 -264 269 -266 265 -236 299 -232 293 -264 267 -268 231 -262 257 -290 265 -232 259 -292 267 -266 263 -270 273 -268 231 -264 261 -262 257 -290 265 -266 231 -264 257 -290 265 -266 265 -236 301 -232 295 -230 291 -264 269 -266 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 261 -264 263 -262 295 -234 299 -266 269 -266 231 -264 261 -262 263 -262 257 -290 265 -264 233 -264 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 261 -264 295 -234 299 -266 269 -232 265 -262 261 -264 261 -264 261 -262 257 -290 265 -266 265 -236 301 -264 267 -266 231 -264 257 -256 291 -264 267 -268 273 -272 235 -266 261 -262 261 -262 261 -264 295 -234 299 -266 269 -266 231 -264 255 -258 291 -264 267 -234 261 -292 263 -266 263 -270 273 -270 231 -262 261 -262 261 -264 295 -268 273 -270 231 -262 261 -262 255 -258 293 -262 269 -234 261 -290 265 -266 263 -270 273 -270 231 -264 259 -262 257 -256 293 -262 269 -268 265 -234 299 -266 269 -234 263 -262 263 -262 261 -264 255 -258 291 -262 269 -274 275 -270 231 -262 261 -262 255 -290 265 -234 261 -292 265 -264 265 -270 273 -270 231 -262 257 -256 291 -264 267 -236 259 -290 265 -266 263 -236 301 -266 269 -232 265 -262 261 -262 261 -262 257 -292 265 -266 231 -264 295 -268 273 -268 231 -264 257 -288 265 -266 233 -264 263 -262 295 -234 299 -266 267 -268 231 -262 263 -262 261 -264 255 -258 291 -262 267 -268 265 -270 273 -268 233 -262 255 -290 265 -272 269 -268 267 -234 263 -264 255 -290 265 -232 259 -292 267 -266 263 -236 301 -266 267 -234 263 -264 255 -258 291 -230 295 -264 267 -266 271 -274 235 -266 263 -262 255 -256 291 -264 269 -238 303 -266 269 -234 263 -262 261 -262 261 -264 257 -290 265 -266 231 -264 295 -270 271 -268 233 -262 261 -262 257 -290 265 -268 231 -264 261 -262 295 -236 299 -266 269 -234 263 -262 261 -262 257 -258 291 -262 269 -268 265 -268 273 -268 231 -264 261 -262 255 -290 -RAW_Data: 267 -234 259 -292 265 -266 265 -234 301 -264 269 -266 231 -264 261 -260 257 -290 267 -232 261 -292 265 -266 263 -236 301 -266 267 -234 263 -264 255 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 261 -262 257 -290 265 -266 231 -264 297 -234 299 -266 267 -234 263 -264 257 -290 265 -264 233 -264 263 -294 269 -272 237 -266 257 -288 265 -264 265 -236 301 -266 267 -234 263 -264 255 -290 265 -266 231 -264 263 -262 295 -234 299 -268 269 -232 265 -262 261 -262 295 -236 299 -266 269 -232 265 -262 261 -262 257 -290 265 -234 261 -258 291 -262 267 -268 265 -270 271 -270 231 -264 259 -262 255 -258 293 -262 269 -268 265 -234 299 -266 269 -232 265 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -270 231 -264 255 -258 291 -262 269 -268 231 -264 293 -268 271 -270 233 -264 261 -260 261 -264 257 -290 265 -266 265 -236 299 -232 295 -264 267 -266 231 -264 261 -264 255 -256 291 -264 269 -266 267 -236 299 -232 293 -262 267 -234 261 -258 291 -262 267 -268 265 -234 301 -232 293 -264 267 -266 231 -264 257 -258 289 -262 269 -234 261 -292 263 -266 265 -236 299 -266 267 -234 265 -262 261 -264 261 -262 295 -234 301 -266 267 -234 263 -264 261 -262 263 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -262 257 -290 265 -266 231 -264 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 263 -262 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 257 -256 291 -264 269 -266 265 -236 299 -264 269 -266 231 -264 261 -262 261 -262 263 -262 257 -258 291 -264 267 -268 265 -234 301 -264 267 -266 231 -264 263 -262 257 -288 265 -274 269 -266 267 -268 229 -264 261 -262 263 -262 257 -290 265 -266 231 -264 297 -234 299 -266 267 -266 231 -264 261 -264 255 -290 265 -234 259 -292 265 -266 263 -236 301 -232 295 -262 267 -268 231 -262 263 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -232 293 -264 267 -268 231 -262 263 -262 261 -264 261 -262 295 -234 301 -264 269 -266 231 -264 261 -262 263 -262 263 -262 257 -290 263 -266 231 -266 295 -234 299 -266 269 -234 263 -262 263 -262 257 -256 291 -270 273 -272 269 -234 263 -262 261 -262 257 -290 265 -268 231 -264 263 -262 293 -234 301 -266 269 -232 265 -262 261 -264 255 -258 291 -262 269 -268 231 -264 295 -234 299 -266 269 -232 265 -262 261 -262 257 -258 291 -230 295 -264 267 -266 231 -264 -RAW_Data: 263 -262 293 -236 299 -266 269 -234 263 -262 261 -262 263 -262 257 -290 265 -274 269 -266 269 -234 263 -262 261 -262 255 -292 265 -266 231 -264 257 -290 265 -266 265 -236 301 -264 269 -266 231 -262 263 -262 261 -262 263 -262 295 -236 299 -264 269 -266 231 -264 261 -262 263 -262 257 -258 291 -230 295 -264 267 -266 265 -270 271 -270 231 -262 261 -262 257 -290 265 -234 259 -292 265 -266 231 -264 295 -234 299 -266 269 -266 231 -264 261 -262 261 -262 263 -262 257 -290 265 -268 265 -234 301 -264 269 -266 231 -262 261 -264 261 -264 255 -290 265 -266 265 -236 301 -266 267 -234 263 -264 255 -258 291 -230 295 -264 267 -268 229 -264 295 -234 301 -264 269 -234 263 -264 261 -262 257 -290 265 -232 261 -258 291 -304 243 -274 235 -264 261 -262 255 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -268 231 -264 259 -262 261 -264 263 -262 257 -290 265 -266 263 -236 301 -234 293 -264 267 -266 231 -262 263 -262 257 -256 291 -230 295 -264 269 -268 263 -236 299 -264 269 -234 263 -264 261 -260 257 -290 267 -232 261 -292 265 -266 271 -274 235 -266 261 -262 261 -262 255 -290 267 -266 233 -264 295 -234 299 -266 267 -266 231 -264 263 -262 261 -262 255 -290 267 -232 261 -260 291 -294 239 -278 273 -234 263 -262 259 -262 257 -290 265 -266 233 -264 295 -234 299 -232 295 -264 267 -266 231 -264 261 -264 255 -290 265 -232 261 -292 265 -266 265 -236 299 -264 269 -234 263 -264 261 -262 261 -262 257 -292 265 -266 231 -264 257 -290 265 -266 265 -236 299 -266 269 -266 229 -264 261 -264 261 -262 257 -290 265 -232 293 -266 277 -274 233 -264 261 -260 261 -264 255 -258 293 -262 269 -268 265 -234 299 -232 295 -262 267 -266 233 -262 261 -262 257 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -258 291 -264 267 -240 301 -266 269 -266 231 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 261 -262 263 -262 257 -290 265 -266 231 -266 295 -234 299 -266 267 -268 231 -262 263 -262 257 -256 291 -264 269 -266 233 -296 267 -272 235 -266 263 -262 255 -256 293 -262 269 -268 231 -262 295 -234 301 -264 269 -266 231 -264 261 -262 257 -290 265 -266 233 -264 257 -290 263 -266 265 -236 301 -266 267 -234 263 -264 259 -262 263 -262 257 -258 291 -264 267 -268 265 -268 273 -268 233 -262 261 -262 261 -262 257 -290 267 -266 265 -236 299 -266 267 -266 -RAW_Data: 231 -264 261 -262 255 -258 293 -230 293 -264 269 -268 265 -234 299 -232 295 -262 267 -268 231 -262 261 -262 257 -292 265 -266 231 -264 295 -236 299 -264 269 -234 259 -290 265 -264 231 -266 295 -236 299 -264 269 -266 231 -262 261 -264 261 -262 263 -262 295 -236 299 -264 269 -266 231 -264 261 -264 261 -262 295 -268 273 -270 231 -264 261 -260 261 -264 255 -292 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -266 233 -264 261 -264 293 -268 273 -270 231 -264 261 -260 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -262 261 -262 257 -292 265 -266 265 -236 299 -266 269 -232 265 -262 257 -288 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -262 257 -292 265 -266 231 -264 295 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -232 259 -294 265 -266 265 -234 301 -266 269 -232 263 -264 255 -290 265 -268 231 -296 269 -272 235 -266 263 -260 261 -262 261 -264 263 -262 261 -264 295 -234 301 -266 269 -232 265 -262 255 -256 293 -262 269 -268 231 -264 293 -268 273 -268 233 -264 255 -290 263 -266 265 -236 301 -266 267 -268 229 -264 261 -262 261 -264 261 -262 257 -290 267 -266 265 -270 273 -236 263 -264 259 -262 257 -258 291 -304 243 -274 235 -266 261 -260 261 -262 261 -264 257 -290 265 -266 265 -236 299 -266 269 -234 263 -262 257 -256 293 -262 269 -268 265 -268 271 -270 231 -262 255 -290 265 -268 231 -264 295 -236 299 -264 269 -266 231 -264 261 -260 263 -262 263 -262 261 -264 295 -234 301 -266 269 -232 265 -262 259 -262 257 -258 291 -264 267 -268 267 -234 301 -264 267 -268 231 -262 261 -262 257 -258 291 -270 271 -272 269 -234 263 -264 261 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -266 233 -262 255 -256 293 -262 269 -234 259 -292 265 -266 263 -236 301 -264 269 -234 263 -264 261 -262 261 -262 263 -262 261 -264 295 -268 273 -236 259 -292 265 -232 259 -292 265 -266 263 -236 301 -266 267 -234 263 -262 263 -262 263 -262 261 -262 261 -264 295 -268 273 -268 233 -262 261 -264 293 -234 301 -266 269 -234 263 -262 261 -262 257 -290 265 -268 231 -264 257 -290 265 -264 265 -270 273 -270 231 -264 261 -260 263 -262 257 -256 293 -296 241 -276 239 -268 257 -290 263 -232 259 -260 291 -262 267 -268 265 -270 273 -268 231 -262 261 -262 257 -256 293 -262 269 -268 -RAW_Data: 265 -236 299 -264 267 -268 231 -262 263 -262 261 -264 255 -290 265 -266 267 -236 299 -264 269 -266 231 -262 263 -262 261 -262 257 -290 265 -266 267 -270 271 -270 231 -264 261 -260 257 -290 265 -234 261 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -262 255 -292 265 -234 261 -290 265 -266 265 -234 301 -266 269 -232 265 -262 261 -262 261 -264 295 -234 301 -266 269 -232 263 -264 261 -262 261 -262 257 -290 267 -266 233 -262 295 -268 273 -268 233 -262 257 -290 263 -266 231 -264 263 -262 295 -236 299 -232 295 -264 267 -266 231 -262 295 -236 299 -234 295 -262 267 -266 231 -264 261 -264 255 -256 293 -262 269 -268 265 -268 273 -268 231 -264 261 -260 257 -290 265 -274 269 -268 267 -234 263 -262 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 257 -258 291 -262 269 -266 265 -270 271 -236 261 -290 263 -266 231 -264 261 -264 295 -234 301 -264 269 -234 263 -264 259 -262 263 -262 263 -262 263 -262 295 -236 299 -264 269 -266 231 -264 255 -258 291 -264 267 -268 233 -262 295 -234 299 -264 269 -266 231 -264 261 -264 255 -290 265 -274 269 -266 269 -232 265 -262 255 -258 291 -262 269 -234 261 -290 265 -266 265 -236 299 -266 267 -234 263 -264 261 -262 261 -264 255 -292 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 255 -258 291 -264 267 -268 231 -296 269 -272 235 -266 263 -260 257 -256 291 -264 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -262 263 -262 263 -262 295 -270 271 -270 231 -264 261 -260 263 -262 295 -236 299 -266 269 -232 265 -262 261 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 255 -290 265 -234 291 -268 277 -272 233 -264 261 -262 259 -262 263 -262 257 -292 265 -266 231 -264 295 -234 299 -266 269 -266 231 -264 261 -262 261 -262 257 -290 265 -274 269 -266 269 -234 263 -262 261 -262 261 -264 257 -290 265 -266 231 -264 297 -234 299 -232 295 -230 293 -230 295 -264 267 -268 263 -270 271 -270 231 -264 259 -262 257 -258 291 -230 295 -264 267 -240 303 -232 295 -262 267 -266 231 -264 263 -262 255 -290 265 -268 231 -264 261 -262 295 -236 299 -266 269 -232 265 -262 261 -262 261 -264 295 -268 273 -268 233 -262 261 -262 261 -264 257 -290 265 -232 259 -294 265 -266 263 -270 273 -268 233 -262 261 -262 261 -264 257 -290 265 -266 271 -240 265 -294 231 -298 231 -264 257 -290 265 -266 265 -236 299 -266 267 -266 -RAW_Data: 231 -264 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 293 -234 301 -266 269 -266 229 -264 255 -258 293 -230 293 -264 269 -266 265 -268 271 -270 233 -262 261 -262 255 -290 267 -266 233 -296 269 -272 235 -266 261 -262 261 -264 255 -290 267 -266 231 -264 295 -234 299 -266 269 -234 263 -262 263 -262 261 -264 261 -264 295 -234 299 -266 267 -234 263 -264 255 -290 265 -266 231 -264 259 -290 265 -266 263 -236 301 -266 269 -232 263 -264 255 -290 265 -274 269 -266 269 -234 263 -262 261 -262 261 -264 255 -258 293 -262 269 -268 231 -264 293 -268 271 -270 233 -264 261 -260 261 -264 261 -264 261 -262 263 -262 295 -236 299 -264 269 -266 231 -262 263 -262 263 -262 257 -256 293 -304 243 -274 235 -264 261 -262 255 -290 265 -266 233 -264 255 -290 265 -266 265 -268 273 -270 233 -262 261 -262 255 -258 291 -264 267 -268 265 -270 271 -236 259 -292 263 -266 231 -264 263 -262 295 -234 299 -266 269 -266 231 -264 261 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 257 -290 265 -266 231 -264 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 295 -236 299 -266 267 -268 229 -264 261 -264 261 -262 257 -290 265 -232 261 -292 265 -266 265 -234 301 -266 269 -232 263 -264 261 -262 261 -264 255 -290 267 -266 233 -264 293 -268 273 -268 233 -262 261 -262 261 -264 295 -268 273 -268 233 -262 261 -262 257 -290 265 -268 231 -264 257 -290 263 -266 265 -270 273 -270 231 -262 261 -262 257 -290 265 -266 233 -264 261 -294 269 -272 237 -266 257 -256 291 -262 267 -268 265 -236 301 -264 267 -266 231 -264 261 -264 261 -262 255 -292 265 -266 267 -234 301 -264 267 -268 231 -262 263 -262 293 -234 301 -266 269 -234 263 -262 261 -262 257 -290 267 -264 233 -264 295 -234 299 -266 269 -234 263 -262 263 -262 261 -264 255 -292 263 -274 275 -236 261 -290 265 -264 231 -266 261 -262 295 -234 301 -232 295 -262 267 -268 231 -262 257 -290 265 -234 259 -292 265 -272 269 -266 269 -232 265 -262 257 -288 265 -234 259 -292 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 257 -290 265 -274 269 -266 269 -232 265 -262 261 -264 261 -262 255 -290 267 -266 233 -264 293 -236 299 -264 269 -268 231 -262 261 -262 257 -290 265 -234 261 -290 265 -266 231 -264 295 -270 271 -268 233 -262 261 -262 261 -264 257 -290 265 -266 271 -274 235 -268 255 -258 289 -262 -RAW_Data: 267 -268 231 -264 297 -234 299 -266 267 -234 263 -262 263 -262 263 -262 257 -290 265 -266 263 -236 301 -266 269 -232 265 -262 261 -264 293 -234 301 -266 269 -232 265 -262 261 -264 261 -264 261 -262 257 -290 265 -266 265 -270 273 -268 231 -264 261 -260 261 -264 261 -264 295 -270 271 -270 231 -264 259 -262 257 -258 291 -262 269 -268 265 -234 299 -266 269 -266 229 -264 261 -264 255 -258 291 -264 269 -266 233 -262 295 -234 299 -264 269 -268 231 -262 263 -262 261 -262 255 -258 293 -262 269 -268 265 -234 301 -230 295 -264 267 -266 231 -264 261 -264 293 -234 301 -266 269 -232 263 -264 261 -262 261 -264 261 -264 255 -290 267 -266 265 -236 299 -266 269 -232 265 -262 261 -262 257 -290 265 -268 231 -264 261 -262 295 -268 273 -270 231 -264 261 -260 263 -262 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 257 -290 265 -266 231 -264 295 -268 273 -268 233 -262 261 -262 257 -290 265 -268 231 -298 269 -270 235 -266 257 -290 263 -266 231 -266 261 -264 293 -234 301 -266 267 -266 231 -264 261 -264 255 -290 265 -266 231 -264 297 -234 299 -266 269 -232 265 -262 261 -264 295 -234 299 -266 269 -234 263 -262 261 -264 261 -264 255 -258 291 -264 267 -274 269 -266 269 -232 263 -264 261 -262 255 -258 293 -296 239 -278 239 -268 263 -260 259 -262 261 -264 257 -292 265 -264 265 -236 301 -266 267 -234 263 -264 261 -262 255 -258 291 -264 269 -266 265 -270 271 -270 231 -264 261 -260 257 -290 265 -234 261 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -262 295 -236 299 -266 269 -232 265 -262 261 -262 257 -290 265 -234 261 -258 291 -262 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -266 231 -264 263 -262 295 -268 273 -268 233 -264 259 -262 257 -258 291 -262 269 -274 275 -270 231 -264 259 -262 255 -290 267 -266 233 -264 257 -290 263 -266 265 -270 273 -268 231 -264 261 -262 255 -290 265 -234 261 -292 265 -272 275 -270 233 -262 255 -290 265 -264 233 -264 295 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 267 -266 231 -264 257 -290 263 -274 267 -234 295 -264 267 -266 231 -262 263 -262 257 -290 265 -266 231 -264 295 -236 299 -266 267 -234 263 -264 255 -290 265 -266 233 -264 263 -262 293 -234 301 -264 269 -268 231 -264 255 -258 289 -262 269 -234 261 -292 265 -272 275 -236 261 -290 263 -264 233 -264 261 -264 295 -234 299 -266 269 -232 -RAW_Data: 265 -262 261 -264 261 -262 255 -260 291 -262 269 -268 231 -264 293 -234 299 -266 269 -268 231 -262 261 -262 261 -264 261 -262 263 -262 295 -270 271 -270 231 -264 261 -260 257 -290 265 -274 269 -266 269 -234 263 -262 261 -262 261 -264 257 -258 291 -260 269 -268 231 -264 295 -236 299 -264 269 -234 263 -264 261 -262 261 -262 295 -236 301 -266 267 -234 263 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 261 -262 263 -262 295 -270 271 -270 231 -264 255 -256 293 -262 269 -268 231 -262 295 -234 301 -264 269 -234 263 -264 261 -262 255 -258 291 -264 269 -274 267 -266 269 -234 263 -262 261 -262 261 -264 263 -262 257 -290 265 -266 265 -234 301 -266 269 -232 265 -262 261 -264 261 -262 295 -268 273 -270 231 -264 261 -260 257 -290 265 -234 261 -290 265 -266 231 -264 295 -270 271 -268 233 -262 261 -262 257 -290 265 -268 231 -264 257 -288 265 -266 267 -270 271 -270 231 -262 261 -262 261 -264 263 -262 261 -296 269 -272 235 -268 255 -290 263 -266 231 -264 263 -262 295 -236 299 -264 269 -234 263 -264 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 295 -236 299 -266 269 -232 265 -262 261 -262 257 -256 293 -230 295 -262 269 -268 231 -264 293 -268 273 -268 233 -262 261 -262 257 -290 265 -268 231 -264 257 -290 265 -264 265 -236 301 -266 267 -234 263 -262 263 -262 263 -262 261 -264 295 -268 271 -270 231 -264 261 -260 263 -262 257 -290 265 -234 259 -292 265 -266 265 -270 273 -268 231 -264 261 -260 257 -290 265 -268 231 -264 263 -260 295 -236 301 -264 269 -234 263 -262 261 -262 261 -264 263 -262 295 -268 273 -268 233 -264 259 -262 261 -264 261 -264 255 -290 267 -266 265 -236 301 -264 267 -266 231 -264 257 -290 263 -268 231 -264 295 -236 299 -232 293 -230 295 -262 267 -268 231 -264 295 -234 299 -266 269 -232 265 -262 261 -262 261 -264 261 -264 257 -290 265 -272 269 -266 269 -234 263 -264 255 -258 291 -270 271 -272 269 -234 263 -264 259 -262 257 -258 293 -262 269 -268 263 -236 299 -264 269 -266 231 -262 263 -262 257 -258 291 -262 269 -268 265 -268 273 -234 261 -258 289 -262 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -264 261 -264 261 -264 261 -262 295 -270 271 -270 231 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -270 231 -264 261 -262 255 -258 291 -264 269 -274 273 -238 265 -262 -RAW_Data: 261 -260 257 -258 291 -264 267 -268 231 -264 293 -234 301 -266 267 -268 229 -264 261 -262 257 -290 265 -234 259 -292 265 -266 265 -236 299 -266 267 -266 231 -264 261 -262 257 -258 291 -264 267 -268 265 -270 271 -234 261 -290 265 -264 231 -264 263 -262 295 -236 299 -264 269 -268 231 -262 263 -262 261 -262 261 -264 261 -262 295 -236 301 -266 267 -234 263 -262 261 -262 295 -236 301 -266 267 -234 263 -262 261 -262 263 -262 263 -262 257 -290 265 -266 265 -236 301 -264 269 -234 263 -262 263 -262 261 -262 257 -290 265 -274 275 -270 231 -264 261 -260 257 -258 291 -262 269 -268 231 -264 293 -268 273 -270 231 -264 255 -258 289 -262 269 -268 231 -264 295 -270 271 -270 231 -262 261 -262 261 -262 257 -292 265 -266 231 -264 295 -236 299 -264 269 -234 263 -262 263 -262 257 -290 265 -266 265 -236 301 -264 269 -234 263 -262 263 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -264 269 -266 231 -264 261 -262 257 -290 265 -234 259 -292 265 -266 265 -270 271 -270 231 -264 261 -260 263 -262 261 -264 295 -268 273 -268 233 -262 263 -262 261 -262 257 -290 265 -266 231 -264 297 -234 299 -266 267 -266 231 -264 261 -264 261 -262 257 -290 265 -272 277 -236 261 -290 263 -266 231 -264 261 -264 293 -234 301 -266 269 -234 263 -264 259 -262 257 -258 291 -230 295 -264 269 -238 303 -266 267 -234 263 -262 257 -290 265 -266 265 -270 273 -268 233 -262 261 -262 255 -290 267 -234 259 -292 265 -266 263 -270 273 -268 231 -264 255 -290 265 -266 231 -264 259 -290 265 -266 265 -268 273 -270 231 -262 261 -262 261 -264 257 -258 291 -262 269 -268 265 -268 273 -268 231 -264 261 -260 257 -290 265 -268 231 -264 263 -262 293 -234 301 -266 269 -232 265 -262 261 -264 261 -264 255 -290 265 -266 231 -264 297 -234 299 -232 295 -264 267 -266 231 -264 255 -258 291 -264 267 -268 265 -236 299 -230 295 -264 267 -234 259 -290 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -290 265 -268 263 -236 301 -264 267 -266 231 -264 257 -258 291 -268 273 -270 271 -234 263 -262 261 -262 263 -262 257 -290 265 -266 231 -266 295 -234 299 -266 269 -266 231 -262 257 -258 291 -262 269 -268 231 -296 267 -238 265 -294 265 -266 231 -264 259 -262 295 -270 273 -268 233 -262 261 -262 257 -290 265 -234 259 -292 265 -272 269 -266 269 -234 263 -262 261 -262 263 -262 257 -290 265 -266 231 -264 263 -262 295 -236 299 -264 269 -266 -RAW_Data: 231 -264 261 -262 261 -264 261 -262 295 -236 301 -266 267 -234 263 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -236 299 -266 269 -266 231 -262 261 -262 263 -262 263 -262 257 -290 265 -266 265 -270 273 -268 231 -264 261 -262 261 -262 257 -258 291 -270 273 -270 271 -234 263 -262 261 -262 261 -264 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -290 265 -274 267 -268 267 -234 263 -264 255 -290 265 -266 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -258 291 -264 267 -240 303 -266 267 -234 263 -264 261 -260 295 -236 301 -266 267 -234 263 -264 261 -262 261 -262 257 -290 267 -266 231 -264 295 -268 273 -268 233 -262 257 -256 291 -264 267 -268 231 -264 295 -268 271 -236 261 -290 265 -264 231 -264 263 -262 295 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -266 231 -264 295 -236 301 -266 267 -234 263 -262 257 -256 291 -230 295 -264 269 -266 265 -268 273 -268 233 -262 261 -262 261 -262 257 -290 267 -266 265 -268 273 -268 233 -262 261 -262 263 -262 257 -290 265 -266 231 -264 295 -270 271 -270 231 -264 261 -260 257 -290 267 -266 231 -264 257 -290 265 -266 263 -236 301 -266 269 -232 265 -262 257 -290 263 -234 259 -292 265 -274 275 -270 231 -264 255 -256 291 -262 269 -268 265 -236 299 -264 269 -266 231 -262 261 -262 257 -290 265 -234 261 -292 265 -238 301 -268 267 -234 263 -262 261 -262 295 -236 301 -266 267 -234 263 -262 263 -262 257 -290 263 -268 231 -264 257 -290 265 -272 269 -266 269 -234 263 -262 257 -290 265 -266 231 -296 271 -272 235 -266 263 -260 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 261 -262 295 -236 299 -234 295 -262 267 -266 231 -264 261 -264 255 -290 265 -266 267 -236 299 -232 293 -262 267 -268 231 -264 261 -264 261 -262 263 -262 263 -262 293 -236 299 -266 269 -234 263 -262 261 -262 257 -290 267 -232 259 -292 265 -266 265 -236 299 -232 295 -262 267 -268 231 -264 261 -264 255 -290 265 -266 233 -264 295 -236 299 -264 267 -266 231 -264 261 -264 255 -292 265 -272 267 -234 295 -264 265 -266 233 -264 261 -264 255 -290 265 -266 231 -264 297 -234 299 -266 267 -266 231 -264 255 -290 265 -268 231 -296 269 -272 235 -266 263 -260 263 -262 257 -290 265 -266 231 -264 295 -236 299 -266 267 -234 263 -264 255 -292 265 -264 233 -264 263 -262 293 -268 273 -270 231 -264 261 -262 261 -262 -RAW_Data: 295 -236 301 -232 295 -262 267 -266 231 -264 261 -262 257 -290 265 -266 233 -264 295 -268 273 -268 231 -264 261 -262 255 -290 267 -266 233 -264 261 -262 293 -270 273 -268 233 -262 261 -262 255 -258 293 -262 269 -274 275 -270 231 -262 261 -262 261 -264 255 -258 291 -264 269 -238 303 -266 267 -234 263 -264 261 -262 255 -290 267 -266 233 -264 261 -262 293 -236 301 -266 267 -234 263 -264 259 -262 257 -292 265 -232 261 -292 265 -264 265 -236 301 -264 269 -232 259 -292 265 -266 231 -262 297 -234 299 -266 267 -268 231 -262 261 -264 255 -290 267 -232 259 -292 267 -272 267 -268 267 -234 263 -264 255 -290 265 -272 269 -268 267 -234 263 -264 261 -260 263 -262 263 -262 257 -290 265 -266 231 -264 297 -268 273 -268 231 -264 255 -290 265 -232 259 -292 267 -266 271 -274 235 -266 257 -256 289 -264 267 -268 265 -236 301 -264 267 -234 263 -264 261 -262 257 -290 265 -266 231 -264 295 -270 271 -270 231 -262 261 -262 257 -290 265 -274 275 -270 233 -262 261 -262 261 -262 263 -262 257 -290 265 -266 231 -264 295 -236 299 -266 267 -234 263 -264 261 -264 259 -262 263 -262 263 -262 263 -262 295 -270 271 -270 231 -264 261 -260 257 -290 265 -234 261 -258 291 -262 267 -268 265 -270 273 -268 231 -264 261 -262 261 -262 261 -264 261 -264 261 -262 295 -236 299 -266 267 -266 231 -264 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -234 263 -262 261 -264 261 -262 255 -292 265 -234 259 -292 273 -276 237 -266 263 -262 255 -290 265 -266 233 -264 295 -234 299 -266 267 -266 231 -264 263 -262 261 -262 261 -262 263 -262 295 -270 273 -268 231 -264 261 -262 261 -262 295 -236 299 -266 269 -234 263 -262 263 -262 257 -290 263 -266 231 -266 261 -264 293 -268 273 -270 231 -264 261 -262 261 -264 261 -262 263 -262 295 -236 299 -232 295 -262 267 -268 231 -262 257 -290 265 -234 259 -260 289 -304 243 -274 235 -264 261 -262 261 -262 257 -290 265 -268 265 -234 301 -264 267 -266 231 -264 263 -262 257 -256 291 -264 267 -268 233 -262 295 -234 299 -234 293 -264 267 -266 233 -262 261 -262 261 -264 257 -290 265 -266 265 -270 273 -268 231 -264 257 -288 265 -266 265 -236 301 -264 269 -234 263 -262 263 -262 261 -264 261 -262 261 -262 295 -236 301 -266 267 -234 263 -262 263 -262 261 -262 295 -270 273 -268 233 -262 261 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -264 261 -262 261 -262 263 -262 -RAW_Data: 263 -262 295 -268 273 -268 233 -262 257 -288 265 -268 265 -236 299 -266 267 -266 231 -264 255 -258 291 -230 295 -264 269 -266 263 -270 271 -270 231 -264 261 -260 257 -290 265 -274 275 -270 233 -262 261 -262 261 -262 257 -290 265 -268 231 -264 261 -262 295 -236 299 -266 269 -232 265 -262 257 -256 291 -230 295 -262 269 -274 269 -266 267 -234 263 -264 261 -262 255 -290 267 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -260 295 -236 301 -232 295 -262 267 -266 233 -262 257 -256 291 -264 269 -234 259 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 261 -262 257 -258 291 -262 269 -240 303 -266 267 -234 263 -264 255 -288 267 -266 265 -236 301 -264 267 -266 231 -264 257 -290 265 -264 233 -264 257 -290 265 -266 263 -270 273 -270 233 -262 261 -260 263 -262 261 -264 257 -322 239 -278 237 -268 257 -290 263 -232 259 -292 265 -266 265 -236 299 -266 269 -234 263 -262 261 -262 261 -264 263 -262 261 -264 295 -268 273 -268 233 -262 261 -262 261 -264 295 -234 299 -266 269 -266 231 -264 261 -262 255 -290 267 -266 233 -264 293 -268 273 -268 233 -264 261 -262 261 -262 263 -262 261 -296 269 -272 235 -268 255 -258 289 -262 269 -268 231 -264 293 -236 299 -266 269 -266 231 -262 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 261 -262 263 -262 257 -290 265 -266 231 -266 295 -234 299 -266 269 -234 263 -262 263 -262 295 -234 299 -266 269 -234 263 -262 263 -262 257 -290 263 -234 261 -292 265 -238 301 -268 267 -234 265 -262 259 -262 263 -262 257 -292 265 -266 231 -264 295 -234 299 -266 269 -266 231 -262 263 -262 257 -290 265 -266 231 -296 271 -272 235 -266 263 -260 257 -288 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 257 -290 263 -234 261 -292 265 -266 263 -270 273 -268 231 -264 255 -290 265 -272 269 -268 269 -232 265 -262 261 -262 261 -264 255 -290 267 -266 233 -264 293 -268 273 -270 231 -264 261 -260 257 -258 291 -296 241 -276 239 -268 263 -262 259 -262 257 -290 265 -266 233 -264 295 -234 299 -232 295 -262 269 -266 231 -264 255 -290 265 -266 231 -264 297 -268 273 -268 231 -264 261 -262 261 -262 295 -270 273 -268 231 -264 261 -262 261 -262 257 -292 265 -266 231 -262 297 -268 273 -268 233 -262 261 -262 261 -262 263 -262 263 -262 295 -236 299 -264 269 -268 229 -264 261 -262 257 -290 265 -234 261 -290 265 -238 303 -266 269 -234 -RAW_Data: 263 -262 257 -256 291 -264 269 -266 265 -236 299 -266 267 -266 231 -264 261 -262 261 -264 261 -264 261 -262 295 -236 299 -264 269 -266 231 -264 257 -256 291 -262 269 -268 265 -270 271 -236 265 -262 261 -262 261 -262 263 -262 263 -262 295 -270 271 -270 231 -262 261 -262 257 -290 265 -268 233 -264 255 -290 263 -274 269 -266 269 -234 263 -262 261 -262 263 -262 261 -296 269 -272 235 -268 263 -262 255 -288 265 -234 259 -294 265 -266 263 -236 299 -266 267 -268 229 -264 255 -292 265 -232 259 -292 267 -264 265 -270 273 -268 233 -262 257 -288 265 -274 267 -268 267 -234 263 -264 261 -262 261 -264 255 -292 265 -264 233 -264 295 -268 273 -268 233 -262 261 -262 257 -258 291 -296 241 -276 239 -268 263 -262 255 -256 291 -264 267 -268 265 -236 299 -264 267 -266 231 -264 261 -262 261 -264 261 -264 261 -264 295 -268 271 -270 233 -264 259 -262 261 -262 295 -268 273 -270 233 -262 261 -262 255 -258 293 -262 269 -234 259 -292 265 -264 265 -270 273 -268 231 -264 261 -262 261 -262 263 -262 263 -262 295 -236 299 -264 269 -266 231 -262 263 -262 263 -262 261 -264 255 -290 265 -274 269 -266 269 -234 263 -262 261 -262 257 -258 291 -262 269 -268 231 -264 293 -234 301 -266 269 -232 265 -262 257 -290 263 -266 231 -266 257 -290 263 -266 265 -236 301 -266 267 -266 231 -264 261 -262 257 -258 291 -264 267 -240 303 -266 267 -234 259 -290 265 -264 233 -264 295 -234 299 -266 269 -232 265 -262 261 -264 255 -292 265 -232 259 -292 265 -272 269 -266 269 -234 263 -264 261 -262 295 -234 301 -264 269 -266 231 -264 261 -262 255 -292 265 -232 259 -260 293 -262 267 -268 265 -268 273 -268 231 -264 261 -262 261 -262 257 -290 265 -268 271 -274 235 -266 257 -290 263 -232 259 -292 265 -274 267 -268 269 -232 265 -262 261 -262 257 -256 293 -262 269 -268 265 -268 273 -268 231 -264 261 -262 255 -290 265 -274 269 -266 269 -234 263 -262 261 -262 261 -264 263 -262 257 -290 265 -266 263 -270 273 -270 233 -262 261 -262 255 -290 265 -234 261 -292 265 -238 301 -268 267 -234 263 -262 263 -262 261 -264 255 -258 291 -264 267 -268 265 -270 271 -268 233 -262 261 -262 261 -264 295 -234 301 -264 269 -234 263 -262 257 -258 291 -262 269 -234 261 -290 263 -266 265 -236 301 -266 267 -234 263 -262 263 -262 257 -256 291 -264 267 -268 231 -264 293 -268 273 -270 233 -262 261 -262 255 -290 267 -266 265 -236 301 -264 267 -266 231 -264 261 -264 -RAW_Data: 255 -258 291 -264 267 -268 233 -262 295 -268 271 -270 231 -264 255 -290 265 -232 259 -326 239 -276 237 -268 257 -258 289 -262 267 -268 231 -264 263 -262 293 -236 299 -266 269 -266 231 -262 261 -262 263 -262 263 -262 261 -264 295 -268 273 -268 231 -264 255 -290 265 -268 265 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -266 233 -264 293 -268 273 -270 231 -264 259 -262 261 -264 261 -296 269 -272 237 -266 261 -262 255 -290 265 -234 261 -258 291 -262 267 -268 265 -236 299 -266 267 -266 231 -264 255 -290 265 -266 233 -264 295 -236 299 -264 269 -266 231 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -232 295 -264 267 -268 231 -262 257 -290 265 -272 269 -268 267 -234 263 -264 259 -262 257 -290 267 -232 261 -258 291 -262 267 -274 269 -266 269 -266 229 -264 261 -264 261 -262 257 -290 265 -234 261 -290 265 -238 303 -266 269 -232 265 -262 261 -264 261 -262 295 -236 299 -264 269 -234 263 -264 261 -262 257 -290 265 -234 259 -258 293 -262 267 -268 265 -270 271 -270 231 -262 261 -262 261 -264 257 -290 265 -266 271 -274 237 -266 261 -262 255 -290 265 -266 233 -264 293 -236 299 -264 269 -266 231 -264 261 -264 255 -258 291 -262 267 -268 265 -236 301 -264 267 -266 231 -264 261 -264 295 -234 299 -266 269 -232 265 -262 261 -264 255 -258 291 -262 269 -234 261 -292 263 -272 275 -272 231 -262 261 -262 255 -258 291 -230 295 -264 269 -266 263 -236 299 -266 269 -234 263 -262 257 -256 291 -264 267 -236 291 -266 275 -274 233 -264 261 -262 255 -290 265 -266 233 -264 295 -236 299 -264 267 -266 231 -264 263 -262 257 -288 265 -234 261 -292 265 -264 265 -236 301 -232 295 -262 267 -266 231 -264 255 -258 293 -230 293 -264 267 -268 265 -268 273 -268 231 -264 261 -262 259 -264 295 -234 301 -266 269 -232 265 -262 261 -264 255 -292 265 -232 259 -292 265 -266 265 -270 271 -270 231 -264 261 -262 255 -258 291 -306 243 -274 235 -264 261 -262 259 -262 261 -264 257 -290 265 -266 265 -236 301 -266 267 -234 263 -264 259 -262 263 -262 257 -290 265 -266 265 -270 273 -236 261 -290 265 -264 231 -264 295 -236 299 -264 269 -234 263 -262 263 -262 257 -290 265 -232 259 -294 265 -264 265 -236 301 -266 267 -234 263 -262 263 -262 261 -264 261 -264 261 -262 293 -236 301 -266 267 -234 263 -264 261 -262 263 -262 263 -262 295 -234 299 -266 267 -268 231 -262 263 -262 261 -264 255 -290 265 -266 233 -264 263 -262 -RAW_Data: 293 -268 273 -270 231 -264 261 -260 257 -290 265 -268 231 -264 257 -290 265 -272 269 -266 269 -234 263 -262 257 -290 263 -268 231 -264 295 -270 271 -270 231 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -264 269 -268 231 -264 261 -262 261 -262 263 -262 261 -264 295 -268 273 -268 233 -262 261 -262 261 -262 263 -262 295 -236 301 -266 267 -234 263 -262 261 -262 257 -290 265 -268 231 -264 295 -268 273 -268 233 -262 261 -262 261 -264 295 -234 299 -266 269 -266 231 -264 255 -290 265 -232 259 -292 267 -266 263 -236 301 -266 267 -234 263 -264 255 -258 291 -262 267 -268 267 -236 299 -264 267 -234 259 -292 265 -264 231 -264 295 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -266 231 -264 297 -234 299 -266 269 -232 265 -262 257 -256 291 -230 295 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 287 -266 269 -272 271 -234 263 -264 255 -290 265 -266 233 -264 255 -290 265 -266 267 -234 301 -264 267 -268 231 -262 261 -262 257 -290 265 -268 231 -264 263 -262 293 -234 301 -266 267 -266 231 -264 257 -256 291 -264 269 -266 233 -262 295 -268 271 -270 231 -264 261 -262 255 -290 265 -268 265 -236 299 -266 267 -266 231 -264 263 -262 255 -290 265 -266 233 -264 295 -268 273 -268 233 -262 261 -262 295 -234 301 -266 267 -234 263 -264 261 -262 261 -264 255 -290 265 -234 261 -292 265 -264 265 -270 273 -268 231 -264 261 -260 257 -290 265 -268 231 -298 269 -272 235 -266 261 -262 261 -262 255 -292 265 -272 271 -266 269 -232 265 -262 261 -262 261 -264 257 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -262 261 -264 263 -262 261 -264 295 -234 299 -232 295 -264 267 -266 231 -264 257 -290 263 -234 259 -292 265 -240 301 -268 267 -234 263 -264 261 -262 255 -290 267 -266 233 -264 255 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 261 -262 257 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 261 -264 295 -234 299 -266 267 -234 263 -264 257 -290 265 -232 259 -260 291 -262 269 -266 265 -270 273 -268 231 -262 261 -262 261 -264 263 -262 261 -264 261 -296 269 -238 265 -260 293 -260 267 -268 231 -264 295 -234 299 -264 269 -268 231 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -260 295 -236 301 -266 267 -234 263 -264 261 -262 255 -290 267 -266 233 -264 293 -234 299 -266 269 -268 231 -262 257 -288 265 -234 259 -292 -RAW_Data: 265 -272 269 -266 269 -234 263 -264 259 -262 257 -290 267 -266 231 -264 261 -264 293 -234 301 -266 269 -234 263 -264 255 -256 293 -230 293 -264 269 -266 233 -262 295 -234 299 -264 269 -268 231 -264 255 -290 265 -266 231 -264 257 -290 265 -266 265 -236 299 -266 269 -232 265 -262 257 -290 263 -268 231 -264 263 -262 295 -268 271 -236 261 -290 265 -232 259 -292 265 -274 267 -268 267 -234 263 -264 261 -260 257 -258 291 -230 295 -264 269 -266 265 -270 271 -268 233 -262 261 -262 255 -292 265 -272 277 -270 231 -264 259 -262 257 -290 265 -234 259 -260 291 -260 269 -268 263 -270 273 -268 233 -262 261 -262 255 -258 291 -230 295 -264 269 -272 275 -238 259 -292 263 -232 259 -292 265 -272 269 -266 269 -232 265 -262 261 -262 261 -264 255 -292 265 -266 265 -236 299 -266 267 -234 263 -264 261 -264 287 -266 275 -274 233 -266 259 -262 261 -262 261 -264 257 -258 291 -262 269 -268 263 -236 301 -264 267 -266 231 -264 263 -262 257 -288 265 -266 231 -264 297 -268 271 -270 231 -264 261 -262 261 -264 255 -292 265 -264 233 -264 261 -264 295 -268 271 -236 261 -292 263 -232 259 -292 265 -272 269 -266 269 -234 263 -262 261 -262 263 -262 263 -262 263 -262 261 -264 295 -234 299 -266 269 -266 231 -262 261 -262 257 -290 265 -268 231 -264 263 -260 295 -270 271 -270 231 -264 261 -262 261 -262 295 -236 301 -266 267 -234 263 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -270 231 -264 261 -262 261 -262 257 -290 265 -266 265 -270 273 -268 233 -262 261 -262 261 -264 257 -290 265 -266 231 -264 297 -234 299 -264 269 -266 231 -264 261 -264 261 -262 261 -264 295 -234 299 -266 269 -266 231 -262 257 -290 265 -266 263 -236 301 -266 269 -232 265 -262 261 -264 255 -290 265 -234 261 -292 265 -238 301 -268 267 -234 263 -262 261 -262 263 -262 263 -262 261 -264 295 -234 301 -264 269 -266 231 -264 259 -262 257 -290 267 -272 269 -268 267 -234 263 -264 255 -258 289 -262 269 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -290 265 -268 231 -264 295 -234 299 -264 269 -268 231 -264 259 -262 261 -264 263 -262 261 -264 295 -268 273 -236 259 -258 291 -260 269 -234 261 -290 265 -266 265 -234 301 -266 269 -232 265 -262 261 -262 257 -256 293 -262 269 -268 265 -234 299 -266 267 -268 229 -264 261 -262 295 -236 299 -234 295 -262 267 -266 233 -262 261 -262 255 -292 265 -234 259 -292 -RAW_Data: 265 -272 269 -266 269 -234 263 -262 257 -256 291 -230 295 -306 243 -274 235 -264 259 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -264 269 -268 229 -264 257 -256 293 -228 295 -264 269 -266 263 -270 273 -268 231 -264 261 -262 261 -262 257 -292 265 -266 231 -264 295 -236 299 -264 269 -234 263 -262 263 -262 261 -262 295 -236 299 -266 269 -234 263 -262 263 -262 261 -262 257 -258 291 -264 267 -268 265 -268 273 -268 233 -262 261 -262 261 -262 257 -290 267 -266 233 -262 295 -234 299 -266 267 -268 233 -262 261 -262 255 -290 267 -272 269 -266 269 -234 263 -262 257 -256 291 -264 269 -234 259 -292 263 -266 265 -236 301 -266 267 -234 263 -262 257 -256 291 -264 269 -266 265 -270 271 -270 231 -264 255 -256 291 -262 269 -266 267 -236 299 -264 269 -266 231 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 255 -290 265 -274 269 -266 269 -234 263 -262 255 -290 265 -266 233 -264 263 -262 293 -234 301 -266 269 -232 263 -264 261 -264 261 -260 257 -290 267 -272 277 -236 265 -262 257 -256 291 -262 269 -266 233 -264 295 -234 299 -264 269 -266 231 -264 261 -264 255 -258 291 -262 269 -274 269 -232 295 -262 267 -266 233 -262 261 -262 257 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -270 231 -264 261 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -266 231 -262 261 -264 255 -292 265 -264 233 -264 295 -270 271 -268 233 -262 261 -262 261 -264 293 -270 273 -270 231 -262 261 -262 261 -264 255 -292 265 -232 259 -292 267 -264 265 -236 299 -266 269 -234 263 -262 263 -262 261 -264 257 -288 265 -274 275 -270 233 -262 255 -256 291 -264 269 -272 269 -266 269 -234 263 -262 261 -262 261 -264 257 -290 265 -266 265 -236 299 -266 269 -234 263 -262 257 -256 291 -270 273 -272 269 -234 263 -264 259 -262 257 -290 265 -234 261 -258 291 -262 267 -268 265 -270 273 -268 231 -264 257 -256 289 -262 269 -268 231 -264 295 -268 273 -268 233 -262 261 -262 255 -292 265 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 261 -264 295 -234 301 -264 269 -234 263 -262 261 -262 263 -262 257 -290 267 -266 231 -264 295 -234 299 -266 269 -234 263 -262 257 -290 265 -232 261 -292 265 -266 231 -264 295 -268 273 -268 231 -264 255 -258 291 -264 267 -240 303 -266 269 -232 263 -264 259 -262 -RAW_Data: 263 -262 257 -258 291 -262 269 -268 265 -268 273 -268 231 -264 261 -262 255 -290 267 -266 233 -296 269 -272 235 -266 257 -256 291 -262 269 -266 233 -262 295 -234 299 -268 267 -234 263 -264 261 -262 257 -290 265 -232 261 -292 265 -266 263 -236 301 -264 269 -266 231 -262 257 -290 265 -266 265 -236 299 -266 269 -266 231 -262 261 -262 257 -258 291 -230 295 -264 269 -238 303 -264 269 -234 263 -262 263 -262 261 -264 255 -292 265 -264 233 -264 295 -268 273 -268 231 -264 261 -262 255 -292 265 -266 267 -268 273 -236 265 -262 259 -262 263 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 257 -290 265 -234 259 -292 265 -266 265 -234 301 -264 269 -266 231 -264 261 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 257 -256 291 -262 269 -268 265 -236 299 -264 269 -266 231 -262 261 -264 261 -264 255 -290 265 -266 265 -236 301 -266 267 -234 263 -264 259 -262 295 -236 301 -266 267 -234 263 -264 261 -262 261 -262 257 -258 291 -264 269 -266 265 -236 299 -264 269 -266 231 -264 261 -264 255 -256 293 -296 239 -278 239 -268 257 -290 263 -266 229 -264 263 -262 295 -236 299 -264 269 -266 231 -264 255 -290 265 -234 261 -290 265 -274 267 -266 269 -232 265 -262 257 -290 263 -274 269 -234 295 -262 267 -268 231 -264 261 -260 257 -258 291 -264 267 -268 231 -264 293 -268 273 -270 231 -264 255 -290 265 -266 231 -264 263 -262 293 -236 299 -266 269 -266 231 -264 261 -262 255 -290 267 -266 233 -264 293 -268 273 -268 233 -264 261 -262 255 -290 265 -268 231 -264 295 -234 299 -266 267 -268 231 -262 263 -262 257 -256 291 -264 269 -266 265 -236 299 -264 269 -266 231 -264 255 -258 291 -262 267 -236 259 -292 265 -272 267 -268 267 -234 263 -264 255 -290 265 -266 267 -236 299 -264 269 -266 231 -262 263 -262 257 -256 291 -262 269 -234 261 -290 265 -274 275 -270 231 -264 259 -262 261 -264 261 -262 295 -268 273 -270 231 -264 255 -290 265 -232 259 -260 293 -262 269 -268 263 -236 299 -264 269 -266 231 -264 259 -262 263 -262 257 -290 265 -274 269 -266 269 -234 257 -290 265 -266 231 -264 295 -270 271 -268 233 -262 261 -262 261 -264 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 257 -288 267 -266 265 -270 273 -268 231 -264 259 -262 263 -262 257 -258 291 -264 267 -268 233 -262 295 -234 299 -264 269 -268 231 -262 255 -258 291 -230 295 -264 267 -268 265 -236 299 -264 267 -268 -RAW_Data: 229 -264 255 -258 291 -264 269 -234 259 -292 263 -266 265 -236 299 -266 269 -232 265 -262 261 -262 257 -258 291 -262 269 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -232 265 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -266 231 -262 263 -262 295 -234 301 -266 267 -234 263 -264 261 -262 257 -258 291 -262 269 -234 261 -290 265 -270 269 -266 269 -234 263 -264 255 -258 291 -262 269 -274 275 -236 265 -262 261 -262 261 -264 261 -264 261 -262 295 -236 299 -264 269 -266 231 -264 255 -258 291 -230 295 -264 267 -268 263 -270 273 -268 231 -264 255 -290 265 -266 265 -236 301 -264 267 -266 231 -264 263 -262 257 -288 265 -234 261 -292 265 -264 265 -270 273 -268 231 -264 261 -260 257 -258 291 -264 267 -268 265 -236 301 -264 267 -234 263 -262 263 -262 257 -290 265 -232 293 -266 277 -272 235 -264 261 -262 255 -290 265 -266 233 -264 261 -262 293 -236 301 -266 267 -234 263 -264 259 -262 257 -258 291 -264 267 -268 233 -262 295 -268 271 -270 233 -262 261 -262 255 -292 265 -266 233 -264 293 -236 299 -264 269 -266 231 -264 261 -264 261 -262 261 -264 295 -234 299 -266 269 -266 231 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 257 -258 291 -270 271 -272 269 -234 263 -264 261 -262 261 -262 257 -258 293 -262 269 -268 263 -236 299 -264 269 -266 231 -262 257 -290 265 -234 259 -292 265 -266 265 -270 271 -270 231 -262 261 -262 261 -264 257 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 261 -264 261 -262 261 -262 297 -268 273 -268 233 -262 261 -262 261 -264 257 -290 265 -264 233 -264 295 -236 299 -264 269 -234 263 -264 261 -260 263 -262 297 -234 301 -264 269 -234 263 -262 263 -262 257 -288 265 -268 231 -264 263 -262 293 -236 299 -266 269 -234 263 -264 261 -260 263 -262 257 -258 291 -264 267 -268 265 -270 271 -268 233 -262 261 -262 261 -264 261 -262 295 -270 273 -268 231 -264 261 -262 255 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -262 257 -290 265 -268 231 -264 297 -268 271 -268 233 -262 261 -262 261 -264 261 -264 295 -234 299 -266 269 -266 229 -264 261 -264 255 -258 291 -230 295 -264 269 -238 303 -266 267 -234 263 -262 263 -262 263 -262 293 -236 299 -266 269 -234 263 -262 263 -262 261 -264 255 -258 291 -264 267 -268 265 -270 271 -268 233 -262 259 -262 -RAW_Data: 257 -258 291 -264 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -262 257 -292 265 -266 265 -270 271 -270 231 -264 255 -256 293 -262 269 -268 231 -262 295 -234 299 -266 267 -268 233 -262 261 -262 261 -262 263 -262 261 -264 261 -264 295 -234 301 -264 269 -266 231 -262 263 -262 257 -256 293 -262 269 -268 263 -236 299 -264 269 -232 259 -292 265 -266 231 -262 297 -234 301 -264 269 -234 263 -262 263 -262 257 -290 265 -232 259 -292 265 -266 265 -236 299 -266 269 -266 231 -262 263 -262 261 -262 295 -270 271 -270 233 -262 261 -262 261 -262 263 -262 257 -290 265 -266 231 -264 297 -268 273 -268 231 -264 255 -290 265 -232 259 -292 267 -266 271 -240 265 -292 265 -266 231 -262 261 -262 263 -262 297 -234 299 -266 269 -266 231 -262 261 -262 263 -262 263 -262 261 -264 295 -268 273 -268 231 -264 261 -262 255 -258 293 -262 269 -268 231 -264 293 -234 301 -266 267 -234 263 -264 261 -264 259 -262 295 -270 273 -270 231 -264 259 -262 261 -264 255 -290 267 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 255 -258 291 -264 269 -266 265 -236 299 -266 267 -266 231 -264 261 -262 261 -264 257 -256 293 -296 239 -278 239 -268 261 -262 255 -258 289 -230 295 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 257 -290 265 -268 265 -270 273 -268 231 -262 261 -262 261 -264 295 -234 299 -266 269 -266 231 -262 263 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 259 -262 295 -270 273 -270 231 -264 259 -262 257 -256 293 -262 269 -268 265 -234 301 -264 267 -268 231 -262 257 -256 293 -262 269 -268 231 -262 295 -268 271 -270 231 -264 261 -262 261 -264 295 -234 301 -264 269 -266 231 -262 261 -264 255 -258 293 -230 293 -264 269 -266 263 -270 273 -268 231 -264 261 -262 255 -290 267 -266 233 -264 261 -262 295 -268 271 -270 233 -264 261 -260 257 -290 265 -268 265 -270 271 -270 231 -262 261 -260 257 -290 267 -266 233 -264 261 -262 295 -234 301 -266 269 -232 263 -264 261 -262 261 -262 263 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -232 265 -262 257 -290 265 -266 231 -264 295 -236 299 -232 295 -262 267 -234 261 -290 265 -266 263 -236 301 -266 267 -234 263 -264 261 -260 257 -258 291 -230 295 -264 269 -266 265 -270 271 -236 265 -262 261 -262 255 -292 265 -272 269 -268 267 -234 263 -264 255 -290 265 -266 233 -264 257 -290 263 -266 -RAW_Data: 265 -270 273 -268 231 -264 255 -258 289 -230 295 -264 269 -268 271 -240 263 -262 291 -260 267 -234 261 -290 265 -266 265 -234 301 -264 269 -234 263 -264 261 -262 263 -262 261 -262 261 -264 295 -270 271 -270 231 -264 261 -260 257 -258 291 -264 267 -268 231 -264 293 -234 301 -266 269 -234 263 -262 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -264 261 -264 261 -260 257 -290 265 -268 231 -264 263 -262 293 -268 273 -270 231 -264 261 -262 255 -292 265 -266 231 -264 295 -236 299 -232 295 -262 269 -266 231 -262 263 -262 257 -256 291 -270 271 -272 271 -236 263 -262 261 -260 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -264 259 -262 257 -258 293 -262 269 -268 265 -268 273 -268 231 -264 255 -290 263 -268 265 -236 299 -264 269 -266 231 -264 261 -264 255 -290 265 -266 233 -264 261 -262 293 -268 273 -270 233 -264 261 -260 263 -262 295 -268 273 -268 233 -262 261 -262 257 -290 265 -266 233 -264 263 -262 293 -268 273 -270 231 -264 261 -262 261 -262 263 -262 261 -264 295 -268 273 -268 233 -262 257 -256 291 -262 269 -268 265 -236 299 -264 269 -232 265 -262 261 -264 255 -258 293 -262 269 -268 263 -236 299 -264 269 -266 231 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -264 261 -264 261 -262 295 -268 273 -268 231 -264 261 -262 261 -264 261 -264 255 -290 267 -266 231 -262 297 -234 301 -266 267 -234 263 -264 261 -262 255 -290 267 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -262 261 -262 261 -264 257 -292 263 -274 275 -270 233 -262 255 -256 291 -264 267 -268 231 -264 295 -234 299 -266 269 -234 263 -262 257 -256 291 -230 295 -264 269 -238 303 -268 267 -234 263 -262 255 -290 265 -268 265 -236 299 -264 269 -266 231 -264 261 -264 261 -260 257 -290 265 -268 231 -264 295 -236 299 -232 293 -264 267 -266 231 -264 257 -258 289 -264 267 -234 261 -292 265 -266 263 -236 299 -266 269 -232 265 -262 261 -264 261 -262 261 -264 295 -236 299 -264 269 -266 231 -264 261 -262 255 -292 265 -266 233 -264 261 -262 295 -234 301 -266 269 -232 263 -264 261 -262 261 -264 261 -264 255 -290 265 -266 267 -236 299 -266 267 -234 263 -262 263 -262 257 -258 291 -296 241 -276 239 -268 263 -260 255 -288 265 -234 261 -292 265 -266 263 -236 301 -266 267 -234 263 -264 255 -258 291 -230 295 -262 269 -268 265 -268 273 -268 231 -264 255 -290 265 -264 265 -236 301 -266 -RAW_Data: 269 -232 263 -264 261 -264 261 -262 257 -288 267 -266 233 -264 293 -268 273 -268 233 -262 261 -262 257 -256 293 -304 243 -274 235 -264 261 -262 261 -262 257 -290 265 -266 265 -236 299 -232 295 -262 267 -268 231 -264 263 -262 261 -262 261 -264 295 -268 273 -268 233 -262 261 -262 261 -264 261 -264 295 -234 299 -266 267 -268 231 -262 261 -264 255 -292 263 -266 231 -266 295 -268 273 -268 233 -262 261 -262 261 -264 261 -264 261 -262 263 -262 295 -270 271 -270 231 -264 261 -260 261 -264 257 -290 265 -274 267 -268 267 -234 263 -264 261 -262 255 -258 291 -264 269 -266 265 -236 299 -232 295 -262 269 -266 231 -264 255 -290 265 -266 231 -264 257 -290 265 -266 265 -236 301 -264 267 -268 229 -264 263 -262 261 -262 257 -290 265 -274 269 -266 269 -232 259 -290 265 -266 231 -264 295 -236 299 -264 269 -234 263 -262 263 -262 257 -290 265 -232 261 -292 265 -238 303 -266 269 -234 263 -262 261 -262 295 -236 301 -264 269 -234 263 -262 261 -262 257 -290 265 -234 261 -258 291 -262 267 -268 265 -270 273 -268 231 -264 259 -262 261 -264 257 -290 265 -266 271 -274 237 -266 261 -262 255 -290 265 -266 265 -236 299 -266 269 -266 229 -264 261 -264 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -232 265 -262 261 -262 257 -256 293 -262 269 -268 231 -264 293 -234 301 -232 295 -262 267 -268 231 -264 255 -290 265 -274 267 -268 269 -232 265 -262 261 -262 255 -290 267 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 263 -262 257 -290 265 -232 259 -292 267 -272 267 -268 267 -234 263 -264 261 -262 255 -292 265 -274 267 -268 267 -234 263 -264 261 -262 261 -262 257 -290 265 -266 233 -264 295 -268 273 -268 231 -264 255 -258 291 -262 269 -268 231 -264 293 -234 299 -232 295 -264 269 -266 231 -264 295 -234 299 -266 267 -266 231 -264 261 -262 257 -290 265 -266 231 -264 263 -262 295 -270 271 -270 231 -264 261 -260 257 -290 265 -274 275 -270 233 -262 261 -262 255 -290 265 -234 261 -292 265 -264 265 -270 273 -268 231 -264 261 -260 257 -258 291 -264 267 -268 265 -270 271 -270 231 -262 255 -258 291 -262 269 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 255 -292 265 -266 233 -264 293 -236 299 -264 269 -266 231 -262 263 -262 263 -262 295 -234 299 -266 269 -266 231 -264 255 -258 291 -264 267 -234 261 -290 265 -264 -RAW_Data: 265 -236 301 -266 267 -234 263 -264 261 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 263 -262 257 -290 265 -266 231 -298 269 -272 235 -266 261 -262 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -288 267 -266 265 -236 301 -264 267 -266 231 -264 261 -262 261 -264 295 -236 299 -266 267 -234 263 -262 263 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -268 233 -264 259 -262 257 -258 291 -296 241 -276 239 -268 263 -262 259 -262 255 -292 265 -266 233 -264 261 -262 295 -234 301 -266 267 -234 263 -264 255 -290 265 -232 261 -292 265 -266 265 -236 299 -266 267 -266 231 -264 261 -264 255 -290 265 -266 233 -264 261 -264 293 -234 301 -266 269 -234 257 -258 291 -262 269 -266 265 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 261 -264 255 -258 293 -262 269 -238 303 -266 267 -266 231 -262 263 -262 257 -290 265 -266 265 -236 301 -264 269 -234 263 -262 263 -262 261 -264 255 -290 265 -266 265 -270 273 -270 231 -262 257 -288 265 -232 261 -292 265 -266 271 -240 265 -294 265 -232 259 -258 291 -260 269 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -264 257 -290 265 -266 263 -236 301 -266 269 -232 265 -262 261 -264 295 -234 299 -266 267 -234 265 -262 261 -264 255 -290 265 -266 233 -264 295 -268 273 -268 233 -262 261 -262 255 -290 265 -268 231 -298 269 -272 235 -266 257 -256 291 -228 295 -264 269 -266 233 -262 295 -268 271 -270 231 -264 261 -262 261 -264 255 -258 291 -264 269 -266 265 -236 299 -264 269 -266 231 -262 261 -262 263 -262 263 -262 257 -290 265 -266 265 -236 301 -266 267 -234 263 -264 261 -260 257 -290 267 -232 261 -292 265 -238 303 -232 295 -262 267 -266 231 -264 263 -262 261 -262 257 -290 265 -266 265 -236 301 -266 267 -234 263 -264 261 -262 255 -290 267 -266 233 -264 293 -268 273 -268 233 -264 259 -262 295 -236 299 -266 267 -236 263 -262 261 -262 257 -258 291 -262 269 -234 261 -292 263 -266 265 -268 273 -268 233 -262 261 -262 257 -290 265 -268 231 -298 269 -272 235 -264 263 -262 259 -262 257 -292 265 -272 269 -266 269 -234 263 -262 261 -262 263 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 295 -234 299 -266 269 -234 263 -264 261 -262 257 -290 265 -232 261 -292 265 -266 263 -236 301 -264 269 -234 263 -264 -RAW_Data: 261 -262 257 -288 267 -266 265 -236 301 -264 267 -266 231 -264 263 -262 261 -262 261 -264 255 -292 265 -266 265 -270 271 -236 261 -258 289 -230 293 -264 267 -268 265 -236 299 -266 267 -266 231 -262 263 -262 257 -290 265 -266 231 -264 263 -262 295 -234 299 -266 269 -266 231 -262 263 -262 257 -258 291 -230 295 -264 267 -266 265 -234 301 -264 269 -234 259 -290 265 -264 233 -264 295 -236 299 -264 269 -266 231 -262 261 -262 257 -258 291 -230 295 -264 269 -266 265 -270 271 -268 231 -264 261 -262 255 -290 267 -272 275 -272 231 -264 259 -262 261 -264 255 -290 267 -266 233 -262 261 -262 295 -236 301 -266 267 -234 263 -262 257 -258 289 -230 295 -264 267 -274 277 -236 261 -288 263 -266 231 -264 263 -262 295 -234 301 -264 269 -266 231 -264 261 -262 255 -292 265 -266 233 -264 293 -236 299 -264 269 -266 231 -264 257 -256 291 -230 295 -264 267 -266 265 -236 299 -266 267 -266 231 -264 261 -264 255 -290 265 -274 269 -266 269 -234 263 -262 261 -262 261 -264 255 -292 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 257 -256 293 -262 269 -268 263 -236 299 -264 269 -266 231 -262 257 -258 291 -230 295 -264 267 -268 271 -274 235 -264 263 -260 257 -256 291 -264 267 -268 265 -236 299 -264 269 -266 231 -264 261 -264 261 -260 263 -262 263 -262 295 -270 271 -270 231 -264 261 -262 261 -262 295 -236 299 -266 267 -266 231 -264 261 -264 261 -262 255 -260 291 -262 269 -268 265 -268 271 -270 231 -264 261 -260 261 -264 263 -294 269 -272 237 -266 261 -262 261 -262 255 -260 291 -262 269 -240 303 -266 267 -234 263 -264 261 -262 255 -258 291 -264 269 -266 265 -236 299 -266 267 -266 231 -264 261 -264 293 -234 301 -232 295 -262 267 -268 231 -264 261 -262 257 -258 289 -262 269 -268 231 -264 295 -234 299 -266 269 -266 231 -262 257 -290 265 -266 231 -264 263 -262 295 -236 299 -264 269 -234 263 -264 261 -262 257 -290 265 -232 261 -292 265 -266 265 -234 301 -264 269 -234 263 -262 257 -258 291 -264 267 -268 233 -262 293 -234 299 -266 269 -268 231 -262 261 -262 255 -258 291 -264 269 -266 233 -264 293 -234 299 -266 269 -266 233 -262 261 -262 257 -290 265 -266 267 -236 299 -264 269 -266 231 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 295 -234 299 -268 269 -232 265 -262 261 -262 -RAW_Data: 255 -258 293 -230 295 -262 269 -240 301 -266 269 -234 263 -262 255 -258 291 -262 269 -268 231 -264 295 -234 299 -264 269 -268 231 -264 261 -262 261 -262 295 -236 299 -266 269 -234 263 -262 255 -290 265 -266 233 -264 257 -290 265 -264 265 -236 301 -266 269 -232 263 -264 261 -262 261 -264 257 -290 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 255 -290 265 -266 231 -264 263 -262 295 -270 271 -270 231 -264 255 -258 289 -264 267 -268 265 -236 301 -264 267 -234 263 -262 263 -262 257 -258 291 -264 267 -268 263 -270 273 -268 231 -264 261 -262 261 -262 295 -236 301 -264 269 -234 263 -262 261 -262 257 -258 291 -262 269 -268 231 -264 293 -268 273 -270 231 -264 261 -262 255 -258 291 -230 295 -298 239 -276 239 -268 263 -262 255 -288 265 -266 231 -264 297 -268 271 -270 231 -264 261 -262 261 -264 261 -264 261 -260 295 -236 301 -266 267 -234 263 -264 255 -290 265 -274 267 -268 267 -234 265 -262 261 -262 255 -258 293 -262 269 -234 261 -290 265 -272 267 -268 269 -232 265 -262 261 -262 261 -264 261 -262 263 -262 295 -236 299 -266 267 -266 231 -264 257 -288 265 -268 231 -264 257 -290 265 -272 275 -270 233 -262 255 -258 289 -264 269 -266 265 -236 299 -266 267 -266 231 -264 261 -264 255 -290 265 -232 261 -292 265 -266 263 -270 273 -270 231 -264 261 -262 255 -290 267 -232 259 -292 265 -266 231 -264 297 -268 271 -270 231 -264 261 -260 257 -290 265 -274 269 -266 269 -232 263 -264 261 -262 257 -290 265 -234 259 -292 265 -266 265 -236 299 -266 267 -266 231 -262 263 -262 261 -264 295 -234 301 -264 269 -234 263 -264 261 -260 263 -262 257 -292 265 -266 231 -262 297 -234 301 -266 269 -232 263 -264 261 -262 261 -262 257 -290 267 -272 275 -238 265 -262 261 -260 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 257 -258 291 -230 295 -264 267 -238 303 -266 269 -234 263 -262 261 -262 261 -264 257 -258 291 -262 269 -240 303 -232 295 -262 267 -266 231 -264 261 -264 261 -262 295 -268 273 -270 231 -264 261 -260 261 -264 255 -292 265 -266 233 -264 261 -262 295 -268 273 -270 231 -264 261 -260 257 -290 265 -234 259 -258 293 -262 267 -268 265 -270 273 -268 231 -262 261 -262 261 -264 257 -290 265 -266 271 -274 237 -266 257 -256 289 -262 267 -268 233 -264 295 -234 299 -266 267 -266 231 -264 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 267 -266 231 -264 261 -262 295 -236 299 -266 -RAW_Data: 269 -232 265 -262 261 -262 257 -290 265 -234 259 -292 265 -266 265 -236 301 -266 267 -234 263 -262 255 -258 291 -230 295 -304 243 -276 235 -264 255 -288 265 -232 259 -292 265 -266 265 -236 301 -266 267 -234 263 -262 263 -262 261 -264 261 -262 295 -234 301 -266 269 -232 263 -264 261 -262 261 -264 295 -236 299 -264 269 -234 263 -264 261 -262 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 263 -262 261 -264 295 -234 299 -266 269 -232 265 -262 261 -264 261 -262 257 -290 265 -272 277 -270 231 -264 259 -262 255 -292 265 -266 233 -264 295 -234 299 -264 269 -268 231 -262 261 -262 257 -258 291 -230 295 -264 267 -266 265 -236 301 -264 269 -234 263 -262 261 -262 257 -290 265 -234 261 -292 263 -266 265 -270 271 -270 231 -264 255 -290 265 -264 233 -264 295 -236 299 -264 269 -266 231 -262 263 -262 263 -262 257 -290 265 -266 263 -270 273 -270 231 -264 261 -260 263 -262 295 -270 271 -270 231 -264 259 -262 257 -258 291 -264 267 -236 259 -292 263 -266 265 -236 299 -266 267 -234 263 -264 261 -264 261 -262 257 -290 265 -272 275 -272 231 -262 257 -256 291 -264 267 -240 303 -266 267 -234 263 -264 261 -262 261 -262 257 -292 265 -264 265 -236 301 -266 267 -234 263 -264 255 -258 291 -270 273 -270 271 -234 263 -262 261 -262 257 -290 265 -234 259 -292 265 -266 231 -264 295 -268 273 -268 233 -262 257 -256 291 -262 269 -266 233 -264 295 -268 273 -268 231 -264 261 -262 255 -290 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -262 261 -264 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 263 -262 257 -290 263 -266 265 -236 301 -266 267 -266 231 -264 261 -262 257 -290 265 -266 233 -264 261 -262 295 -268 273 -270 231 -264 261 -260 261 -264 295 -234 301 -266 269 -232 265 -262 261 -262 261 -264 255 -290 267 -266 233 -264 293 -268 273 -270 231 -264 261 -260 257 -290 265 -268 231 -298 269 -270 235 -266 257 -258 289 -262 269 -268 231 -264 295 -234 299 -264 269 -268 231 -262 261 -262 261 -264 263 -262 261 -264 295 -234 299 -266 269 -232 265 -262 261 -264 295 -234 299 -266 269 -266 231 -262 261 -264 261 -264 261 -262 257 -290 265 -272 269 -266 269 -234 263 -264 261 -262 255 -258 291 -298 241 -278 237 -268 261 -262 255 -290 265 -232 259 -292 267 -266 263 -236 301 -266 267 -234 263 -264 255 -258 291 -228 295 -264 269 -266 265 -236 299 -266 267 -266 -RAW_Data: 231 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 257 -290 263 -266 265 -270 273 -270 231 -264 259 -262 257 -290 265 -234 259 -260 291 -260 269 -266 267 -236 299 -266 267 -266 231 -264 261 -264 259 -262 257 -258 291 -264 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 289 -264 269 -270 271 -234 263 -264 259 -262 257 -258 291 -264 269 -268 231 -262 295 -234 299 -266 267 -268 231 -264 257 -288 265 -232 259 -294 265 -272 275 -270 233 -262 255 -256 291 -262 269 -266 267 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -232 259 -292 267 -272 269 -266 269 -232 265 -262 255 -290 265 -274 269 -232 295 -264 267 -266 231 -264 261 -264 255 -290 265 -266 231 -264 297 -234 299 -266 267 -266 231 -264 255 -290 265 -268 231 -264 261 -262 295 -234 301 -266 269 -232 265 -262 261 -264 255 -290 265 -266 231 -264 297 -268 273 -268 231 -264 261 -262 261 -262 263 -262 263 -262 295 -234 299 -266 269 -266 231 -264 261 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 255 -290 265 -234 259 -292 265 -266 265 -236 299 -266 269 -234 263 -262 255 -290 265 -268 265 -270 273 -236 263 -262 261 -262 257 -290 265 -268 231 -264 257 -290 263 -274 275 -270 233 -262 261 -262 261 -262 261 -264 293 -270 271 -270 233 -264 255 -290 263 -234 259 -258 293 -264 267 -268 265 -236 299 -264 267 -266 231 -264 261 -262 261 -264 257 -290 265 -272 269 -266 269 -234 257 -258 291 -262 269 -268 265 -268 273 -268 231 -264 261 -262 261 -262 257 -290 267 -266 263 -236 301 -266 269 -232 263 -264 255 -258 291 -262 269 -274 275 -236 265 -262 257 -288 265 -266 231 -264 263 -264 293 -236 299 -266 267 -234 263 -264 261 -264 255 -258 291 -264 267 -268 265 -268 273 -268 233 -262 261 -262 255 -258 291 -264 269 -234 259 -292 263 -274 267 -266 269 -266 231 -262 257 -258 291 -262 269 -268 265 -234 299 -266 267 -266 231 -264 261 -264 261 -262 257 -256 291 -264 267 -274 269 -266 269 -232 265 -262 261 -264 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -266 231 -264 261 -264 255 -290 265 -274 269 -266 269 -234 263 -262 261 -262 255 -292 265 -268 231 -264 261 -264 293 -234 299 -266 269 -266 233 -262 257 -290 263 -234 259 -292 265 -272 275 -272 231 -264 259 -262 255 -290 267 -266 265 -236 301 -264 267 -266 231 -264 261 -264 261 -262 261 -262 263 -262 -RAW_Data: 295 -236 299 -266 269 -234 263 -262 257 -290 265 -264 265 -270 273 -270 231 -264 257 -288 265 -232 259 -294 265 -264 265 -236 301 -266 267 -234 263 -262 263 -262 257 -290 265 -266 231 -298 269 -272 235 -266 257 -256 291 -262 267 -268 231 -264 295 -234 301 -264 269 -234 263 -262 263 -262 257 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 261 -262 261 -264 257 -290 265 -266 265 -234 301 -266 269 -232 265 -262 261 -264 261 -262 295 -268 273 -268 233 -264 261 -262 255 -290 265 -234 261 -290 265 -266 231 -264 295 -268 273 -268 233 -262 261 -262 257 -258 291 -262 269 -234 261 -290 265 -266 263 -270 273 -270 231 -264 259 -262 255 -292 265 -266 233 -296 269 -272 235 -268 261 -262 259 -262 263 -262 263 -262 263 -262 295 -234 299 -266 269 -266 231 -264 255 -258 291 -262 267 -268 267 -234 301 -264 267 -268 231 -262 261 -262 295 -236 299 -266 269 -234 263 -262 261 -262 257 -290 265 -268 231 -264 257 -290 265 -272 269 -266 269 -234 263 -262 257 -256 291 -264 269 -272 277 -236 265 -262 261 -262 255 -290 265 -234 261 -258 291 -262 267 -274 269 -266 269 -232 265 -262 257 -256 291 -230 295 -264 269 -266 265 -268 273 -268 233 -262 261 -262 261 -264 261 -262 257 -290 265 -268 265 -236 299 -232 293 -232 293 -264 267 -234 259 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 255 -258 291 -264 267 -268 233 -262 295 -234 299 -232 295 -264 267 -266 231 -264 261 -262 257 -256 291 -264 269 -266 265 -236 299 -266 267 -266 231 -264 255 -290 265 -266 265 -270 273 -270 231 -262 261 -262 261 -264 261 -264 255 -292 265 -266 265 -236 299 -266 269 -232 265 -262 261 -262 257 -258 291 -296 241 -276 239 -268 263 -262 255 -256 289 -264 269 -268 263 -236 301 -230 295 -264 267 -266 231 -264 261 -262 263 -262 257 -290 265 -264 265 -270 273 -270 231 -264 255 -290 265 -266 265 -270 273 -268 231 -264 261 -262 255 -290 267 -232 261 -292 265 -272 269 -266 269 -232 263 -264 255 -290 265 -268 231 -298 267 -272 235 -266 257 -256 291 -228 295 -264 269 -268 231 -264 293 -234 299 -266 269 -266 233 -262 257 -288 265 -266 231 -264 263 -262 295 -270 271 -270 231 -264 261 -260 263 -262 257 -290 265 -268 231 -264 295 -266 273 -268 233 -264 261 -262 261 -262 263 -262 295 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -268 231 -264 261 -262 295 -234 301 -266 269 -232 265 -262 261 -264 261 -262 -RAW_Data: 255 -258 291 -264 269 -266 265 -270 271 -270 231 -264 261 -260 261 -264 261 -264 295 -268 273 -268 231 -264 261 -262 261 -264 261 -262 257 -290 267 -266 263 -236 301 -266 269 -232 265 -262 261 -262 261 -264 261 -262 295 -236 301 -232 295 -228 293 -264 267 -268 231 -264 293 -236 299 -264 269 -268 231 -264 261 -260 263 -262 257 -256 293 -262 269 -240 303 -266 267 -234 263 -262 261 -262 261 -264 295 -236 299 -264 269 -268 231 -264 261 -260 257 -258 291 -264 267 -268 231 -264 293 -268 273 -270 231 -264 257 -256 289 -230 295 -264 267 -268 265 -268 273 -268 233 -262 261 -262 255 -292 265 -234 259 -292 265 -266 263 -270 273 -270 231 -264 259 -262 261 -264 255 -292 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -234 259 -292 265 -266 265 -268 273 -270 231 -264 261 -260 257 -290 265 -234 261 -292 265 -264 265 -236 301 -264 269 -234 257 -290 265 -266 231 -264 295 -236 299 -266 267 -266 231 -264 261 -262 257 -290 265 -234 259 -292 265 -272 269 -266 269 -232 265 -262 257 -256 291 -230 295 -306 243 -274 233 -264 257 -256 289 -262 269 -234 261 -290 265 -266 265 -236 299 -266 269 -234 263 -262 257 -256 291 -230 295 -264 267 -268 265 -270 271 -236 259 -290 265 -264 233 -264 295 -268 273 -268 231 -264 261 -262 261 -264 255 -290 267 -266 263 -236 301 -266 269 -232 265 -262 261 -262 261 -264 295 -268 273 -268 231 -264 261 -262 257 -290 265 -234 259 -292 265 -266 231 -264 295 -268 273 -268 233 -262 261 -262 261 -264 261 -264 261 -262 295 -270 271 -270 231 -264 261 -260 257 -290 265 -234 261 -292 265 -264 231 -264 295 -236 299 -232 295 -230 293 -264 267 -268 263 -236 299 -266 267 -266 231 -264 261 -262 263 -262 263 -262 257 -290 265 -264 265 -236 301 -266 269 -232 263 -264 261 -264 255 -258 291 -230 295 -264 267 -266 265 -270 271 -270 231 -264 259 -262 261 -264 263 -262 295 -270 271 -270 231 -262 261 -262 261 -264 255 -292 265 -266 233 -264 293 -236 299 -264 269 -266 231 -264 261 -264 261 -262 255 -290 267 -272 275 -238 261 -290 263 -266 231 -264 261 -264 293 -234 301 -266 267 -266 231 -264 261 -264 255 -258 291 -230 295 -264 269 -238 303 -266 267 -234 263 -262 263 -262 261 -262 295 -236 299 -266 269 -232 265 -262 261 -264 261 -264 255 -290 265 -266 231 -264 297 -268 271 -270 231 -264 255 -258 291 -230 295 -262 269 -266 265 -234 301 -264 269 -234 263 -262 -RAW_Data: 263 -262 257 -256 293 -262 269 -268 265 -268 273 -268 231 -264 261 -260 257 -290 265 -234 259 -292 265 -266 265 -234 301 -266 269 -232 263 -264 261 -264 261 -262 257 -258 291 -262 269 -268 265 -234 299 -232 295 -262 269 -266 231 -262 257 -290 265 -266 233 -264 295 -234 299 -232 295 -262 269 -232 259 -292 265 -266 265 -236 299 -266 269 -232 265 -262 261 -262 261 -264 255 -292 265 -266 265 -236 299 -266 269 -234 263 -262 257 -256 291 -270 273 -270 271 -234 263 -262 261 -262 263 -262 257 -290 265 -266 231 -264 295 -236 299 -266 267 -268 231 -262 257 -258 291 -262 269 -268 231 -296 267 -238 263 -294 267 -232 259 -292 263 -266 265 -270 273 -268 231 -264 261 -262 255 -290 267 -266 233 -264 261 -262 295 -268 271 -270 233 -262 261 -262 295 -234 301 -266 269 -232 263 -264 261 -264 261 -262 257 -290 265 -266 231 -264 263 -262 295 -268 271 -270 233 -264 261 -260 261 -262 257 -292 265 -266 265 -236 299 -266 267 -266 231 -264 263 -262 255 -290 265 -234 261 -292 265 -264 265 -270 271 -236 261 -258 291 -260 269 -266 265 -236 299 -266 267 -266 231 -264 263 -262 261 -262 257 -290 265 -266 233 -264 261 -262 295 -234 301 -266 269 -232 263 -264 261 -264 255 -256 293 -262 269 -268 265 -234 299 -266 267 -266 231 -262 257 -290 267 -266 263 -270 273 -268 233 -262 261 -262 257 -290 265 -268 231 -264 257 -290 265 -272 267 -268 269 -232 265 -262 261 -262 257 -258 291 -296 241 -276 239 -268 263 -262 259 -262 255 -292 265 -266 267 -236 299 -232 293 -262 267 -268 233 -262 261 -262 257 -256 293 -262 269 -268 265 -234 301 -264 267 -234 259 -292 265 -264 265 -236 301 -232 295 -262 267 -266 231 -264 257 -290 263 -234 259 -292 265 -266 265 -270 273 -268 231 -264 261 -262 255 -258 291 -264 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 255 -292 265 -234 261 -290 265 -272 275 -270 233 -262 261 -262 261 -262 257 -290 265 -268 231 -264 295 -268 271 -270 231 -264 261 -262 261 -262 257 -290 265 -268 231 -264 295 -236 299 -264 267 -266 231 -264 263 -262 257 -290 265 -232 259 -292 265 -266 265 -270 271 -236 261 -292 263 -266 231 -264 261 -264 295 -234 299 -232 295 -264 267 -266 231 -264 255 -290 265 -234 259 -292 265 -272 269 -266 269 -234 263 -262 263 -262 295 -234 299 -266 269 -234 263 -262 263 -262 257 -290 263 -266 231 -266 257 -290 263 -266 265 -270 273 -270 231 -264 255 -290 265 -266 231 -296 -RAW_Data: 271 -272 235 -266 263 -260 257 -256 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -264 261 -262 263 -262 295 -268 273 -268 233 -262 261 -262 263 -262 295 -236 299 -266 269 -232 265 -262 261 -260 263 -262 263 -262 257 -290 267 -266 265 -270 271 -270 231 -264 261 -260 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 261 -262 263 -262 257 -258 291 -264 267 -274 275 -236 265 -262 255 -290 265 -232 261 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 257 -258 291 -262 269 -268 265 -234 301 -264 267 -266 231 -264 263 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -264 269 -234 259 -258 291 -262 267 -268 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 257 -290 265 -266 265 -236 299 -266 269 -232 263 -264 255 -258 293 -262 269 -272 275 -270 233 -262 261 -262 255 -290 265 -266 233 -264 263 -262 293 -234 301 -266 269 -232 263 -264 261 -264 261 -262 257 -258 291 -264 267 -268 263 -270 273 -268 231 -264 255 -256 293 -262 269 -268 265 -234 299 -264 269 -266 231 -264 261 -264 255 -258 291 -262 269 -268 265 -234 299 -266 267 -268 229 -264 261 -262 257 -290 265 -268 231 -264 295 -234 299 -264 269 -268 231 -262 261 -262 261 -264 295 -270 271 -270 231 -264 255 -258 291 -262 269 -268 231 -264 261 -260 295 -270 273 -268 231 -264 261 -262 255 -290 267 -266 233 -264 255 -290 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 255 -258 291 -262 269 -268 271 -274 235 -266 261 -262 261 -262 261 -264 257 -290 265 -264 265 -236 301 -266 269 -232 263 -264 261 -262 255 -258 293 -262 269 -268 265 -268 273 -268 233 -262 261 -260 263 -262 295 -236 299 -266 267 -268 231 -262 263 -262 261 -264 255 -290 265 -266 265 -236 301 -264 269 -234 263 -262 263 -262 261 -264 287 -266 275 -274 235 -264 261 -260 261 -262 257 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -262 263 -262 263 -262 295 -270 271 -270 231 -264 261 -260 263 -262 295 -236 299 -234 293 -262 267 -268 231 -264 261 -262 255 -292 265 -266 233 -264 293 -268 273 -270 231 -264 261 -260 263 -262 263 -262 261 -264 261 -262 295 -268 273 -270 233 -262 261 -262 261 -262 257 -290 265 -274 267 -268 269 -234 263 -262 261 -262 255 -258 291 -264 269 -266 267 -236 299 -264 269 -232 263 -264 261 -264 261 -262 261 -262 257 -290 265 -268 231 -264 297 -234 299 -264 269 -266 231 -264 -RAW_Data: 261 -262 261 -262 261 -264 295 -236 301 -232 295 -228 293 -230 295 -264 267 -268 263 -236 301 -264 269 -234 263 -262 261 -262 257 -290 265 -234 261 -290 265 -238 303 -266 269 -232 265 -262 261 -264 293 -234 301 -266 269 -234 263 -264 259 -262 257 -290 267 -232 261 -292 265 -266 229 -264 295 -270 271 -270 231 -264 255 -290 265 -232 259 -292 267 -264 273 -274 235 -266 257 -256 289 -262 269 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -266 231 -264 295 -270 271 -270 231 -262 261 -262 257 -290 265 -274 275 -270 233 -262 261 -260 263 -262 261 -264 255 -292 265 -266 231 -264 295 -236 299 -264 269 -266 231 -264 261 -262 261 -264 261 -264 261 -262 295 -236 299 -266 267 -234 263 -264 255 -258 293 -262 269 -234 259 -292 263 -266 265 -270 271 -270 231 -264 259 -262 261 -264 263 -262 261 -264 261 -264 293 -270 271 -270 231 -264 259 -262 263 -262 257 -290 265 -234 261 -292 263 -266 265 -236 299 -266 269 -234 263 -262 257 -256 291 -230 295 -264 267 -268 265 -234 299 -266 267 -266 231 -264 263 -262 293 -236 299 -266 269 -266 231 -262 263 -262 257 -288 265 -268 231 -264 263 -260 295 -270 273 -268 231 -264 261 -262 255 -290 267 -272 275 -272 231 -262 261 -262 255 -292 265 -232 259 -292 267 -264 265 -270 273 -270 231 -262 261 -262 261 -262 257 -290 265 -268 265 -270 273 -268 231 -264 255 -258 289 -262 269 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -262 257 -292 265 -266 265 -236 299 -266 269 -234 263 -262 261 -262 261 -264 261 -264 261 -262 295 -236 299 -266 269 -232 265 -262 261 -264 261 -262 295 -234 301 -266 269 -232 263 -264 255 -258 293 -262 269 -234 259 -292 263 -266 265 -236 299 -266 267 -266 231 -264 261 -264 255 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -268 231 -264 261 -260 261 -264 261 -264 295 -268 271 -270 231 -264 255 -290 265 -266 231 -264 263 -262 295 -234 301 -264 269 -234 263 -264 261 -262 257 -258 291 -262 269 -240 303 -266 267 -234 263 -262 261 -262 295 -236 301 -232 295 -262 267 -268 231 -262 261 -262 257 -290 265 -268 231 -264 263 -262 293 -268 273 -270 231 -264 261 -260 257 -258 291 -296 241 -278 239 -266 263 -262 255 -290 265 -264 233 -264 295 -236 299 -264 269 -234 263 -262 263 -262 261 -262 261 -264 263 -262 295 -270 271 -270 231 -264 259 -262 261 -264 295 -234 301 -266 269 -232 265 -262 261 -262 255 -292 265 -266 -RAW_Data: 233 -264 261 -262 295 -234 301 -266 267 -234 263 -264 261 -264 255 -290 265 -232 259 -292 267 -272 269 -266 269 -232 265 -262 257 -288 265 -234 261 -292 265 -272 275 -270 231 -264 261 -260 261 -264 255 -292 265 -266 265 -236 301 -264 269 -234 263 -262 261 -262 257 -258 291 -230 295 -264 267 -268 263 -236 299 -232 295 -262 267 -268 231 -264 261 -262 261 -264 255 -290 267 -266 265 -270 273 -236 263 -264 255 -290 265 -266 265 -236 301 -264 267 -266 231 -264 261 -264 261 -262 261 -262 263 -262 295 -236 299 -266 267 -268 229 -264 261 -264 261 -262 295 -270 273 -268 231 -264 261 -260 263 -262 257 -290 265 -268 231 -264 295 -234 299 -266 267 -268 231 -262 263 -262 261 -262 261 -264 261 -264 295 -268 273 -268 231 -264 255 -290 265 -268 265 -236 299 -264 269 -266 231 -262 257 -258 291 -230 295 -264 267 -266 265 -268 273 -268 233 -262 261 -262 257 -290 265 -274 275 -270 231 -264 261 -260 261 -264 255 -292 265 -266 233 -264 261 -264 293 -234 301 -266 267 -266 231 -264 255 -258 291 -230 295 -262 269 -240 303 -266 267 -234 263 -262 261 -262 257 -290 265 -234 261 -292 263 -266 265 -236 301 -264 269 -234 263 -262 261 -262 295 -236 301 -232 295 -262 267 -266 231 -264 257 -256 291 -264 269 -234 259 -290 265 -266 265 -234 301 -266 269 -232 265 -262 261 -262 261 -264 255 -258 291 -264 269 -238 303 -268 267 -234 263 -262 255 -290 265 -268 265 -236 299 -264 269 -266 231 -264 257 -288 265 -266 231 -264 259 -288 265 -266 265 -270 273 -270 231 -264 255 -256 291 -228 297 -264 267 -268 271 -274 235 -266 261 -262 255 -290 265 -266 233 -264 295 -234 299 -264 269 -268 231 -262 261 -262 261 -264 261 -264 261 -264 295 -268 273 -268 231 -264 261 -262 261 -262 295 -236 299 -266 269 -266 231 -262 257 -290 265 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 255 -290 267 -266 233 -264 257 -288 265 -266 265 -236 299 -266 269 -232 265 -262 261 -264 255 -258 291 -270 273 -270 271 -234 263 -262 261 -262 261 -264 257 -290 265 -266 265 -270 273 -268 231 -264 261 -262 261 -262 257 -290 267 -266 231 -264 295 -234 299 -266 269 -234 263 -262 263 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -232 265 -262 257 -290 265 -266 265 -234 301 -266 269 -232 265 -262 261 -262 261 -264 261 -264 261 -264 261 -262 295 -270 271 -270 231 -264 261 -262 293 -236 301 -266 267 -234 263 -262 -RAW_Data: 261 -262 257 -290 265 -268 231 -264 257 -290 265 -266 263 -270 273 -270 231 -264 261 -262 261 -262 263 -262 261 -296 269 -272 237 -266 257 -288 265 -232 259 -292 265 -272 269 -266 269 -234 263 -264 261 -262 255 -258 291 -264 267 -268 265 -236 299 -266 267 -266 231 -264 261 -264 293 -234 301 -266 267 -266 231 -264 261 -262 261 -264 261 -264 255 -292 265 -264 265 -270 273 -270 231 -264 261 -260 257 -258 291 -230 295 -264 267 -240 303 -266 267 -234 263 -262 261 -262 263 -262 257 -258 291 -264 269 -266 265 -268 273 -268 233 -262 261 -262 255 -290 267 -266 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 257 -290 265 -266 231 -264 297 -234 299 -266 267 -234 263 -264 261 -264 255 -258 291 -230 293 -264 269 -240 301 -266 269 -234 263 -262 257 -290 265 -266 231 -264 295 -234 299 -266 269 -266 233 -262 261 -262 261 -264 261 -262 263 -262 261 -264 295 -268 273 -268 233 -262 261 -262 255 -258 293 -304 243 -274 235 -264 261 -262 255 -258 291 -262 269 -234 259 -292 265 -266 263 -236 301 -264 269 -234 263 -262 257 -258 291 -264 267 -268 263 -270 273 -234 261 -290 265 -264 231 -264 263 -262 295 -236 299 -266 267 -234 263 -264 255 -290 265 -234 261 -292 265 -264 265 -236 299 -266 267 -266 231 -264 261 -264 255 -290 265 -232 261 -292 265 -266 231 -264 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 295 -268 273 -268 233 -262 261 -262 261 -264 261 -264 255 -290 267 -266 231 -264 295 -268 273 -268 231 -264 261 -262 255 -258 291 -264 269 -234 259 -292 265 -264 265 -270 273 -268 233 -262 257 -288 265 -234 259 -324 239 -278 237 -268 261 -262 261 -262 255 -290 267 -266 231 -264 295 -236 299 -232 295 -262 267 -268 231 -262 261 -262 257 -290 265 -268 265 -270 273 -234 265 -262 257 -288 265 -268 265 -236 299 -232 295 -262 269 -266 231 -262 261 -264 255 -292 265 -266 231 -264 295 -270 271 -268 233 -262 261 -262 263 -262 295 -270 271 -270 231 -262 261 -262 263 -262 261 -264 257 -290 265 -266 233 -262 295 -236 299 -264 269 -234 263 -264 261 -262 263 -262 257 -290 265 -272 269 -268 267 -234 263 -264 259 -262 263 -262 257 -290 265 -268 231 -264 295 -234 301 -230 295 -230 295 -230 293 -264 269 -266 263 -236 299 -266 267 -234 263 -264 261 -262 263 -262 257 -290 265 -266 231 -264 297 -234 299 -266 267 -234 265 -262 261 -264 261 -262 255 -258 291 -264 269 -274 267 -266 269 -234 263 -262 -RAW_Data: 263 -262 261 -262 295 -234 301 -266 269 -232 265 -262 261 -262 261 -264 261 -264 255 -292 265 -264 265 -270 273 -270 231 -264 261 -260 261 -264 257 -290 265 -266 271 -274 237 -266 257 -256 289 -262 267 -268 233 -264 295 -234 299 -266 267 -266 231 -264 263 -262 255 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 261 -262 295 -236 301 -266 267 -234 263 -262 257 -256 291 -230 295 -264 269 -268 265 -268 271 -268 233 -262 261 -262 257 -290 265 -266 233 -264 295 -236 299 -264 267 -266 231 -264 263 -262 261 -262 255 -290 267 -266 265 -236 301 -264 267 -266 231 -264 263 -262 261 -262 263 -262 261 -264 295 -234 301 -264 269 -234 263 -262 263 -262 257 -290 265 -232 259 -292 267 -264 265 -236 301 -266 267 -234 263 -262 263 -262 257 -290 265 -232 259 -292 267 -266 263 -270 273 -268 231 -264 261 -262 257 -256 293 -262 269 -268 265 -234 299 -266 267 -268 231 -262 261 -262 257 -290 265 -268 231 -264 295 -268 271 -270 231 -264 261 -262 293 -236 301 -266 267 -234 263 -264 261 -260 263 -262 257 -290 265 -266 231 -266 261 -264 293 -268 273 -270 231 -264 261 -262 255 -290 267 -266 233 -296 269 -272 235 -266 261 -264 259 -262 257 -290 265 -268 265 -270 271 -270 231 -262 261 -262 261 -262 257 -290 267 -266 265 -236 299 -266 267 -266 231 -264 261 -264 295 -234 299 -266 267 -234 263 -264 261 -264 255 -290 265 -266 231 -264 257 -290 265 -274 267 -268 269 -232 265 -262 261 -262 257 -258 291 -264 267 -240 303 -266 267 -234 263 -262 263 -262 257 -290 265 -232 261 -258 291 -262 267 -274 277 -236 261 -258 289 -228 295 -262 269 -268 265 -234 301 -264 267 -268 231 -262 261 -264 255 -290 265 -268 231 -264 263 -262 293 -234 301 -232 295 -264 267 -266 231 -264 255 -258 291 -264 267 -268 231 -264 293 -268 273 -270 231 -264 255 -290 265 -264 265 -236 301 -266 269 -266 231 -262 261 -262 263 -262 257 -256 293 -262 269 -268 265 -268 273 -268 231 -264 261 -262 255 -258 291 -296 241 -278 239 -268 261 -262 261 -260 257 -290 265 -268 231 -264 295 -236 299 -232 293 -264 267 -266 233 -262 257 -256 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 261 -264 295 -234 299 -266 269 -266 231 -262 257 -258 291 -262 269 -234 261 -290 265 -272 275 -270 233 -262 261 -260 261 -262 263 -262 257 -292 265 -266 265 -270 271 -270 231 -264 259 -262 257 -290 265 -268 231 -264 257 -290 265 -272 269 -266 269 -234 -RAW_Data: 263 -262 263 -262 261 -262 255 -292 265 -266 233 -264 295 -234 299 -266 269 -232 265 -262 261 -262 257 -290 265 -234 259 -292 265 -266 231 -264 295 -270 271 -270 231 -264 259 -262 257 -290 265 -268 231 -296 269 -272 235 -266 263 -260 263 -262 257 -290 265 -232 259 -292 267 -266 263 -236 301 -266 267 -234 263 -264 255 -258 289 -264 267 -268 265 -236 301 -264 267 -266 231 -264 257 -290 263 -268 265 -236 299 -266 267 -234 263 -264 261 -262 263 -262 257 -290 265 -266 265 -236 299 -266 269 -232 265 -262 255 -258 291 -270 273 -270 271 -234 263 -262 261 -262 263 -262 263 -262 257 -290 265 -266 233 -264 293 -268 273 -270 231 -264 261 -260 257 -290 265 -266 233 -264 295 -268 273 -268 233 -262 261 -260 257 -258 291 -230 295 -264 267 -268 265 -236 299 -232 293 -264 267 -266 231 -264 263 -262 295 -234 299 -266 269 -266 231 -262 261 -262 263 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -268 229 -264 261 -264 255 -290 265 -268 231 -264 263 -262 293 -268 273 -270 231 -264 261 -262 261 -262 295 -236 299 -266 267 -234 263 -264 261 -264 261 -262 257 -290 265 -266 233 -264 295 -268 273 -268 231 -264 261 -260 257 -290 265 -268 231 -298 269 -272 235 -266 257 -288 265 -266 231 -264 261 -262 295 -236 299 -266 269 -234 263 -262 261 -262 257 -290 267 -266 233 -264 261 -262 293 -236 299 -266 269 -232 259 -292 265 -266 231 -262 297 -234 299 -266 267 -234 265 -262 261 -264 261 -262 257 -258 291 -262 269 -240 303 -264 269 -234 263 -262 257 -290 265 -266 231 -264 263 -262 295 -234 299 -266 267 -268 231 -262 263 -262 255 -290 267 -266 265 -270 273 -236 263 -264 259 -262 257 -290 265 -234 261 -292 265 -264 265 -270 271 -270 231 -264 261 -262 255 -290 267 -234 259 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -262 261 -262 257 -290 265 -266 233 -264 295 -268 273 -234 261 -258 291 -262 267 -268 231 -264 295 -234 299 -264 269 -236 263 -262 261 -262 261 -264 257 -290 265 -266 265 -270 273 -268 231 -264 261 -262 255 -290 267 -272 269 -266 269 -234 263 -264 261 -260 263 -262 257 -290 267 -266 231 -264 295 -234 299 -266 269 -234 263 -262 263 -262 257 -256 293 -230 293 -304 243 -274 235 -266 255 -256 289 -264 267 -234 261 -292 263 -266 265 -236 299 -266 269 -232 265 -262 257 -256 291 -230 295 -264 269 -266 263 -270 273 -268 231 -264 261 -262 261 -262 257 -290 267 -266 231 -264 295 -234 -RAW_Data: 301 -264 269 -234 263 -262 263 -262 261 -264 295 -234 299 -266 269 -232 265 -262 261 -264 255 -258 291 -262 269 -268 231 -264 295 -234 299 -264 269 -268 231 -262 261 -262 263 -262 263 -262 257 -290 265 -266 265 -270 273 -268 233 -262 261 -262 255 -290 267 -272 269 -266 269 -234 263 -262 261 -262 257 -290 265 -234 261 -292 265 -264 265 -236 299 -266 267 -234 265 -262 257 -256 293 -230 293 -264 269 -274 275 -236 263 -264 259 -262 255 -292 265 -266 267 -236 299 -264 269 -266 231 -262 263 -262 261 -262 261 -264 261 -264 295 -234 301 -264 269 -266 231 -264 255 -290 265 -272 269 -268 269 -232 265 -262 255 -290 265 -234 259 -292 265 -266 265 -236 299 -266 269 -232 265 -262 261 -262 257 -290 265 -268 231 -264 295 -268 271 -270 231 -264 261 -262 261 -262 257 -290 265 -266 231 -266 295 -234 299 -266 269 -234 263 -262 263 -262 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 255 -290 265 -268 231 -264 263 -262 293 -234 301 -266 267 -266 231 -264 257 -256 291 -264 269 -266 233 -262 261 -262 295 -270 271 -236 261 -290 263 -266 231 -266 261 -264 293 -234 299 -266 269 -266 231 -264 261 -262 257 -290 265 -266 233 -264 295 -234 299 -264 269 -266 231 -264 257 -290 263 -274 269 -232 295 -264 267 -266 233 -262 257 -256 291 -262 269 -234 259 -292 265 -272 269 -266 269 -234 263 -262 257 -288 265 -268 231 -298 269 -238 263 -294 265 -234 259 -290 265 -238 303 -266 269 -234 263 -262 261 -262 257 -258 291 -230 295 -264 267 -240 301 -266 269 -232 265 -262 257 -290 265 -272 269 -266 269 -234 263 -262 261 -262 257 -290 265 -268 231 -264 257 -290 263 -268 265 -270 271 -270 231 -264 255 -258 289 -230 295 -264 267 -268 265 -268 273 -268 233 -262 261 -262 255 -290 267 -234 259 -260 289 -262 267 -268 265 -270 273 -268 233 -262 261 -262 261 -264 295 -234 299 -266 269 -234 263 -262 263 -262 257 -290 263 -234 259 -292 265 -266 265 -236 301 -232 295 -262 267 -266 231 -264 261 -264 255 -258 291 -264 267 -268 265 -236 299 -264 267 -268 229 -264 263 -262 261 -262 295 -268 273 -270 233 -262 261 -262 261 -262 263 -262 257 -290 265 -266 265 -270 273 -268 233 -262 261 -262 255 -258 291 -230 295 -298 239 -278 237 -268 263 -262 255 -290 263 -266 231 -266 295 -236 299 -264 269 -234 263 -262 263 -262 263 -262 261 -262 257 -290 265 -274 269 -266 267 -234 263 -264 255 -290 265 -274 -RAW_Data: 267 -268 269 -232 265 -262 261 -262 255 -292 265 -234 259 -292 265 -266 265 -234 301 -266 269 -232 263 -264 261 -262 261 -264 261 -264 255 -290 265 -266 267 -236 299 -264 269 -266 231 -262 263 -262 257 -258 291 -262 269 -274 275 -236 265 -262 261 -260 257 -258 291 -264 267 -268 231 -264 295 -234 299 -266 269 -234 263 -262 263 -262 257 -290 265 -232 259 -292 265 -266 265 -236 301 -232 295 -262 267 -266 231 -264 261 -264 261 -260 263 -262 263 -296 267 -274 235 -266 263 -260 257 -290 265 -266 233 -264 295 -268 271 -270 231 -264 261 -260 263 -262 263 -262 263 -262 295 -234 299 -266 269 -266 231 -262 263 -262 295 -234 299 -266 269 -266 231 -264 261 -262 261 -262 263 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 263 -262 257 -290 265 -264 273 -274 235 -266 263 -262 259 -262 257 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 257 -258 291 -262 269 -268 231 -264 293 -268 273 -268 233 -262 261 -262 263 -262 257 -290 265 -268 231 -264 293 -234 301 -266 269 -232 263 -264 261 -264 255 -290 265 -266 265 -236 301 -264 269 -266 231 -264 259 -262 263 -262 257 -258 291 -264 267 -268 265 -236 299 -264 267 -266 231 -264 263 -262 257 -290 265 -232 259 -292 265 -266 265 -270 273 -270 231 -262 261 -262 261 -262 263 -262 295 -270 271 -270 231 -264 261 -262 261 -262 257 -290 265 -266 233 -264 295 -234 299 -266 269 -232 265 -262 261 -264 261 -262 257 -290 265 -274 275 -238 259 -290 265 -264 231 -264 263 -262 295 -236 299 -264 269 -266 231 -262 263 -262 261 -264 255 -258 293 -262 269 -238 303 -266 267 -234 263 -262 257 -290 265 -266 265 -270 273 -270 231 -262 261 -262 255 -258 293 -230 293 -264 269 -266 265 -270 271 -270 231 -264 255 -256 291 -262 269 -268 231 -296 269 -238 263 -262 291 -262 267 -234 261 -292 265 -264 265 -236 299 -266 269 -232 265 -262 261 -262 261 -264 257 -258 291 -264 267 -240 303 -266 267 -234 263 -262 261 -262 263 -262 257 -290 265 -266 231 -264 295 -236 299 -266 269 -234 263 -262 261 -262 257 -290 265 -234 261 -290 265 -266 265 -236 299 -266 269 -232 265 -262 257 -290 263 -234 261 -292 265 -264 265 -236 301 -264 269 -234 263 -262 263 -262 261 -264 255 -290 265 -266 265 -236 301 -264 269 -234 263 -262 257 -258 291 -270 271 -272 271 -234 263 -264 259 -262 261 -264 255 -290 265 -266 231 -266 295 -234 301 -264 269 -234 263 -262 257 -256 293 -262 -RAW_Data: 269 -268 231 -296 269 -238 263 -294 265 -266 231 -264 261 -262 295 -268 273 -270 231 -264 261 -260 257 -290 265 -234 261 -290 265 -274 267 -268 267 -234 263 -262 261 -262 295 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -258 291 -264 269 -266 265 -236 299 -264 269 -266 231 -262 261 -264 255 -290 265 -268 231 -264 263 -262 293 -234 301 -266 269 -234 263 -264 261 -260 263 -262 263 -262 257 -290 265 -266 265 -236 299 -266 267 -266 231 -264 263 -262 255 -290 265 -268 231 -264 263 -262 293 -268 273 -270 233 -262 261 -260 257 -290 265 -268 231 -264 263 -262 295 -234 299 -266 269 -232 265 -262 261 -264 261 -264 255 -290 265 -274 267 -268 269 -232 265 -262 255 -290 265 -268 265 -236 299 -266 267 -266 231 -264 261 -262 261 -262 257 -258 291 -264 267 -274 269 -266 269 -232 263 -264 261 -264 293 -234 301 -266 269 -232 263 -264 261 -264 261 -262 257 -290 265 -266 233 -264 293 -268 273 -268 233 -262 257 -256 291 -264 269 -266 233 -262 295 -268 271 -236 261 -292 263 -266 231 -264 261 -262 295 -236 299 -266 267 -268 231 -262 261 -262 257 -290 265 -268 231 -264 295 -268 271 -270 233 -262 261 -262 257 -256 293 -230 293 -264 269 -266 265 -234 301 -264 269 -232 265 -262 261 -264 255 -292 265 -272 275 -272 231 -264 261 -260 261 -262 261 -264 257 -290 265 -268 231 -264 295 -234 299 -266 267 -268 231 -262 257 -288 267 -266 233 -264 255 -290 265 -266 263 -236 301 -266 269 -232 265 -262 257 -290 265 -234 259 -292 265 -272 275 -238 263 -264 255 -256 291 -262 269 -268 265 -236 299 -264 269 -266 231 -262 261 -262 257 -290 265 -234 261 -292 265 -238 301 -268 269 -234 263 -262 261 -262 295 -234 301 -266 269 -232 263 -264 261 -262 255 -292 265 -266 233 -264 255 -290 265 -272 269 -268 269 -232 265 -262 255 -290 265 -266 233 -296 269 -272 235 -266 261 -262 261 -264 255 -292 265 -266 265 -236 299 -266 269 -234 263 -262 261 -262 257 -290 265 -268 231 -264 295 -268 271 -270 231 -264 261 -262 261 -262 297 -234 299 -266 267 -234 265 -262 261 -264 261 -262 257 -258 291 -264 267 -240 303 -266 267 -234 263 -264 261 -260 257 -290 265 -234 261 -292 265 -266 231 -264 295 -268 271 -270 231 -264 261 -262 261 -262 257 -290 265 -234 259 -292 265 -266 265 -234 301 -266 269 -232 265 -262 261 -264 261 -262 257 -290 263 -268 265 -270 273 -268 231 -264 261 -262 261 -262 263 -262 257 -290 265 -266 265 -236 -RAW_Data: 301 -264 269 -234 263 -262 263 -262 257 -290 265 -266 233 -296 269 -272 235 -266 257 -288 265 -266 231 -264 295 -236 299 -232 293 -264 267 -268 231 -264 255 -258 289 -264 267 -268 265 -236 301 -264 267 -266 231 -264 261 -262 261 -264 295 -234 299 -266 269 -234 265 -262 257 -288 265 -234 259 -292 267 -264 265 -270 271 -270 231 -264 255 -290 265 -232 259 -292 267 -266 271 -240 265 -292 265 -266 231 -262 263 -262 263 -262 293 -234 301 -266 269 -234 263 -262 261 -262 261 -264 257 -290 265 -268 265 -236 299 -264 267 -268 231 -262 257 -258 291 -262 267 -268 233 -264 293 -234 301 -264 269 -234 263 -262 263 -262 261 -264 293 -268 273 -270 233 -262 261 -262 261 -262 257 -290 267 -232 259 -292 265 -266 265 -236 299 -266 267 -268 231 -262 263 -262 261 -262 257 -290 265 -266 233 -264 295 -236 299 -264 267 -266 231 -264 263 -262 255 -258 291 -296 241 -278 239 -268 263 -260 255 -288 265 -268 231 -264 261 -262 295 -236 299 -266 269 -234 263 -262 263 -262 257 -256 291 -264 267 -268 265 -270 271 -236 265 -262 261 -262 261 -264 295 -234 301 -266 267 -234 263 -262 263 -262 263 -262 257 -290 263 -268 265 -236 299 -264 269 -266 231 -262 263 -262 263 -262 289 -264 277 -272 235 -264 261 -262 255 -256 293 -262 269 -268 263 -236 301 -264 267 -266 231 -264 257 -288 265 -268 231 -264 263 -262 293 -268 273 -270 231 -264 261 -262 261 -262 295 -236 299 -266 267 -268 231 -262 263 -262 261 -262 255 -292 265 -266 233 -264 263 -262 293 -268 273 -270 231 -264 261 -262 255 -290 267 -266 231 -264 261 -262 295 -236 299 -266 269 -232 265 -262 261 -264 255 -290 265 -268 233 -262 295 -234 299 -264 269 -268 231 -264 261 -262 255 -290 267 -266 233 -264 261 -262 293 -270 273 -268 233 -262 261 -262 261 -264 257 -288 265 -234 261 -292 265 -238 303 -266 267 -234 263 -262 257 -290 265 -268 231 -296 269 -272 235 -266 257 -290 263 -266 231 -266 257 -290 263 -266 265 -236 301 -266 267 -234 263 -262 257 -290 265 -266 233 -264 261 -262 293 -270 273 -270 231 -264 259 -262 261 -264 295 -236 299 -264 269 -266 231 -264 261 -262 255 -258 293 -262 269 -268 265 -268 273 -236 263 -264 261 -260 257 -258 291 -296 241 -276 239 -270 261 -262 259 -262 261 -264 255 -292 265 -266 233 -264 295 -234 299 -264 269 -234 265 -262 257 -256 291 -264 269 -266 265 -236 299 -264 269 -266 231 -264 255 -258 291 -262 269 -266 233 -262 295 -236 -RAW_Data: 299 -232 295 -262 269 -266 231 -262 263 -262 293 -236 301 -266 267 -266 231 -264 261 -260 263 -262 257 -258 291 -264 267 -268 265 -236 299 -264 267 -268 231 -262 263 -262 257 -290 265 -266 231 -264 261 -264 295 -234 299 -266 269 -232 265 -262 257 -258 291 -262 269 -240 301 -266 269 -234 263 -262 257 -290 265 -266 231 -264 263 -260 295 -236 301 -264 269 -234 263 -262 257 -258 289 -230 295 -264 269 -266 265 -236 299 -264 269 -232 259 -292 265 -266 263 -236 301 -264 269 -234 263 -264 261 -262 257 -290 265 -266 231 -264 263 -262 295 -268 273 -270 231 -262 261 -262 257 -290 265 -272 277 -238 265 -262 259 -262 257 -290 265 -268 231 -264 261 -262 295 -268 273 -270 231 -264 261 -260 263 -262 263 -262 263 -262 293 -270 273 -268 233 -262 255 -258 291 -262 267 -268 265 -236 301 -264 267 -266 231 -264 263 -262 261 -262 257 -290 265 -268 265 -270 273 -234 265 -262 261 -262 255 -258 291 -264 267 -268 265 -236 299 -266 267 -266 231 -264 261 -264 255 -258 291 -262 269 -240 301 -266 269 -234 263 -262 257 -290 265 -232 259 -260 293 -262 269 -266 263 -236 299 -266 269 -234 263 -262 263 -262 257 -290 263 -268 231 -264 263 -262 295 -234 299 -266 269 -232 265 -262 261 -264 261 -262 257 -290 265 -272 277 -270 233 -262 255 -288 265 -266 233 -264 261 -264 293 -234 301 -266 269 -232 265 -262 261 -262 257 -258 291 -264 267 -240 303 -266 269 -232 265 -262 261 -260 295 -236 301 -266 267 -234 263 -264 261 -262 263 -262 257 -290 265 -232 261 -292 265 -264 265 -270 273 -270 231 -262 261 -262 255 -258 291 -298 241 -278 237 -268 261 -262 255 -290 265 -266 231 -264 297 -234 299 -266 269 -232 265 -262 261 -262 261 -264 261 -264 261 -264 295 -268 271 -270 231 -264 261 -262 261 -262 263 -262 257 -290 265 -266 265 -236 299 -266 269 -234 265 -262 259 -262 257 -292 265 -266 231 -264 295 -234 299 -232 295 -264 267 -268 231 -262 257 -256 293 -262 269 -234 261 -290 265 -264 265 -236 301 -264 269 -234 263 -262 261 -262 261 -264 263 -262 257 -290 265 -272 269 -266 269 -234 263 -264 255 -290 265 -268 265 -268 273 -268 233 -262 261 -262 255 -292 265 -234 259 -260 291 -260 269 -266 267 -270 271 -236 265 -262 255 -258 291 -262 269 -268 231 -296 269 -272 235 -266 257 -256 289 -264 267 -268 233 -262 295 -234 299 -266 267 -236 263 -264 261 -262 261 -262 263 -262 263 -262 295 -268 273 -268 233 -262 261 -262 261 -264 -RAW_Data: 295 -236 299 -266 267 -234 263 -264 261 -262 257 -290 265 -266 233 -264 293 -268 273 -270 231 -264 261 -262 261 -262 263 -262 261 -296 269 -272 235 -268 257 -256 291 -262 267 -268 233 -262 295 -234 299 -266 269 -234 263 -262 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 269 -234 263 -264 259 -262 263 -262 263 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -264 293 -268 273 -270 231 -264 261 -262 255 -258 291 -264 267 -268 233 -262 295 -236 299 -264 269 -232 265 -262 261 -264 261 -262 263 -262 257 -290 265 -266 265 -236 301 -264 269 -234 263 -262 263 -262 261 -262 261 -296 269 -274 235 -266 263 -260 261 -262 263 -262 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 257 -258 291 -262 269 -268 231 -264 293 -268 273 -270 231 -264 255 -288 265 -268 265 -236 299 -264 269 -266 231 -262 263 -262 261 -262 263 -262 263 -262 261 -264 295 -268 273 -268 233 -262 261 -262 257 -256 293 -304 243 -274 235 -264 261 -262 261 -262 261 -262 257 -290 267 -272 269 -234 295 -262 267 -266 231 -264 261 -262 257 -290 265 -266 267 -236 299 -264 269 -266 231 -262 257 -258 289 -262 269 -268 231 -264 295 -234 299 -266 269 -232 265 -262 261 -264 261 -264 261 -262 257 -290 265 -268 265 -236 299 -264 269 -266 231 -264 261 -262 261 -262 257 -290 265 -268 231 -264 295 -234 299 -266 269 -234 263 -262 263 -262 257 -256 291 -230 295 -264 267 -274 275 -238 263 -264 259 -262 255 -292 265 -266 267 -236 299 -264 269 -266 231 -262 263 -262 255 -258 291 -264 269 -266 233 -262 295 -268 271 -270 231 -264 255 -290 265 -234 259 -292 271 -278 237 -268 261 -262 255 -290 265 -266 233 -264 261 -262 293 -236 301 -266 267 -234 263 -262 261 -262 263 -262 263 -262 263 -262 295 -268 273 -268 233 -264 255 -290 265 -266 263 -236 301 -266 267 -234 263 -264 255 -292 263 -234 261 -292 265 -264 265 -270 271 -270 231 -264 261 -262 261 -264 261 -296 269 -272 235 -266 263 -260 257 -288 265 -268 231 -266 255 -290 265 -266 263 -236 301 -266 269 -232 265 -262 257 -290 265 -266 231 -264 295 -236 299 -264 269 -234 263 -262 263 -262 261 -264 255 -258 293 -262 269 -268 263 -236 299 -232 295 -262 269 -266 231 -262 257 -288 267 -266 233 -264 261 -262 295 -268 273 -268 233 -262 261 -262 255 -290 267 -266 233 -264 261 -262 261 -264 295 -234 299 -266 267 -236 263 -264 255 -290 265 -266 233 -264 261 -264 -RAW_Data: 293 -268 273 -268 233 -262 261 -262 261 -264 295 -234 301 -264 269 -266 231 -264 261 -260 263 -262 257 -290 267 -266 233 -262 295 -268 271 -270 233 -264 261 -260 257 -290 265 -268 271 -274 235 -266 261 -262 261 -262 255 -290 267 -266 265 -236 301 -264 267 -266 231 -264 261 -264 255 -258 293 -262 269 -266 265 -236 299 -264 267 -268 231 -262 263 -262 295 -234 299 -266 269 -266 231 -264 259 -262 263 -262 257 -290 267 -232 259 -292 265 -240 301 -266 269 -266 231 -264 261 -260 257 -258 291 -264 267 -268 233 -262 295 -234 299 -264 269 -234 265 -262 261 -262 263 -262 257 -258 291 -264 267 -268 265 -236 299 -264 269 -232 265 -262 257 -256 293 -262 269 -268 231 -264 293 -234 299 -266 269 -232 265 -262 261 -264 255 -292 265 -232 261 -292 265 -264 265 -270 273 -270 231 -262 261 -262 255 -258 293 -262 269 -268 271 -274 235 -264 263 -260 261 -262 257 -290 265 -268 231 -264 295 -234 299 -234 295 -262 267 -266 233 -262 257 -256 291 -264 269 -266 265 -236 299 -266 267 -234 259 -290 265 -266 231 -264 295 -236 299 -264 267 -268 231 -262 263 -262 261 -264 255 -290 265 -266 267 -236 299 -264 269 -266 231 -262 257 -258 291 -228 295 -264 269 -266 265 -236 299 -266 267 -234 263 -262 263 -262 263 -262 287 -266 269 -270 271 -234 265 -262 255 -290 265 -266 233 -264 257 -288 265 -266 267 -236 299 -264 269 -234 263 -262 263 -262 255 -290 267 -266 233 -264 261 -262 293 -234 301 -266 269 -234 263 -264 255 -256 293 -262 269 -268 231 -262 295 -268 271 -270 231 -264 257 -288 265 -266 267 -236 299 -264 269 -266 231 -264 255 -290 265 -234 259 -292 265 -266 265 -268 273 -270 233 -262 261 -260 257 -290 265 -274 269 -266 269 -232 265 -262 261 -262 261 -264 263 -262 255 -290 267 -266 265 -270 273 -236 263 -264 259 -262 263 -262 257 -290 265 -266 265 -270 273 -236 261 -290 263 -266 231 -264 261 -264 295 -234 299 -266 269 -232 265 -262 261 -262 263 -262 257 -290 265 -266 265 -236 299 -266 269 -232 265 -264 259 -262 295 -236 301 -266 267 -234 263 -264 261 -262 257 -288 267 -232 261 -258 291 -262 267 -276 267 -268 269 -232 263 -264 259 -262 257 -258 291 -264 267 -274 269 -266 269 -232 265 -262 261 -264 261 -262 261 -262 257 -290 265 -268 265 -270 273 -234 261 -258 289 -230 293 -264 267 -268 265 -270 273 -236 263 -262 261 -262 255 -258 293 -262 269 -268 231 -264 293 -234 301 -264 269 -234 265 -262 261 -262 -RAW_Data: 261 -264 257 -256 293 -262 269 -268 265 -234 299 -266 267 -266 231 -264 257 -288 265 -266 267 -236 299 -264 269 -234 265 -262 261 -262 261 -264 255 -258 291 -264 267 -268 265 -270 271 -268 233 -262 261 -262 257 -256 293 -296 239 -278 273 -234 263 -260 255 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -266 231 -264 261 -262 257 -258 291 -264 267 -236 297 -234 299 -266 269 -232 259 -290 265 -266 265 -236 301 -264 269 -232 263 -264 255 -292 265 -266 231 -264 257 -290 265 -272 277 -236 265 -262 261 -262 261 -262 261 -264 289 -264 277 -274 235 -264 261 -260 257 -288 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -262 263 -262 257 -290 265 -274 267 -268 267 -234 263 -264 261 -262 261 -264 255 -258 293 -262 269 -268 265 -234 299 -266 267 -234 257 -260 291 -260 269 -274 269 -268 267 -234 263 -262 261 -262 255 -292 265 -268 231 -264 257 -288 265 -266 265 -270 273 -268 233 -262 261 -262 255 -292 265 -234 259 -292 265 -266 263 -236 301 -266 269 -232 263 -264 261 -262 255 -258 293 -262 269 -274 275 -236 265 -262 261 -262 255 -258 291 -264 267 -236 259 -292 265 -264 265 -270 271 -270 231 -264 261 -262 255 -290 267 -266 233 -296 267 -274 235 -266 261 -262 261 -262 255 -290 267 -266 233 -264 295 -234 299 -266 267 -234 263 -264 255 -292 265 -266 231 -264 295 -234 301 -264 269 -234 263 -264 259 -262 295 -236 301 -232 295 -262 267 -268 231 -264 261 -260 257 -258 291 -264 267 -268 265 -236 299 -264 269 -266 231 -262 257 -258 291 -262 269 -268 231 -264 293 -234 299 -266 269 -268 231 -262 261 -262 255 -258 293 -262 269 -274 275 -236 265 -262 255 -258 291 -230 295 -262 269 -268 231 -264 293 -234 299 -266 269 -234 265 -262 261 -262 261 -262 263 -262 257 -290 265 -266 265 -236 299 -266 269 -266 231 -262 257 -290 265 -266 233 -264 261 -262 293 -270 273 -236 261 -290 263 -234 259 -292 265 -238 303 -266 267 -234 263 -264 261 -262 257 -258 291 -262 269 -234 261 -290 263 -266 265 -236 301 -266 267 -234 263 -262 263 -262 257 -288 265 -274 269 -266 269 -234 263 -262 257 -288 265 -234 261 -292 265 -264 265 -236 301 -266 267 -234 263 -262 261 -262 257 -258 291 -296 243 -276 239 -268 261 -262 261 -260 261 -264 257 -290 265 -266 265 -236 301 -266 267 -234 263 -262 263 -262 257 -256 291 -264 269 -266 265 -270 271 -236 265 -262 255 -258 291 -262 269 -234 261 -290 265 -266 -RAW_Data: 265 -234 301 -266 269 -232 263 -264 261 -262 295 -234 301 -264 269 -234 263 -262 263 -262 257 -290 265 -234 261 -258 291 -260 269 -266 267 -270 271 -236 265 -262 261 -262 261 -264 255 -292 265 -266 233 -264 261 -260 295 -270 273 -268 233 -262 261 -262 255 -258 291 -264 269 -274 275 -236 265 -262 255 -256 291 -230 295 -264 269 -266 265 -236 299 -232 293 -264 269 -232 263 -264 263 -262 261 -264 255 -290 265 -266 233 -296 269 -272 235 -268 255 -258 289 -262 269 -268 265 -236 299 -266 267 -234 263 -262 263 -262 261 -264 261 -262 263 -262 295 -234 301 -266 267 -234 263 -262 257 -290 265 -272 269 -268 269 -232 265 -262 261 -262 261 -262 257 -290 267 -234 259 -292 265 -238 303 -266 267 -234 263 -262 257 -290 265 -266 233 -264 261 -264 293 -234 299 -268 269 -232 265 -262 255 -258 291 -264 267 -236 259 -290 265 -272 275 -238 259 -292 263 -266 231 -264 261 -264 293 -234 301 -266 267 -234 263 -264 261 -262 255 -292 265 -234 259 -292 265 -266 231 -264 295 -234 301 -264 269 -234 263 -262 263 -262 261 -262 263 -262 261 -264 295 -268 273 -236 265 -264 261 -260 257 -290 265 -272 269 -268 269 -232 265 -262 261 -262 255 -292 265 -234 259 -292 265 -266 265 -268 273 -236 265 -262 261 -262 261 -264 261 -296 269 -272 235 -268 261 -262 261 -262 261 -264 255 -290 267 -266 265 -236 301 -264 267 -234 263 -264 261 -262 263 -262 261 -264 255 -292 265 -266 263 -270 273 -236 265 -264 255 -256 291 -264 267 -268 233 -262 295 -234 299 -266 269 -232 265 -262 261 -262 257 -258 291 -264 267 -240 303 -266 269 -232 265 -262 261 -262 261 -264 261 -264 255 -292 265 -266 263 -236 301 -266 267 -234 263 -264 261 -264 261 -262 295 -268 271 -270 233 -264 261 -260 263 -262 257 -258 291 -262 269 -266 233 -262 295 -268 271 -270 231 -264 261 -262 257 -290 265 -266 231 -264 259 -290 231 -300 263 -270 273 -268 231 -264 261 -262 261 -264 257 -290 265 -266 271 -274 235 -266 257 -290 231 -298 231 -296 231 -262 295 -234 301 -266 233 -300 231 -264 261 -262 257 -258 291 -264 267 -268 263 -236 299 -264 269 -266 231 -264 261 -264 295 -234 299 -266 267 -266 231 -264 261 -262 257 -290 265 -234 259 -292 233 -298 265 -236 299 -266 233 -300 231 -264 257 -258 289 -230 293 -306 243 -274 235 -264 257 -288 265 -264 233 -296 231 -262 293 -236 299 -266 235 -300 231 -262 263 -262 261 -262 257 -290 265 -272 269 -266 235 -300 231 -296 -RAW_Data: 229 -262 263 -262 295 -234 299 -266 235 -300 231 -294 231 -262 263 -262 257 -290 265 -264 265 -236 301 -266 233 -300 231 -296 229 -262 261 -294 229 -296 231 -294 263 -236 299 -266 235 -300 229 -264 261 -262 263 -262 257 -290 265 -272 275 -270 233 -262 261 -262 261 -264 257 -258 291 -262 269 -266 265 -234 301 -264 269 -266 231 -264 261 -264 255 -290 265 -232 259 -294 231 -300 263 -236 301 -266 235 -300 229 -264 261 -294 229 -264 257 -290 231 -298 265 -270 273 -268 233 -264 255 -290 231 -300 231 -296 263 -234 301 -266 233 -300 231 -262 263 -262 257 -290 265 -266 231 -298 263 -268 271 -268 233 -262 261 -294 229 -264 295 -270 271 -270 231 -264 261 -260 263 -262 257 -292 231 -298 231 -296 231 -262 295 -236 299 -264 269 -266 233 -262 261 -262 263 -262 257 -290 265 -272 275 -270 233 -262 261 -262 261 -264 257 -290 265 -264 265 -270 267 -266 233 -300 231 -264 257 -258 291 -230 293 -264 267 -272 269 -266 235 -300 229 -296 231 -262 261 -262 257 -258 291 -264 267 -274 267 -234 263 -294 267 -266 233 -262 263 -262 257 -290 231 -298 265 -270 273 -268 233 -262 261 -262 257 -258 291 -264 267 -234 261 -290 231 -300 263 -270 267 -266 233 -300 231 -264 261 -262 263 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -264 261 -264 255 -290 231 -300 265 -268 273 -270 233 -262 261 -294 229 -264 257 -258 291 -262 267 -268 265 -234 299 -266 235 -300 231 -262 257 -292 229 -300 231 -298 263 -234 299 -232 295 -230 295 -262 235 -300 231 -264 293 -234 299 -266 269 -268 231 -262 261 -262 261 -294 231 -296 229 -296 263 -234 299 -266 233 -300 231 -296 229 -296 263 -234 299 -266 233 -300 231 -264 257 -290 231 -300 231 -296 229 -296 263 -234 299 -266 235 -300 229 -296 231 -262 257 -256 293 -262 269 -272 269 -264 235 -268 259 -258 259 -294 267 -266 267 -236 299 -264 235 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 263 -270 273 -268 231 -264 261 -264 261 -262 255 -292 265 -266 231 -298 261 -270 271 -268 231 -264 263 -262 257 -256 291 -262 269 -274 275 -270 231 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -266 233 -262 261 -294 231 -294 229 -264 255 -292 231 -298 231 -298 263 -236 299 -264 267 -266 231 -264 257 -258 259 -296 267 -266 265 -270 271 -236 259 -292 231 -300 231 -296 229 -262 295 -268 265 -266 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 -RAW_Data: 265 -236 299 -264 235 -300 231 -296 229 -264 293 -234 299 -266 235 -300 231 -264 261 -294 229 -296 231 -262 257 -290 265 -264 265 -236 301 -266 235 -300 229 -264 261 -262 257 -258 291 -296 239 -278 237 -270 257 -290 229 -300 231 -296 231 -262 293 -236 299 -266 235 -300 229 -264 257 -258 259 -260 295 -264 267 -274 267 -268 235 -300 229 -264 257 -290 265 -272 267 -234 263 -296 233 -298 231 -296 231 -262 257 -258 291 -262 235 -300 231 -296 263 -268 271 -270 231 -264 257 -290 231 -266 259 -292 233 -298 265 -236 299 -264 269 -266 233 -262 261 -262 257 -258 291 -264 267 -266 265 -270 271 -270 231 -264 261 -262 255 -290 265 -268 231 -264 295 -236 299 -264 235 -300 231 -296 229 -262 257 -258 291 -230 295 -262 269 -266 265 -234 299 -266 269 -266 231 -264 261 -262 257 -258 291 -264 267 -268 263 -236 299 -264 235 -300 231 -264 261 -264 261 -294 263 -268 271 -270 233 -262 261 -262 257 -256 293 -262 269 -234 261 -292 263 -272 275 -270 231 -264 261 -260 257 -290 265 -234 293 -266 275 -272 233 -266 261 -262 259 -296 229 -264 257 -290 231 -300 263 -236 301 -266 235 -300 231 -262 261 -294 229 -264 257 -290 265 -272 267 -268 235 -266 259 -292 231 -298 231 -298 261 -270 271 -268 233 -264 261 -294 229 -262 257 -292 231 -298 265 -236 301 -266 233 -300 231 -262 261 -296 229 -296 261 -270 271 -270 231 -264 261 -294 229 -264 257 -258 291 -262 269 -266 233 -262 295 -266 273 -268 233 -264 257 -258 289 -262 267 -268 231 -298 261 -270 271 -268 231 -264 261 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -232 295 -264 233 -266 259 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 261 -262 257 -258 293 -262 267 -268 265 -236 299 -264 269 -266 231 -264 261 -262 257 -290 265 -232 261 -292 231 -300 263 -270 273 -268 231 -264 261 -262 263 -262 295 -268 265 -234 295 -262 267 -268 231 -264 261 -260 257 -292 231 -298 233 -296 263 -236 299 -264 267 -268 231 -264 257 -290 231 -266 259 -292 265 -272 275 -236 261 -292 229 -266 259 -292 233 -298 263 -236 301 -266 233 -300 231 -264 263 -262 261 -294 229 -264 257 -290 265 -272 267 -268 235 -300 231 -262 257 -290 231 -300 265 -268 273 -270 231 -264 261 -262 255 -258 291 -264 267 -268 231 -264 295 -266 271 -270 233 -264 255 -258 291 -264 233 -300 231 -296 269 -238 265 -262 259 -262 293 -230 295 -264 233 -300 265 -234 299 -266 233 -300 231 -298 -RAW_Data: 229 -262 257 -290 265 -264 233 -296 263 -270 271 -268 231 -264 263 -262 257 -290 229 -266 261 -292 233 -298 265 -234 301 -266 235 -300 229 -264 261 -262 261 -296 261 -270 273 -268 233 -262 261 -262 257 -290 233 -266 259 -292 231 -300 231 -296 263 -268 273 -268 231 -264 261 -294 231 -262 257 -290 231 -266 261 -292 231 -300 263 -270 273 -268 231 -264 261 -262 257 -290 233 -298 231 -296 271 -238 263 -294 233 -298 231 -264 295 -234 299 -266 235 -300 229 -296 231 -262 257 -290 231 -266 259 -292 233 -298 265 -270 265 -266 235 -300 231 -262 257 -290 265 -272 269 -266 235 -300 231 -294 229 -264 257 -290 231 -266 259 -260 293 -262 267 -272 269 -266 235 -300 231 -262 261 -262 257 -258 293 -296 239 -278 237 -268 257 -258 257 -294 267 -234 261 -292 231 -298 265 -236 301 -266 233 -300 229 -264 257 -258 291 -228 295 -264 267 -268 265 -268 273 -268 231 -264 263 -262 255 -258 291 -230 295 -262 269 -268 263 -236 297 -266 235 -300 231 -264 261 -262 257 -258 291 -262 267 -268 265 -236 299 -264 235 -300 231 -296 229 -264 257 -256 291 -262 267 -268 231 -266 295 -234 299 -232 295 -262 235 -300 229 -296 231 -262 257 -258 291 -262 269 -266 265 -236 299 -264 235 -300 231 -264 255 -292 265 -270 269 -266 235 -302 229 -264 261 -262 257 -290 265 -232 259 -260 293 -262 269 -272 269 -264 235 -300 231 -264 261 -262 257 -258 291 -296 241 -276 239 -266 263 -262 255 -258 291 -264 267 -268 265 -234 299 -232 295 -262 235 -300 231 -264 261 -262 257 -258 291 -264 267 -268 263 -270 271 -268 233 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -260 257 -292 231 -298 231 -298 263 -234 299 -266 235 -300 231 -262 257 -292 231 -298 231 -296 271 -272 235 -266 257 -258 289 -228 295 -264 267 -268 233 -262 295 -234 299 -266 267 -268 231 -264 261 -294 229 -296 229 -264 261 -262 295 -268 271 -270 233 -262 261 -262 263 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -264 257 -290 231 -300 263 -236 301 -266 235 -300 229 -264 261 -262 257 -290 265 -266 233 -264 261 -294 263 -234 299 -266 235 -300 231 -296 229 -262 263 -262 257 -258 291 -262 235 -300 263 -270 273 -268 233 -262 261 -294 229 -296 229 -296 263 -268 273 -268 231 -264 261 -262 261 -262 257 -292 231 -298 265 -270 273 -268 233 -262 261 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -302 231 -264 257 -288 231 -300 263 -236 301 -266 -RAW_Data: 235 -300 231 -262 261 -262 257 -258 293 -228 295 -264 267 -274 267 -266 235 -300 231 -262 257 -258 291 -262 267 -274 275 -270 233 -262 261 -262 261 -264 257 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -258 259 -260 295 -264 267 -268 265 -236 299 -264 235 -300 231 -262 257 -258 261 -294 267 -234 259 -292 231 -300 263 -236 301 -266 233 -300 231 -262 257 -258 291 -264 233 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -262 269 -266 265 -236 299 -264 235 -266 259 -260 291 -230 293 -264 267 -268 231 -264 293 -268 271 -270 233 -264 261 -262 255 -292 231 -266 259 -294 265 -272 267 -266 235 -300 231 -262 257 -290 231 -300 265 -270 271 -270 233 -262 261 -262 257 -290 265 -266 233 -264 257 -290 229 -300 265 -270 271 -270 231 -264 257 -288 231 -268 259 -292 231 -300 271 -238 265 -294 231 -300 231 -264 257 -290 231 -298 265 -236 299 -266 235 -300 231 -296 229 -262 261 -296 229 -296 229 -296 261 -270 271 -268 233 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -268 231 -264 261 -292 229 -296 263 -270 271 -268 233 -262 261 -294 231 -262 257 -292 231 -264 261 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -294 231 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -264 261 -262 261 -264 257 -258 291 -296 239 -278 237 -270 261 -262 255 -258 291 -230 295 -264 233 -300 265 -234 299 -266 235 -300 231 -296 229 -262 263 -262 257 -290 231 -300 263 -270 273 -268 231 -264 261 -296 229 -294 263 -236 299 -266 233 -300 231 -296 229 -264 259 -296 229 -264 257 -290 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -268 259 -292 231 -300 263 -236 299 -266 235 -300 231 -296 229 -262 257 -290 231 -300 265 -234 301 -266 235 -300 229 -296 229 -264 261 -262 257 -258 291 -262 267 -268 265 -236 299 -266 233 -300 231 -296 229 -262 257 -292 231 -266 259 -292 231 -300 265 -234 301 -264 235 -300 231 -296 229 -264 261 -294 263 -268 271 -270 233 -264 259 -294 229 -296 231 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -264 255 -258 291 -262 269 -266 265 -270 271 -268 233 -264 255 -290 231 -298 265 -236 301 -266 235 -300 229 -296 231 -262 257 -290 231 -298 231 -298 229 -264 295 -268 271 -270 231 -264 261 -262 -RAW_Data: 257 -290 265 -272 267 -268 233 -300 231 -264 263 -262 261 -262 257 -290 265 -266 231 -296 263 -270 271 -268 233 -264 261 -262 261 -296 229 -262 261 -296 261 -236 301 -266 233 -300 231 -262 263 -262 257 -290 231 -300 231 -298 229 -262 295 -268 271 -270 231 -264 261 -262 261 -262 257 -290 265 -266 265 -270 267 -266 233 -300 231 -264 261 -296 229 -262 257 -290 231 -300 231 -296 263 -234 301 -264 269 -268 231 -262 261 -294 229 -296 229 -264 261 -294 263 -236 299 -266 235 -298 231 -264 257 -290 231 -300 263 -236 301 -266 235 -298 231 -296 229 -296 229 -262 257 -290 265 -266 265 -234 301 -266 235 -300 231 -262 261 -296 229 -264 293 -268 271 -270 233 -264 261 -262 261 -262 257 -290 233 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -290 231 -300 231 -296 229 -296 263 -268 273 -268 231 -264 257 -290 231 -298 265 -236 299 -266 235 -300 231 -262 257 -290 265 -232 261 -292 231 -300 263 -270 273 -268 231 -264 261 -262 257 -258 291 -304 243 -274 235 -264 261 -262 255 -258 291 -262 269 -234 261 -292 231 -298 265 -234 301 -264 235 -300 231 -296 229 -262 261 -296 229 -296 229 -262 295 -234 301 -264 235 -300 231 -264 261 -294 229 -264 257 -258 291 -264 267 -268 263 -236 299 -264 235 -300 231 -296 229 -294 231 -262 257 -258 291 -262 267 -268 265 -270 271 -270 231 -264 259 -262 261 -296 231 -262 257 -290 231 -300 265 -234 301 -264 269 -266 231 -264 261 -262 261 -296 229 -264 257 -290 231 -300 231 -296 269 -272 235 -268 257 -290 229 -300 231 -264 295 -236 299 -264 235 -300 231 -264 261 -262 257 -258 291 -262 269 -266 265 -270 271 -268 233 -262 261 -262 257 -290 265 -272 269 -266 235 -300 231 -264 263 -262 261 -262 257 -258 291 -262 267 -268 265 -270 271 -270 231 -262 261 -296 229 -296 229 -262 257 -290 265 -266 233 -264 293 -234 301 -266 233 -300 231 -264 255 -258 291 -264 267 -234 261 -292 231 -298 265 -234 299 -266 269 -266 231 -264 257 -256 291 -230 295 -264 267 -266 265 -236 299 -266 235 -300 231 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -268 233 -264 255 -290 231 -298 233 -296 231 -262 293 -236 299 -232 295 -262 267 -268 231 -264 295 -234 299 -264 269 -268 231 -264 261 -262 255 -292 231 -300 231 -264 263 -262 295 -268 271 -270 231 -264 261 -262 257 -290 265 -272 275 -270 233 -262 261 -262 261 -264 255 -260 291 -262 269 -266 265 -236 299 -264 235 -300 -RAW_Data: 231 -264 255 -258 293 -262 267 -268 263 -270 271 -270 231 -262 257 -258 291 -262 269 -266 265 -236 299 -266 233 -300 231 -296 229 -264 261 -262 257 -290 265 -266 265 -236 299 -266 233 -300 231 -296 229 -264 255 -292 231 -300 231 -296 263 -234 299 -266 267 -268 231 -262 263 -294 229 -264 295 -234 299 -266 233 -300 231 -264 257 -258 291 -262 269 -234 259 -292 231 -298 265 -236 299 -266 233 -300 231 -264 261 -264 261 -262 255 -292 231 -300 231 -298 263 -234 299 -266 233 -300 231 -264 257 -290 263 -266 231 -298 231 -294 269 -270 237 -266 263 -262 261 -262 257 -290 265 -266 265 -236 299 -264 269 -266 231 -264 261 -264 255 -292 231 -298 231 -298 263 -268 271 -270 231 -264 261 -294 229 -296 263 -234 299 -266 233 -300 231 -264 261 -262 257 -258 293 -262 267 -268 231 -264 293 -268 273 -270 231 -264 261 -262 255 -258 291 -296 241 -276 239 -268 263 -262 261 -260 263 -296 229 -262 295 -236 299 -264 269 -266 231 -264 261 -262 257 -258 291 -264 267 -268 263 -236 299 -266 233 -300 231 -264 261 -264 293 -234 301 -266 233 -300 231 -296 229 -264 255 -258 291 -264 267 -234 261 -292 231 -298 265 -268 273 -268 233 -262 261 -262 257 -258 293 -262 267 -268 231 -262 295 -236 299 -266 233 -300 231 -264 261 -294 229 -264 257 -290 265 -266 231 -296 263 -234 299 -266 269 -268 231 -262 257 -256 291 -264 267 -268 231 -264 293 -234 301 -266 233 -302 229 -264 257 -258 289 -264 267 -234 261 -292 231 -298 265 -270 271 -270 231 -264 261 -262 261 -262 257 -290 265 -266 273 -238 265 -294 231 -266 259 -260 259 -294 267 -268 265 -234 299 -266 267 -268 231 -264 261 -262 261 -262 257 -292 231 -298 265 -236 299 -266 235 -300 231 -262 263 -262 295 -234 299 -266 267 -268 231 -264 257 -256 291 -262 269 -268 231 -264 293 -268 271 -270 233 -264 261 -260 257 -290 265 -266 233 -296 269 -272 235 -268 257 -256 291 -228 293 -264 267 -268 233 -262 297 -234 299 -264 235 -300 231 -264 261 -264 259 -296 229 -296 263 -234 299 -266 233 -300 231 -264 257 -290 231 -266 259 -294 265 -264 265 -236 301 -232 263 -294 267 -266 231 -262 259 -290 265 -272 269 -266 235 -300 231 -262 261 -294 231 -262 257 -292 263 -266 231 -298 263 -234 299 -266 233 -302 229 -296 229 -264 257 -288 265 -234 259 -260 291 -262 267 -274 267 -268 235 -300 229 -264 263 -262 257 -290 231 -300 263 -270 273 -268 231 -264 263 -262 257 -256 291 -262 267 -268 -RAW_Data: 265 -236 301 -264 233 -300 231 -296 229 -262 257 -258 291 -262 267 -236 259 -294 231 -298 271 -272 237 -266 263 -260 261 -262 257 -290 265 -272 269 -234 295 -264 233 -300 231 -262 263 -262 257 -290 231 -300 263 -270 273 -268 233 -264 259 -262 257 -292 265 -272 275 -270 231 -264 261 -262 255 -290 267 -234 259 -292 231 -298 265 -236 299 -266 235 -300 231 -262 257 -290 265 -232 261 -292 265 -272 267 -266 235 -300 231 -264 261 -294 229 -296 229 -264 261 -264 261 -294 261 -236 301 -266 233 -268 259 -258 259 -260 293 -264 269 -268 263 -236 301 -264 233 -300 231 -264 263 -262 257 -290 265 -264 231 -298 231 -262 293 -234 301 -266 235 -300 229 -296 231 -262 257 -256 293 -230 293 -264 267 -274 267 -266 235 -300 231 -262 257 -290 231 -298 265 -270 267 -266 235 -300 229 -264 263 -262 261 -262 257 -258 291 -264 267 -268 265 -268 271 -270 231 -262 261 -262 257 -258 293 -296 239 -276 237 -302 231 -262 255 -256 291 -264 269 -268 231 -262 293 -234 301 -264 269 -268 231 -264 261 -262 255 -258 291 -264 269 -266 265 -236 299 -264 235 -266 259 -292 231 -300 265 -234 301 -264 235 -300 231 -264 257 -256 291 -230 295 -264 233 -300 231 -264 295 -234 301 -264 235 -300 231 -262 263 -262 261 -262 257 -258 293 -262 235 -300 263 -236 299 -266 233 -302 229 -296 229 -264 257 -290 265 -270 269 -268 235 -300 231 -262 263 -262 261 -262 257 -290 265 -266 233 -264 293 -236 299 -266 235 -300 229 -264 261 -296 229 -262 263 -262 257 -290 265 -266 265 -236 299 -266 235 -300 229 -264 257 -290 233 -266 259 -292 231 -300 269 -274 235 -268 261 -262 255 -258 291 -264 267 -268 265 -234 299 -266 233 -300 231 -296 229 -264 261 -294 229 -296 229 -264 295 -268 273 -268 231 -264 287 -266 267 -270 271 -268 231 -262 261 -262 257 -290 233 -298 231 -296 231 -262 295 -270 271 -268 233 -262 261 -296 229 -296 229 -262 261 -294 263 -270 271 -236 261 -260 257 -294 267 -268 231 -264 293 -236 299 -266 235 -300 231 -262 261 -262 257 -258 293 -262 267 -268 265 -234 301 -264 235 -300 231 -294 231 -262 295 -234 299 -266 235 -300 231 -264 261 -262 255 -292 231 -300 231 -296 263 -236 299 -264 269 -266 231 -262 259 -290 229 -266 261 -292 265 -272 275 -236 261 -292 231 -298 231 -296 229 -262 295 -236 299 -266 233 -300 231 -296 231 -262 261 -294 229 -264 257 -290 231 -300 263 -270 273 -270 231 -264 261 -294 229 -262 257 -258 293 -228 -RAW_Data: 293 -264 267 -268 265 -236 299 -264 269 -266 233 -262 261 -294 231 -262 261 -264 255 -292 265 -266 265 -270 271 -268 231 -264 261 -262 257 -290 265 -234 259 -292 265 -272 267 -266 235 -302 229 -296 229 -264 257 -258 289 -230 295 -264 267 -268 265 -268 271 -270 231 -264 261 -264 255 -290 265 -272 273 -272 231 -264 261 -262 257 -290 231 -266 259 -260 293 -262 235 -300 263 -270 271 -270 231 -264 261 -262 257 -256 293 -230 295 -262 269 -272 275 -236 261 -292 229 -266 259 -292 265 -272 267 -266 235 -300 231 -296 229 -294 231 -294 229 -264 261 -294 263 -234 301 -266 235 -300 229 -296 229 -262 289 -300 241 -272 235 -264 261 -262 261 -294 229 -264 257 -258 291 -264 267 -268 265 -234 299 -266 233 -300 231 -296 229 -296 229 -262 261 -294 263 -270 267 -264 235 -300 231 -294 231 -262 261 -264 255 -292 231 -298 231 -298 263 -234 299 -232 295 -230 295 -230 295 -262 235 -300 263 -236 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 233 -298 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -298 231 -298 229 -296 261 -270 271 -268 233 -264 261 -294 261 -270 271 -270 231 -264 261 -294 229 -264 257 -290 231 -298 233 -296 263 -236 299 -264 233 -302 231 -264 261 -294 229 -296 229 -296 229 -294 263 -268 273 -234 261 -260 259 -260 293 -264 269 -266 265 -236 299 -264 235 -300 231 -264 261 -264 261 -262 255 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -264 293 -234 301 -266 233 -300 231 -296 229 -264 261 -294 229 -262 259 -290 231 -300 263 -270 267 -266 233 -300 231 -264 261 -262 255 -260 291 -296 241 -276 239 -300 229 -262 261 -262 257 -258 291 -262 267 -268 265 -234 301 -264 235 -300 233 -262 261 -294 229 -264 257 -290 231 -298 265 -270 273 -270 231 -264 255 -258 291 -262 267 -236 259 -292 231 -298 265 -236 301 -264 235 -300 231 -294 231 -262 293 -268 267 -266 235 -300 229 -296 231 -262 257 -290 231 -266 259 -294 231 -300 231 -296 263 -268 271 -268 233 -262 263 -294 229 -262 259 -290 229 -266 261 -292 231 -300 263 -270 273 -268 233 -264 261 -260 257 -258 293 -262 267 -272 275 -270 233 -262 257 -258 289 -230 295 -264 267 -268 265 -234 299 -266 233 -302 231 -264 261 -260 257 -292 231 -298 231 -298 229 -296 263 -268 271 -268 233 -264 257 -256 259 -294 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 261 -294 229 -296 229 -296 263 -234 299 -264 269 -266 -RAW_Data: 233 -262 257 -290 263 -272 269 -266 235 -302 229 -296 231 -262 257 -256 291 -264 267 -234 261 -292 263 -272 269 -266 235 -300 229 -264 257 -290 231 -298 233 -296 231 -262 293 -268 267 -266 235 -300 231 -262 257 -290 231 -298 233 -264 257 -292 263 -272 275 -236 263 -258 259 -292 267 -268 231 -264 295 -234 299 -264 269 -268 231 -264 261 -262 255 -292 231 -266 259 -294 231 -300 231 -296 263 -234 299 -266 233 -300 231 -264 261 -294 231 -294 231 -262 261 -294 263 -268 273 -268 233 -264 261 -262 255 -292 231 -298 265 -270 273 -270 231 -264 261 -260 257 -258 293 -262 235 -300 265 -270 271 -268 231 -264 261 -294 229 -264 257 -290 231 -300 271 -272 237 -266 263 -260 261 -262 257 -258 293 -262 235 -300 265 -270 271 -268 231 -264 261 -262 257 -258 291 -264 267 -268 265 -234 299 -266 233 -300 231 -296 229 -264 293 -268 267 -266 233 -300 231 -296 229 -296 229 -262 257 -292 231 -266 259 -292 265 -272 267 -268 233 -302 231 -262 257 -256 291 -230 295 -304 243 -274 235 -264 257 -256 289 -262 269 -234 261 -292 231 -298 265 -268 267 -266 235 -298 231 -264 261 -262 257 -258 291 -264 267 -268 265 -268 271 -268 233 -264 261 -294 229 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -298 229 -262 261 -294 263 -234 301 -266 235 -300 231 -262 263 -262 255 -292 231 -300 231 -296 231 -262 295 -232 299 -266 269 -266 233 -262 261 -296 229 -262 257 -292 231 -298 231 -298 263 -268 271 -268 233 -264 261 -262 257 -290 265 -272 267 -268 233 -300 231 -264 257 -258 289 -264 267 -234 261 -292 231 -298 265 -236 299 -266 235 -298 231 -264 257 -258 291 -262 267 -268 265 -268 273 -268 231 -264 257 -256 293 -262 233 -302 263 -236 299 -266 233 -300 231 -298 229 -262 261 -294 229 -296 231 -262 293 -268 267 -266 235 -300 231 -262 263 -294 263 -268 267 -266 233 -300 231 -262 257 -292 231 -298 231 -298 229 -296 261 -268 267 -264 235 -300 231 -264 261 -294 229 -264 257 -290 265 -272 273 -272 233 -262 257 -258 257 -294 267 -268 233 -264 293 -234 299 -266 267 -268 231 -264 257 -256 291 -230 295 -264 267 -274 267 -266 235 -300 231 -294 229 -296 229 -264 255 -258 291 -264 267 -274 267 -234 263 -294 233 -300 231 -298 229 -262 261 -294 263 -268 273 -270 231 -264 261 -294 229 -262 259 -290 231 -298 231 -298 229 -296 261 -270 271 -268 231 -298 229 -262 257 -258 291 -262 267 -266 233 -296 263 -234 299 -266 -RAW_Data: 233 -300 231 -296 231 -262 257 -256 291 -264 233 -300 271 -274 235 -268 261 -262 259 -262 257 -292 231 -266 259 -294 231 -298 265 -270 267 -266 233 -300 231 -262 257 -292 231 -298 231 -296 263 -236 299 -264 235 -302 231 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -264 261 -262 255 -292 231 -300 265 -268 267 -266 235 -300 231 -262 257 -258 291 -230 293 -264 235 -300 265 -236 299 -264 233 -302 229 -298 229 -262 261 -262 257 -258 291 -264 233 -300 265 -270 271 -270 231 -264 261 -262 255 -292 231 -300 231 -264 257 -292 231 -298 265 -236 299 -264 269 -266 233 -262 261 -296 229 -262 257 -292 231 -298 231 -298 261 -270 271 -268 233 -264 261 -262 255 -258 293 -262 267 -274 275 -270 231 -264 261 -294 229 -262 257 -258 259 -296 267 -266 267 -234 299 -266 233 -300 231 -264 257 -256 293 -262 267 -268 265 -236 299 -230 295 -230 295 -264 233 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -298 233 -296 263 -236 299 -264 235 -300 231 -262 257 -258 293 -268 271 -270 237 -302 231 -262 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -262 257 -292 231 -298 265 -236 301 -264 233 -300 231 -296 231 -262 257 -290 231 -266 259 -292 265 -272 269 -266 235 -300 231 -294 229 -296 229 -296 229 -296 229 -294 229 -264 293 -268 273 -268 233 -264 261 -262 255 -292 231 -298 265 -270 273 -270 231 -264 261 -260 257 -258 293 -262 235 -300 233 -262 295 -234 299 -266 235 -300 231 -294 229 -296 229 -296 229 -262 257 -292 231 -298 265 -236 299 -266 235 -300 229 -296 231 -262 261 -262 257 -290 231 -300 265 -270 271 -236 261 -292 231 -298 231 -296 231 -262 293 -268 267 -266 235 -300 231 -262 261 -296 229 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -262 257 -292 231 -298 231 -298 263 -268 271 -270 231 -264 261 -262 255 -292 231 -266 291 -302 239 -274 235 -264 261 -262 255 -292 231 -298 231 -298 229 -296 263 -234 299 -264 235 -300 231 -264 257 -258 291 -262 267 -268 231 -296 263 -234 299 -266 233 -302 231 -264 261 -262 255 -260 291 -262 235 -300 233 -262 295 -234 297 -266 269 -268 231 -264 255 -290 265 -272 267 -268 235 -300 231 -262 261 -296 229 -262 257 -258 261 -294 267 -266 267 -234 299 -266 235 -300 -RAW_Data: 231 -262 263 -262 255 -292 231 -266 259 -292 233 -298 265 -270 271 -270 231 -262 261 -262 257 -292 265 -272 269 -266 235 -300 231 -294 229 -264 257 -258 257 -294 269 -266 233 -264 295 -232 299 -266 235 -300 231 -264 257 -290 231 -266 259 -294 265 -272 273 -238 259 -292 231 -266 259 -292 231 -300 263 -236 301 -266 233 -300 231 -296 229 -262 261 -294 231 -262 257 -292 265 -270 269 -266 235 -300 231 -262 259 -290 229 -300 265 -270 271 -270 231 -264 257 -290 231 -266 259 -292 233 -298 231 -296 263 -268 273 -268 231 -296 231 -262 257 -290 231 -298 231 -296 271 -272 235 -266 259 -256 259 -260 293 -264 269 -268 265 -234 299 -266 233 -300 231 -296 229 -264 255 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -296 229 -264 255 -290 233 -298 265 -270 265 -266 235 -300 231 -294 229 -296 229 -296 263 -268 271 -268 233 -264 261 -262 255 -290 265 -234 261 -292 231 -300 231 -296 263 -268 271 -268 233 -264 261 -294 229 -264 257 -290 231 -266 259 -292 233 -298 265 -270 271 -270 231 -264 261 -260 257 -292 231 -298 233 -296 269 -272 235 -300 229 -262 261 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 229 -264 255 -290 231 -300 231 -298 263 -234 299 -232 295 -230 295 -262 235 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -262 257 -258 291 -264 267 -272 269 -266 235 -300 231 -294 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -258 259 -292 269 -234 261 -292 231 -298 265 -270 271 -270 231 -262 261 -296 229 -296 229 -296 229 -294 263 -268 273 -268 231 -264 257 -256 291 -264 233 -268 259 -292 231 -300 263 -270 267 -232 263 -262 293 -230 295 -262 235 -300 263 -236 301 -266 233 -300 229 -296 231 -262 257 -290 231 -266 259 -294 231 -300 263 -236 299 -232 295 -264 233 -300 231 -296 231 -262 257 -256 291 -264 233 -300 265 -236 301 -266 233 -300 231 -262 257 -290 231 -300 265 -268 273 -270 231 -264 261 -262 255 -292 231 -266 259 -294 231 -300 263 -236 299 -266 233 -300 231 -296 229 -264 257 -258 259 -328 239 -276 239 -300 231 -262 255 -258 291 -262 235 -300 265 -236 299 -232 293 -264 233 -302 231 -264 261 -262 257 -258 291 -262 267 -268 265 -268 273 -268 231 -264 257 -290 231 -298 265 -270 271 -270 231 -264 261 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -264 257 -290 231 -300 231 -296 269 -272 235 -268 257 -256 -RAW_Data: 259 -260 293 -264 269 -268 231 -264 293 -268 267 -266 235 -300 229 -264 257 -290 231 -300 231 -296 229 -296 263 -268 271 -268 233 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -234 301 -264 267 -268 231 -264 255 -290 231 -300 265 -268 267 -266 235 -300 231 -294 231 -262 257 -290 231 -298 231 -298 229 -296 263 -234 299 -266 233 -302 231 -264 259 -296 229 -262 257 -260 257 -294 267 -268 265 -270 271 -268 233 -296 229 -262 261 -296 229 -296 263 -268 271 -268 233 -296 229 -262 257 -290 231 -266 259 -292 231 -300 265 -268 267 -266 235 -300 231 -294 229 -264 255 -290 231 -268 261 -292 231 -298 271 -274 235 -266 259 -288 231 -298 265 -236 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -294 265 -272 267 -266 235 -300 231 -262 257 -292 265 -270 269 -266 235 -300 231 -296 229 -264 259 -262 257 -292 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 229 -294 231 -262 257 -290 231 -300 263 -270 273 -268 233 -262 261 -296 229 -294 229 -264 257 -258 259 -294 267 -268 265 -270 271 -268 233 -262 257 -258 291 -262 235 -300 231 -296 263 -234 299 -266 233 -300 231 -298 229 -262 261 -294 229 -264 257 -292 229 -300 265 -236 299 -266 235 -300 231 -262 261 -262 257 -258 291 -264 267 -268 265 -234 299 -266 235 -266 259 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 229 -264 257 -290 231 -266 259 -292 267 -270 269 -266 235 -300 231 -262 257 -258 259 -260 295 -304 243 -274 235 -266 255 -258 257 -294 267 -234 261 -292 231 -300 263 -236 301 -266 233 -300 229 -264 257 -258 259 -260 295 -262 269 -268 265 -268 273 -236 259 -292 231 -298 231 -296 263 -270 271 -268 231 -296 231 -262 261 -294 229 -296 229 -264 293 -268 267 -266 233 -302 231 -262 261 -296 229 -296 263 -268 271 -268 233 -296 229 -262 257 -290 231 -266 259 -260 291 -262 267 -268 265 -270 271 -270 231 -264 261 -294 229 -294 231 -294 229 -296 263 -268 271 -270 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 231 -296 263 -234 299 -232 295 -230 295 -264 233 -300 265 -234 299 -266 233 -300 231 -298 229 -262 261 -294 229 -264 257 -290 231 -300 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -228 295 -264 267 -268 265 -270 271 -268 231 -264 261 -294 229 -296 229 -264 293 -268 273 -268 233 -264 261 -262 261 -262 257 -292 231 -298 233 -296 263 -234 299 -266 233 -302 231 -262 261 -296 229 -262 -RAW_Data: 257 -292 263 -272 275 -236 263 -292 229 -266 259 -292 265 -272 267 -266 235 -300 231 -264 261 -262 257 -258 291 -230 295 -264 267 -274 267 -266 233 -300 231 -264 257 -290 265 -272 267 -268 235 -300 231 -294 229 -264 257 -290 231 -300 231 -262 259 -290 231 -300 265 -236 299 -264 235 -300 231 -296 229 -264 261 -262 257 -258 291 -262 235 -300 265 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -300 263 -270 273 -268 233 -264 261 -262 257 -290 231 -298 233 -296 231 -262 293 -270 265 -266 235 -300 231 -264 261 -294 229 -264 257 -258 257 -294 269 -266 233 -296 263 -234 299 -264 235 -300 231 -264 257 -290 231 -298 233 -296 263 -236 299 -230 295 -264 235 -266 259 -292 231 -298 265 -268 267 -266 235 -300 231 -264 261 -294 229 -262 257 -258 293 -262 267 -272 269 -266 235 -300 231 -264 257 -256 291 -270 271 -270 237 -300 231 -296 229 -296 229 -262 257 -258 259 -294 267 -268 265 -234 301 -264 235 -300 231 -262 257 -258 259 -294 267 -268 233 -296 269 -236 265 -294 231 -266 259 -292 231 -300 265 -268 273 -268 233 -294 229 -294 231 -294 231 -294 229 -296 229 -296 263 -234 299 -264 235 -300 231 -264 257 -258 259 -262 293 -264 267 -274 267 -268 233 -300 231 -296 229 -262 257 -258 291 -230 295 -264 233 -300 265 -234 299 -266 233 -302 231 -264 259 -296 229 -262 257 -292 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 231 -300 263 -236 301 -266 233 -300 231 -262 257 -258 291 -262 269 -272 275 -270 231 -264 261 -262 255 -260 291 -262 235 -300 231 -296 263 -234 299 -266 233 -300 231 -296 229 -264 257 -258 291 -262 267 -274 269 -266 235 -300 231 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -294 231 -262 257 -290 231 -300 263 -270 267 -266 235 -300 231 -262 261 -294 229 -296 263 -268 271 -270 231 -264 261 -294 229 -264 257 -290 231 -300 231 -298 261 -270 271 -268 231 -264 257 -290 231 -298 231 -298 229 -296 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 263 -270 267 -266 235 -300 229 -296 229 -264 257 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 229 -296 229 -264 255 -260 259 -294 267 -268 263 -236 299 -266 233 -300 231 -296 231 -262 257 -290 231 -298 231 -298 231 -262 293 -268 267 -266 235 -300 231 -262 263 -294 229 -262 257 -290 233 -298 265 -270 265 -266 235 -300 231 -294 231 -294 229 -264 257 -290 -RAW_Data: 231 -300 263 -270 267 -266 233 -300 231 -264 261 -294 229 -296 263 -268 273 -268 231 -264 261 -262 257 -258 291 -262 267 -268 231 -296 263 -236 299 -264 235 -300 231 -264 257 -290 231 -298 231 -298 229 -264 293 -268 273 -268 233 -262 257 -290 231 -298 265 -270 267 -266 235 -300 229 -264 257 -290 231 -264 261 -292 233 -298 265 -270 271 -270 231 -264 261 -262 255 -258 293 -302 243 -274 235 -266 261 -262 255 -258 291 -262 235 -268 259 -292 231 -298 265 -236 301 -266 233 -300 229 -264 257 -258 259 -294 267 -268 265 -236 299 -264 233 -302 231 -264 261 -262 257 -258 291 -230 293 -264 269 -266 265 -236 299 -232 293 -264 233 -302 231 -296 263 -234 299 -264 233 -302 231 -264 261 -262 257 -290 231 -300 231 -264 257 -292 231 -298 265 -268 267 -266 235 -300 231 -294 231 -262 257 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -292 231 -298 265 -270 271 -270 231 -264 261 -262 255 -292 231 -266 259 -294 231 -300 231 -296 263 -268 271 -268 233 -262 257 -258 259 -294 267 -268 231 -298 267 -272 235 -268 257 -290 229 -300 231 -296 231 -262 295 -268 271 -270 231 -264 257 -290 231 -264 261 -292 265 -272 267 -268 235 -300 229 -296 229 -296 229 -296 263 -234 299 -266 233 -300 231 -296 229 -296 229 -296 229 -262 257 -290 231 -300 263 -270 273 -270 231 -264 261 -294 229 -262 259 -290 231 -298 271 -274 237 -266 261 -262 261 -294 229 -296 263 -234 299 -266 233 -302 231 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -294 231 -300 263 -236 301 -232 263 -294 233 -300 231 -296 229 -296 229 -296 229 -262 257 -290 265 -272 267 -268 233 -302 231 -262 261 -262 257 -290 233 -298 231 -298 263 -234 301 -264 233 -300 231 -296 231 -262 257 -290 231 -266 259 -294 265 -272 267 -268 233 -300 231 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 231 -296 263 -268 271 -270 231 -264 261 -294 229 -264 257 -290 231 -300 271 -274 235 -266 257 -258 257 -294 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 257 -288 231 -300 231 -296 263 -270 271 -268 233 -264 261 -262 257 -290 265 -272 267 -268 235 -300 231 -294 229 -296 229 -264 255 -292 231 -300 231 -296 263 -268 271 -268 233 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -264 261 -294 229 -264 257 -290 -RAW_Data: 231 -300 231 -296 263 -268 273 -268 231 -264 261 -294 229 -296 229 -296 263 -234 299 -266 267 -268 231 -264 261 -294 229 -262 259 -258 259 -294 267 -268 265 -234 299 -266 233 -300 231 -298 229 -262 261 -294 229 -264 257 -292 263 -272 269 -266 235 -300 231 -264 261 -294 229 -296 263 -234 299 -266 233 -302 231 -264 261 -262 255 -292 231 -300 231 -296 263 -236 297 -266 235 -300 231 -262 259 -290 229 -300 231 -298 269 -272 235 -266 259 -256 257 -294 267 -236 259 -292 231 -300 263 -236 301 -266 233 -300 231 -294 231 -294 229 -296 229 -296 229 -294 263 -268 273 -268 231 -264 263 -294 227 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -300 265 -270 267 -264 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 231 -300 263 -236 299 -266 235 -300 231 -296 229 -262 261 -262 257 -290 233 -298 265 -270 267 -266 233 -300 231 -262 257 -258 291 -262 269 -234 261 -290 231 -300 263 -236 301 -266 233 -300 231 -294 229 -264 257 -256 293 -262 235 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -300 231 -296 269 -272 235 -300 229 -262 261 -294 231 -294 231 -294 263 -268 265 -266 235 -300 231 -264 261 -262 255 -260 291 -262 269 -272 269 -266 235 -300 229 -296 229 -264 259 -296 261 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -268 231 -264 295 -268 271 -270 231 -264 263 -260 257 -258 291 -296 241 -276 237 -302 229 -264 255 -288 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -270 265 -266 235 -300 231 -294 231 -294 263 -234 299 -266 233 -302 231 -264 261 -262 255 -292 231 -300 231 -264 257 -290 265 -272 273 -272 233 -262 261 -294 229 -296 229 -264 255 -292 231 -298 265 -270 267 -266 233 -300 231 -262 257 -292 231 -298 231 -264 291 -264 275 -272 235 -264 261 -262 261 -294 229 -296 229 -296 263 -234 299 -266 235 -300 231 -296 229 -262 257 -258 291 -230 295 -264 233 -300 265 -234 299 -232 295 -264 267 -266 233 -262 261 -262 257 -258 291 -264 267 -268 265 -268 273 -268 231 -264 257 -290 229 -300 265 -270 265 -266 235 -300 231 -296 229 -262 261 -296 229 -262 257 -292 265 -272 267 -266 235 -300 231 -296 229 -296 229 -262 289 -298 241 -272 235 -264 263 -260 261 -262 257 -292 231 -298 233 -296 231 -294 263 -268 273 -268 231 -296 229 -264 259 -262 257 -292 231 -298 265 -270 273 -236 261 -258 -RAW_Data: 257 -294 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 255 -292 231 -298 231 -298 261 -236 299 -264 235 -302 231 -264 259 -262 257 -292 231 -298 233 -296 231 -262 293 -268 267 -266 235 -300 229 -296 229 -296 229 -296 229 -294 263 -234 301 -264 235 -300 231 -294 231 -294 229 -264 257 -290 231 -300 231 -296 263 -234 299 -266 233 -302 229 -298 229 -262 257 -290 231 -266 261 -260 259 -292 267 -274 269 -266 235 -300 231 -262 257 -290 233 -298 231 -296 269 -272 237 -266 263 -262 259 -296 229 -296 229 -294 231 -294 263 -234 299 -266 235 -300 231 -262 257 -292 229 -300 231 -298 229 -262 295 -268 271 -270 233 -264 257 -288 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -292 231 -266 259 -292 231 -300 265 -268 273 -268 233 -262 261 -262 257 -290 265 -272 269 -266 235 -300 231 -296 229 -264 261 -260 257 -292 231 -298 265 -270 267 -266 235 -300 229 -264 257 -256 293 -262 235 -300 263 -236 301 -266 233 -268 257 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 229 -296 229 -264 255 -292 231 -300 263 -270 267 -266 233 -300 231 -264 261 -262 257 -258 291 -262 267 -272 269 -268 233 -302 229 -296 229 -296 229 -262 257 -258 291 -268 271 -272 237 -302 231 -262 261 -294 229 -264 255 -292 231 -300 231 -296 263 -234 299 -266 233 -300 231 -264 257 -258 259 -296 267 -234 259 -292 231 -300 263 -236 299 -266 233 -302 231 -264 255 -258 291 -230 293 -264 269 -266 265 -270 271 -236 259 -292 229 -266 261 -292 231 -298 265 -236 301 -266 233 -300 229 -296 229 -264 255 -292 231 -300 231 -296 263 -268 273 -268 231 -296 229 -264 261 -294 263 -234 301 -266 233 -300 231 -296 229 -294 231 -262 257 -290 231 -298 233 -296 263 -268 271 -270 231 -266 261 -260 257 -290 231 -300 231 -298 269 -272 235 -266 257 -290 231 -266 259 -292 265 -272 267 -268 233 -300 231 -298 229 -262 261 -262 257 -290 231 -300 265 -270 273 -268 231 -264 261 -262 257 -258 291 -264 233 -302 231 -262 295 -234 299 -266 233 -302 231 -264 261 -294 229 -296 229 -264 255 -292 265 -272 267 -266 235 -300 231 -264 261 -262 257 -290 231 -300 231 -264 257 -290 231 -300 265 -236 301 -264 235 -298 231 -298 229 -262 257 -258 291 -230 295 -262 269 -272 267 -266 235 -300 231 -264 261 -294 229 -296 263 -234 299 -266 235 -300 231 -262 257 -290 231 -266 261 -292 231 -300 231 -296 263 -268 271 -270 231 -264 261 -294 229 -296 -RAW_Data: 229 -296 229 -294 263 -268 267 -232 263 -294 233 -300 231 -296 263 -236 299 -232 295 -264 233 -300 231 -296 229 -262 257 -258 291 -262 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 293 -268 267 -266 233 -300 231 -296 229 -262 257 -258 259 -296 267 -266 265 -236 299 -264 235 -300 231 -264 257 -258 291 -262 235 -300 265 -268 273 -236 259 -292 231 -298 231 -296 229 -296 263 -234 299 -266 235 -300 231 -294 229 -264 257 -290 231 -300 231 -296 263 -234 301 -266 233 -300 231 -262 257 -258 259 -262 293 -264 269 -268 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 231 -294 263 -268 265 -266 235 -300 231 -296 229 -262 261 -262 257 -258 293 -262 235 -300 265 -236 299 -264 235 -300 231 -262 257 -258 291 -262 267 -268 231 -296 269 -272 235 -300 229 -264 255 -258 291 -262 235 -300 265 -234 299 -266 235 -300 231 -264 261 -294 229 -296 229 -296 229 -262 295 -234 301 -264 235 -300 231 -296 229 -262 295 -268 267 -232 261 -296 267 -266 233 -264 255 -290 231 -268 259 -292 231 -300 265 -268 273 -268 233 -262 261 -294 231 -296 229 -294 269 -272 235 -300 229 -262 261 -262 257 -290 233 -298 265 -270 265 -266 235 -300 231 -294 229 -264 257 -258 289 -262 269 -268 265 -234 299 -266 233 -300 231 -296 231 -294 263 -268 271 -270 231 -264 261 -294 229 -296 229 -264 257 -290 231 -298 265 -270 271 -270 233 -264 261 -260 257 -258 291 -230 295 -264 267 -272 269 -266 235 -300 229 -296 231 -262 261 -262 257 -258 291 -264 233 -300 265 -270 271 -270 231 -262 257 -258 291 -262 267 -268 233 -264 293 -234 299 -264 269 -268 231 -264 261 -262 257 -290 231 -266 261 -258 261 -294 267 -266 267 -234 299 -266 233 -302 231 -264 255 -258 291 -264 233 -300 231 -296 263 -268 273 -234 261 -292 231 -266 259 -292 263 -272 269 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 231 -300 263 -270 273 -268 231 -264 261 -262 257 -258 291 -304 241 -276 233 -266 261 -262 255 -290 231 -266 261 -292 231 -300 263 -270 267 -266 235 -300 229 -264 261 -262 257 -258 291 -262 269 -266 265 -270 271 -236 259 -292 231 -298 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -292 231 -298 231 -298 263 -268 271 -268 233 -296 229 -264 259 -296 261 -270 271 -270 231 -264 261 -294 229 -296 229 -264 255 -292 231 -298 233 -296 263 -234 299 -266 -RAW_Data: 233 -300 231 -298 229 -262 261 -262 257 -290 265 -272 269 -266 235 -302 229 -264 261 -294 229 -264 257 -290 231 -300 231 -298 263 -234 299 -230 295 -232 293 -230 295 -264 233 -300 263 -236 301 -266 233 -300 231 -296 229 -294 229 -264 255 -292 231 -298 233 -296 263 -234 299 -266 233 -302 231 -264 261 -262 257 -258 291 -230 293 -264 267 -268 265 -234 299 -266 235 -300 231 -262 257 -290 231 -300 265 -236 301 -264 235 -300 229 -264 257 -290 231 -298 233 -296 231 -262 293 -268 273 -268 233 -264 261 -294 229 -264 257 -290 231 -300 271 -240 265 -294 231 -298 231 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -268 231 -298 261 -268 271 -270 231 -264 257 -290 263 -272 269 -266 235 -300 231 -296 231 -262 261 -262 257 -290 231 -266 261 -292 265 -272 267 -268 235 -300 229 -264 257 -258 257 -262 293 -264 269 -266 265 -236 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 265 -272 267 -268 235 -302 229 -264 255 -290 231 -300 233 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -268 231 -296 263 -234 299 -266 233 -300 231 -264 257 -290 231 -300 231 -296 231 -294 263 -268 271 -270 231 -264 257 -258 257 -294 267 -268 265 -236 301 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -268 271 -270 231 -264 261 -296 261 -236 299 -232 295 -264 233 -300 231 -296 229 -262 257 -290 231 -300 231 -296 231 -296 261 -268 271 -270 231 -266 261 -260 257 -290 265 -266 233 -296 269 -272 235 -300 229 -262 257 -256 291 -264 233 -300 265 -268 273 -268 233 -264 259 -296 229 -296 229 -262 261 -296 261 -270 265 -266 235 -300 231 -296 229 -264 293 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -264 257 -292 263 -272 269 -266 235 -300 231 -296 229 -264 255 -290 231 -300 265 -236 299 -234 261 -296 233 -298 231 -264 257 -292 231 -266 259 -260 259 -294 267 -274 273 -238 261 -258 259 -294 267 -266 233 -296 261 -236 297 -266 267 -268 231 -264 261 -262 255 -292 231 -300 231 -296 231 -296 261 -236 299 -230 295 -264 233 -300 231 -296 231 -262 257 -290 231 -266 259 -294 265 -272 267 -266 235 -268 259 -258 257 -294 267 -268 265 -236 301 -264 233 -300 231 -298 229 -262 261 -262 257 -290 231 -300 265 -270 273 -268 231 -264 261 -262 257 -258 291 -296 241 -276 237 -302 229 -264 259 -262 257 -290 231 -298 -RAW_Data: 233 -296 263 -236 299 -230 295 -264 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -270 271 -234 261 -292 231 -298 231 -296 263 -236 299 -264 235 -300 231 -264 257 -258 291 -262 235 -300 231 -296 263 -234 299 -264 235 -300 231 -296 229 -264 255 -290 233 -266 259 -292 233 -298 265 -236 299 -266 233 -300 231 -296 231 -262 257 -290 231 -298 265 -270 273 -268 231 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -236 297 -266 235 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 229 -298 261 -270 271 -268 233 -264 261 -294 229 -264 255 -292 231 -300 271 -272 237 -266 257 -258 257 -294 267 -268 231 -296 263 -236 299 -264 233 -300 231 -298 229 -294 231 -262 257 -290 231 -300 263 -236 301 -266 233 -300 231 -296 229 -264 293 -268 267 -266 233 -300 231 -296 229 -296 229 -262 261 -262 257 -292 231 -298 265 -270 273 -268 231 -298 229 -262 261 -294 229 -296 261 -270 271 -270 231 -264 257 -258 259 -260 295 -262 269 -266 265 -236 299 -264 235 -302 231 -262 261 -294 229 -296 231 -294 263 -234 299 -266 235 -300 231 -296 229 -296 261 -268 265 -234 261 -296 267 -266 233 -264 261 -294 229 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -262 257 -292 231 -298 231 -296 231 -294 263 -234 299 -266 235 -300 231 -296 229 -262 257 -258 291 -262 267 -274 275 -270 231 -264 257 -290 229 -266 261 -260 259 -294 267 -268 265 -234 299 -266 235 -300 231 -296 229 -296 229 -262 261 -262 257 -290 231 -300 265 -236 301 -266 233 -300 231 -296 229 -262 261 -294 229 -296 231 -294 263 -268 271 -236 261 -260 259 -260 293 -264 267 -274 267 -234 263 -294 233 -300 231 -298 229 -262 257 -290 231 -298 231 -298 263 -268 273 -268 231 -296 229 -264 261 -294 263 -268 273 -268 233 -262 261 -262 257 -258 291 -262 267 -234 261 -292 233 -298 265 -234 301 -266 233 -300 231 -262 257 -292 231 -264 261 -292 265 -272 275 -270 231 -264 255 -258 291 -264 267 -272 269 -266 235 -300 231 -294 229 -296 229 -264 255 -290 231 -300 265 -236 301 -266 233 -300 231 -294 229 -296 231 -262 257 -256 291 -264 233 -302 265 -234 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 269 -266 265 -270 271 -268 233 -262 261 -262 257 -290 231 -268 259 -260 259 -294 267 -268 265 -236 299 -264 235 -300 231 -264 261 -262 257 -290 231 -300 231 -296 231 -262 295 -268 271 -270 231 -264 261 -262 257 -258 291 -264 267 -272 -RAW_Data: 275 -270 231 -264 255 -290 231 -266 259 -294 231 -300 231 -296 263 -234 299 -266 235 -300 231 -262 257 -258 259 -294 267 -268 265 -236 299 -232 295 -262 235 -300 231 -296 263 -234 299 -232 295 -264 233 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -262 289 -266 269 -268 271 -268 231 -264 259 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 229 -296 229 -262 257 -292 263 -272 269 -266 235 -300 231 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -266 259 -294 265 -272 267 -268 233 -300 231 -296 229 -294 231 -262 257 -290 231 -300 231 -296 263 -236 297 -266 235 -300 231 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -262 257 -258 291 -230 295 -262 235 -300 265 -236 299 -264 235 -300 231 -296 229 -264 261 -260 257 -292 231 -266 259 -294 231 -300 263 -270 273 -268 231 -264 261 -294 229 -262 257 -292 231 -298 231 -298 269 -272 235 -266 263 -262 255 -290 233 -298 231 -298 229 -264 293 -268 267 -266 233 -300 231 -264 255 -292 231 -300 231 -296 263 -234 299 -266 233 -300 231 -264 257 -292 263 -272 267 -234 295 -264 267 -266 233 -296 227 -262 257 -258 291 -230 295 -264 235 -300 263 -236 299 -266 233 -300 231 -264 257 -290 231 -300 231 -296 231 -262 295 -268 265 -266 235 -300 231 -294 229 -264 257 -290 231 -298 233 -296 263 -270 271 -268 231 -296 231 -262 257 -290 231 -266 259 -292 231 -300 231 -296 263 -268 273 -268 231 -296 231 -262 257 -256 291 -262 267 -234 261 -292 231 -300 263 -270 273 -268 231 -264 261 -262 257 -290 231 -300 233 -296 267 -272 235 -268 257 -290 231 -298 231 -296 231 -296 261 -268 265 -266 235 -300 231 -296 229 -264 255 -258 291 -262 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 293 -268 267 -266 233 -300 231 -264 261 -262 257 -292 231 -298 233 -264 257 -290 265 -270 269 -266 235 -300 231 -264 255 -260 259 -260 295 -304 243 -274 235 -264 257 -288 231 -298 231 -298 229 -296 263 -234 299 -266 233 -302 231 -264 259 -262 257 -258 293 -262 267 -266 267 -268 273 -268 231 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -264 261 -294 229 -296 229 -296 229 -294 263 -234 299 -266 235 -300 231 -296 229 -264 259 -262 257 -292 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 229 -262 257 -258 291 -302 243 -274 235 -266 261 -262 261 -262 257 -258 -RAW_Data: 291 -262 267 -268 265 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -262 267 -268 231 -298 261 -236 297 -266 235 -300 231 -296 229 -262 261 -262 257 -292 231 -298 265 -270 273 -268 233 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -262 261 -296 229 -296 229 -296 261 -270 271 -268 231 -296 231 -262 261 -262 289 -300 239 -274 235 -264 261 -262 261 -262 257 -290 265 -266 233 -296 229 -264 293 -234 299 -266 235 -300 231 -296 229 -264 261 -294 229 -296 263 -268 271 -268 233 -264 257 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 229 -264 255 -258 291 -264 267 -268 231 -264 293 -234 299 -266 235 -300 231 -296 229 -264 255 -292 231 -266 259 -292 231 -300 263 -270 267 -266 235 -300 229 -264 257 -290 265 -272 267 -268 233 -300 231 -264 257 -258 291 -228 295 -264 267 -268 265 -234 299 -266 233 -302 231 -262 261 -262 257 -292 231 -298 231 -264 259 -290 231 -298 265 -270 267 -266 235 -300 229 -264 257 -290 231 -298 231 -298 263 -268 273 -268 231 -264 255 -290 231 -300 231 -264 259 -290 231 -298 265 -270 267 -264 235 -300 231 -262 257 -292 231 -298 231 -296 263 -236 299 -232 295 -230 261 -296 267 -268 231 -296 263 -234 299 -264 235 -300 231 -264 261 -294 229 -264 257 -258 259 -294 267 -274 269 -266 235 -300 229 -264 257 -258 291 -268 271 -270 237 -304 231 -262 261 -294 229 -262 257 -290 231 -300 265 -236 301 -266 233 -300 231 -262 257 -258 291 -230 295 -262 235 -300 265 -268 273 -236 259 -292 231 -298 231 -296 229 -296 263 -268 271 -268 233 -264 261 -294 229 -264 257 -290 231 -298 233 -296 263 -270 271 -268 231 -296 231 -262 257 -256 291 -262 267 -268 231 -298 261 -270 271 -268 231 -264 261 -262 257 -258 293 -262 267 -274 273 -270 233 -262 261 -262 257 -258 291 -264 233 -300 231 -296 263 -234 299 -266 235 -300 233 -262 261 -262 257 -290 231 -268 259 -292 231 -300 265 -234 301 -266 233 -300 231 -296 229 -264 255 -258 291 -262 267 -268 265 -270 271 -236 259 -260 259 -260 293 -264 267 -268 233 -262 295 -268 265 -266 235 -300 231 -264 261 -294 229 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -264 257 -290 231 -298 265 -270 265 -266 235 -300 231 -294 231 -294 229 -264 257 -290 231 -298 265 -236 301 -266 233 -300 231 -294 231 -294 231 -262 295 -268 271 -270 231 -264 261 -294 229 -296 229 -264 255 -292 231 -300 231 -296 263 -268 -RAW_Data: 271 -270 231 -296 229 -264 259 -296 229 -296 229 -294 263 -270 271 -268 231 -296 231 -262 257 -290 231 -266 259 -292 233 -298 231 -296 263 -236 299 -232 295 -230 293 -262 235 -300 265 -270 271 -268 233 -294 229 -294 229 -264 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -264 261 -294 229 -296 263 -236 299 -264 233 -302 231 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -234 301 -266 233 -300 231 -296 229 -264 261 -262 257 -290 265 -272 273 -238 261 -292 231 -298 231 -296 229 -296 261 -268 267 -266 233 -300 231 -264 261 -262 257 -258 291 -230 293 -264 269 -272 269 -266 233 -300 231 -296 229 -264 261 -294 263 -268 273 -268 233 -262 263 -262 255 -258 293 -230 293 -264 233 -302 263 -270 273 -268 231 -264 257 -256 291 -262 267 -268 231 -298 267 -238 265 -294 231 -300 231 -262 259 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 261 -294 231 -294 231 -294 263 -268 273 -268 231 -296 231 -262 257 -288 231 -300 231 -296 231 -296 261 -236 299 -264 235 -300 231 -296 229 -264 261 -294 263 -268 271 -270 233 -262 261 -262 257 -292 231 -266 259 -260 259 -296 233 -300 265 -234 299 -266 233 -302 231 -264 261 -262 255 -258 293 -262 269 -266 233 -262 295 -268 271 -270 231 -264 261 -262 257 -290 231 -300 231 -298 269 -272 235 -300 229 -262 257 -288 231 -300 231 -296 231 -262 295 -268 265 -266 235 -300 231 -294 231 -294 231 -294 229 -296 263 -234 299 -266 233 -300 231 -264 261 -294 263 -236 299 -232 295 -264 233 -300 231 -296 229 -264 255 -290 231 -268 259 -292 265 -272 269 -266 235 -300 229 -296 229 -296 229 -296 261 -270 271 -268 231 -296 231 -262 261 -294 229 -264 257 -290 231 -298 233 -296 263 -268 273 -268 231 -264 257 -290 231 -298 233 -296 231 -262 293 -268 273 -268 233 -264 261 -262 257 -290 231 -298 233 -296 231 -294 229 -264 293 -268 267 -266 235 -266 259 -260 257 -294 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 255 -258 291 -264 267 -268 231 -264 293 -234 299 -266 235 -300 231 -264 257 -258 257 -294 267 -274 269 -268 233 -300 231 -296 229 -294 231 -294 229 -264 255 -292 265 -270 269 -266 235 -300 231 -296 229 -262 257 -258 259 -328 241 -276 239 -268 263 -260 261 -262 257 -290 -RAW_Data: 231 -300 265 -268 267 -234 261 -296 231 -300 233 -264 257 -258 257 -262 293 -264 269 -266 265 -270 271 -268 233 -296 229 -262 261 -296 261 -270 271 -270 231 -264 261 -262 257 -258 291 -262 235 -300 231 -296 263 -268 271 -270 231 -264 257 -288 231 -300 231 -296 271 -270 237 -298 231 -262 261 -262 255 -292 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -296 229 -262 261 -294 229 -296 263 -268 273 -268 231 -264 263 -294 229 -294 229 -264 257 -290 231 -300 265 -236 299 -266 235 -298 231 -264 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -268 231 -298 261 -236 299 -264 235 -300 233 -262 261 -262 257 -290 231 -268 259 -292 231 -300 263 -270 273 -268 233 -262 261 -262 257 -292 231 -298 265 -270 271 -270 231 -264 261 -262 257 -290 231 -300 231 -296 231 -294 263 -234 301 -264 233 -300 231 -296 231 -294 229 -264 257 -290 265 -272 267 -268 235 -300 231 -262 257 -290 231 -300 265 -236 299 -264 235 -300 231 -296 229 -264 261 -262 257 -258 291 -264 267 -272 269 -266 235 -300 229 -296 229 -296 229 -296 261 -270 271 -268 231 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -270 231 -264 257 -256 291 -262 267 -268 233 -264 293 -268 271 -236 261 -292 231 -298 231 -298 229 -262 295 -234 299 -264 269 -268 231 -264 261 -262 257 -290 231 -298 233 -296 263 -270 271 -268 231 -296 231 -262 257 -256 291 -230 293 -264 267 -268 265 -236 299 -266 233 -300 231 -296 231 -262 257 -288 265 -272 275 -270 233 -264 261 -294 229 -294 229 -264 257 -290 231 -300 231 -296 263 -234 299 -266 233 -300 231 -264 257 -258 259 -296 267 -234 259 -292 231 -300 263 -236 299 -266 235 -300 231 -262 259 -290 229 -266 261 -292 265 -272 275 -268 233 -264 255 -258 291 -264 233 -302 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 265 -272 267 -268 233 -302 229 -296 229 -296 263 -234 299 -264 235 -300 231 -296 229 -264 255 -290 231 -300 231 -264 259 -290 265 -270 269 -266 235 -302 229 -264 257 -290 231 -298 231 -298 269 -272 235 -300 229 -262 261 -262 257 -290 233 -298 265 -270 265 -266 235 -300 231 -294 229 -264 257 -290 231 -298 233 -296 263 -270 271 -268 231 -264 261 -294 229 -296 263 -234 299 -266 235 -300 231 -296 229 -262 261 -296 229 -262 257 -292 231 -298 265 -270 271 -270 233 -262 261 -262 257 -258 291 -264 233 -302 265 -234 -RAW_Data: 299 -266 233 -300 231 -296 229 -296 229 -262 257 -258 259 -296 267 -272 275 -270 231 -264 257 -256 291 -264 233 -300 231 -296 263 -236 299 -264 233 -300 231 -298 229 -262 257 -290 233 -298 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -262 255 -292 231 -300 231 -296 263 -236 299 -264 235 -266 259 -292 231 -300 231 -296 263 -236 299 -264 233 -302 231 -264 261 -262 257 -258 291 -262 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -262 257 -258 291 -262 267 -268 233 -296 229 -262 295 -268 271 -270 231 -264 257 -258 259 -292 269 -266 233 -264 295 -266 273 -268 233 -264 261 -262 261 -294 263 -268 267 -266 233 -302 229 -264 257 -290 231 -266 259 -294 265 -272 267 -268 233 -300 231 -296 229 -296 229 -262 289 -298 241 -272 235 -266 261 -262 255 -290 231 -268 259 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -298 229 -264 293 -234 299 -266 235 -300 231 -296 229 -262 257 -258 291 -262 267 -268 231 -296 263 -234 299 -266 233 -302 231 -296 229 -262 261 -294 231 -294 231 -294 231 -294 263 -268 271 -270 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -268 265 -270 271 -268 233 -262 261 -294 231 -294 263 -236 299 -264 235 -300 231 -296 229 -264 261 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -294 229 -296 229 -262 287 -300 241 -274 233 -266 261 -262 255 -258 291 -264 267 -268 265 -234 299 -266 233 -302 231 -264 255 -290 231 -300 231 -298 229 -262 295 -268 271 -270 233 -264 259 -294 229 -296 263 -234 299 -266 235 -300 231 -296 229 -264 261 -262 255 -292 231 -300 231 -296 263 -268 271 -270 233 -264 261 -260 257 -290 231 -300 231 -298 229 -264 293 -268 271 -270 233 -264 261 -262 255 -258 291 -264 267 -274 273 -270 233 -262 261 -296 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 231 -296 263 -234 299 -266 233 -300 231 -298 229 -294 231 -262 261 -294 263 -234 301 -232 263 -262 293 -230 295 -264 233 -300 265 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 265 -272 267 -268 233 -302 231 -294 229 -264 255 -292 231 -298 265 -270 265 -266 235 -300 231 -294 231 -262 257 -290 231 -300 231 -296 231 -262 295 -268 271 -270 231 -264 -RAW_Data: 261 -262 257 -258 259 -328 239 -278 237 -270 261 -262 261 -294 229 -262 257 -292 231 -300 231 -296 263 -234 299 -266 233 -302 231 -264 255 -258 291 -262 267 -268 265 -236 299 -266 233 -300 231 -262 257 -292 231 -266 259 -292 233 -298 265 -236 299 -266 235 -300 229 -264 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -264 233 -300 265 -270 265 -266 233 -300 231 -296 229 -264 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 233 -262 261 -262 257 -258 291 -264 267 -274 275 -270 231 -264 261 -292 229 -264 257 -290 231 -300 231 -296 263 -236 299 -264 233 -300 231 -264 257 -258 261 -260 293 -264 269 -268 265 -234 299 -266 233 -300 231 -296 229 -296 261 -268 267 -266 233 -300 231 -264 261 -262 257 -292 231 -298 231 -298 231 -262 293 -268 271 -270 233 -264 261 -262 255 -292 265 -272 275 -270 231 -264 261 -262 255 -290 265 -234 261 -292 231 -300 263 -270 271 -268 233 -296 229 -264 261 -294 229 -296 229 -262 295 -268 271 -270 233 -264 257 -256 289 -264 267 -268 265 -236 299 -264 235 -300 231 -264 261 -294 229 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 231 -294 229 -296 229 -296 261 -236 299 -266 233 -300 231 -296 229 -264 261 -294 263 -268 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -274 269 -266 235 -300 231 -294 229 -296 229 -296 229 -262 257 -292 229 -300 231 -298 263 -234 299 -264 235 -300 233 -262 261 -262 257 -258 291 -264 267 -268 265 -268 271 -236 261 -292 231 -264 261 -290 231 -300 231 -296 263 -236 297 -266 235 -300 231 -296 229 -262 257 -290 231 -300 265 -236 299 -266 233 -300 231 -296 229 -296 263 -234 299 -264 235 -300 233 -262 261 -296 229 -262 257 -290 231 -300 231 -298 229 -264 293 -268 273 -268 233 -262 261 -262 257 -258 291 -298 239 -276 237 -302 229 -264 255 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 231 -294 229 -296 229 -296 227 -296 261 -270 273 -268 233 -262 261 -294 231 -294 263 -236 297 -266 235 -300 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 265 -234 301 -264 233 -300 231 -264 257 -258 259 -296 267 -266 233 -296 263 -268 271 -268 231 -296 231 -262 257 -290 231 -266 259 -292 265 -272 275 -270 231 -264 261 -294 229 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -296 229 -262 257 -290 231 -300 231 -296 263 -234 299 -266 235 -300 -RAW_Data: 231 -296 229 -262 261 -296 229 -262 257 -292 265 -272 267 -266 235 -302 229 -264 255 -292 231 -298 265 -236 301 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -236 299 -266 233 -300 231 -296 231 -262 261 -294 263 -268 273 -268 233 -262 261 -294 231 -262 257 -292 231 -298 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 263 -268 271 -268 233 -264 257 -290 229 -300 265 -270 265 -266 235 -300 231 -262 257 -258 291 -230 295 -262 235 -300 263 -270 273 -268 231 -264 261 -262 257 -258 291 -304 241 -274 235 -266 261 -260 261 -262 257 -292 231 -268 259 -290 233 -298 265 -236 299 -266 235 -300 231 -262 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 263 -270 267 -266 235 -300 229 -296 229 -296 261 -236 299 -232 295 -262 235 -300 231 -262 257 -258 259 -296 267 -234 261 -292 229 -300 263 -236 301 -266 233 -300 231 -296 229 -294 229 -296 229 -264 255 -292 263 -272 269 -266 235 -300 231 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -262 257 -292 231 -266 259 -260 259 -294 267 -268 265 -268 273 -268 231 -264 257 -258 257 -294 267 -268 233 -296 269 -270 237 -266 257 -258 257 -294 267 -268 231 -298 263 -234 299 -264 267 -268 231 -264 261 -294 229 -296 229 -296 229 -296 263 -268 271 -268 233 -296 229 -262 261 -294 263 -236 299 -264 235 -300 231 -296 229 -296 229 -296 229 -294 231 -262 293 -268 273 -268 233 -264 261 -294 229 -296 229 -296 229 -294 269 -272 235 -268 257 -258 257 -294 267 -268 231 -298 261 -236 297 -266 235 -300 231 -296 229 -262 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 263 -270 267 -266 235 -300 229 -296 229 -296 229 -296 261 -236 299 -264 267 -268 231 -264 261 -262 257 -258 291 -264 233 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 261 -296 229 -262 257 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 271 -274 235 -266 263 -262 259 -296 229 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -262 257 -258 259 -296 267 -266 233 -264 293 -268 271 -270 233 -264 255 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 229 -262 261 -294 231 -294 231 -296 261 -270 271 -268 233 -264 261 -262 255 -258 291 -304 243 -274 235 -266 261 -262 259 -294 231 -262 -RAW_Data: 257 -290 265 -272 267 -234 295 -264 233 -300 231 -264 257 -290 231 -266 259 -294 231 -300 263 -236 301 -264 235 -300 231 -296 229 -262 257 -290 231 -266 259 -292 233 -298 265 -236 301 -266 233 -300 231 -296 229 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -260 257 -292 231 -298 233 -296 263 -236 299 -264 235 -266 259 -260 259 -294 267 -268 265 -236 299 -264 233 -300 231 -298 229 -262 257 -290 231 -266 259 -294 231 -298 265 -270 271 -270 231 -264 261 -262 257 -258 291 -304 243 -274 235 -264 261 -262 255 -258 291 -262 235 -268 259 -292 231 -300 263 -236 301 -266 233 -300 231 -262 257 -258 291 -264 233 -300 265 -268 273 -236 259 -260 259 -294 267 -266 233 -296 263 -234 299 -264 235 -300 231 -296 229 -262 261 -296 229 -296 229 -296 261 -236 299 -264 235 -300 231 -264 261 -294 229 -264 257 -290 231 -300 265 -268 267 -266 235 -300 231 -262 261 -262 257 -290 231 -300 265 -270 267 -266 233 -300 231 -296 229 -294 229 -296 229 -296 229 -296 261 -236 299 -264 267 -268 231 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -262 259 -258 259 -294 267 -268 231 -296 269 -270 237 -266 263 -260 261 -262 257 -290 231 -302 265 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -270 271 -268 233 -264 261 -294 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -268 231 -264 263 -260 257 -290 233 -298 271 -274 237 -266 261 -262 261 -262 255 -292 231 -300 265 -270 267 -266 233 -300 231 -262 261 -262 257 -258 293 -262 267 -268 265 -236 299 -264 235 -300 231 -296 229 -264 293 -234 299 -266 235 -300 231 -296 229 -264 261 -262 255 -292 231 -266 259 -294 265 -272 267 -266 235 -300 231 -262 257 -258 259 -262 293 -264 269 -268 263 -236 299 -264 235 -300 231 -264 257 -258 259 -292 269 -234 293 -266 275 -272 233 -266 261 -260 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 255 -292 231 -266 259 -292 231 -300 265 -268 267 -232 263 -294 233 -300 231 -264 257 -258 291 -230 293 -264 267 -268 265 -270 271 -268 231 -264 261 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -262 257 -290 265 -234 259 -294 231 -298 265 -268 273 -268 231 -264 261 -262 257 -258 291 -304 -RAW_Data: 243 -274 235 -264 263 -260 261 -294 229 -264 257 -290 231 -300 265 -236 299 -266 235 -298 231 -296 229 -264 255 -258 293 -262 267 -266 265 -270 273 -234 261 -292 229 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -300 231 -296 263 -268 273 -268 231 -296 229 -264 261 -294 269 -272 235 -300 229 -264 259 -294 229 -296 229 -296 263 -234 299 -232 295 -264 267 -266 233 -262 257 -290 231 -300 231 -264 257 -290 231 -300 265 -236 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 267 -268 231 -264 293 -268 267 -232 263 -262 293 -264 267 -268 231 -264 293 -268 271 -270 233 -262 261 -294 229 -296 231 -294 229 -296 263 -234 299 -264 235 -300 233 -262 261 -262 257 -258 293 -262 233 -268 261 -292 231 -298 265 -236 299 -266 233 -300 231 -296 229 -264 261 -294 263 -268 271 -270 233 -264 261 -260 257 -258 291 -264 233 -268 259 -292 231 -300 263 -270 273 -268 231 -296 231 -262 261 -262 257 -290 231 -300 271 -240 265 -294 231 -266 259 -260 257 -294 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 261 -262 257 -290 231 -300 265 -236 299 -266 235 -298 231 -264 261 -296 261 -236 299 -266 235 -300 231 -294 229 -296 229 -264 259 -262 257 -292 231 -298 265 -270 273 -270 231 -264 261 -294 229 -296 229 -262 257 -292 231 -298 265 -236 301 -266 233 -300 231 -262 257 -290 231 -300 231 -264 289 -264 269 -270 271 -268 231 -262 257 -290 231 -298 231 -266 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -292 231 -298 231 -296 231 -294 263 -234 299 -266 235 -300 231 -262 259 -256 291 -262 269 -268 231 -264 293 -268 271 -270 233 -264 261 -262 255 -290 231 -300 265 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -262 263 -294 261 -268 267 -266 235 -300 231 -262 263 -294 229 -262 259 -290 229 -266 261 -292 231 -300 263 -270 273 -268 233 -262 263 -260 257 -292 231 -298 233 -296 269 -270 237 -298 231 -262 261 -262 257 -290 265 -272 267 -268 235 -300 231 -294 231 -294 229 -264 257 -290 231 -300 263 -236 301 -266 233 -302 229 -264 261 -294 263 -268 267 -264 235 -300 231 -264 261 -262 257 -258 259 -294 267 -268 231 -264 263 -294 263 -234 299 -266 233 -300 231 -296 231 -294 229 -262 257 -290 231 -300 233 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -260 259 -296 267 -266 265 -236 299 -264 -RAW_Data: 235 -300 231 -296 229 -264 261 -294 263 -234 301 -266 233 -300 231 -264 257 -290 231 -264 261 -260 259 -294 267 -268 265 -268 273 -268 231 -264 261 -294 229 -296 229 -296 229 -296 263 -268 271 -236 259 -260 259 -294 267 -266 267 -234 299 -232 263 -294 267 -268 231 -264 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 233 -300 231 -298 229 -262 295 -232 301 -266 233 -300 231 -296 231 -262 257 -290 231 -298 231 -298 263 -236 299 -264 233 -300 231 -264 257 -292 231 -264 261 -292 265 -272 273 -238 261 -292 229 -266 259 -292 231 -300 265 -234 301 -266 233 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -236 299 -264 235 -300 233 -262 257 -256 293 -230 293 -264 233 -300 265 -236 301 -264 233 -300 231 -296 231 -262 257 -290 265 -272 267 -266 235 -302 229 -296 229 -294 229 -264 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -268 271 -268 233 -264 257 -290 231 -266 259 -292 231 -300 271 -274 235 -266 259 -256 257 -262 293 -264 269 -268 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -270 271 -268 231 -298 229 -262 261 -294 263 -234 301 -266 235 -300 229 -296 229 -296 229 -262 257 -258 259 -296 267 -266 265 -270 271 -270 231 -264 261 -294 229 -296 229 -296 267 -272 235 -300 229 -264 259 -262 257 -258 291 -262 269 -266 265 -236 301 -264 233 -300 231 -264 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -296 261 -236 299 -232 295 -262 233 -300 231 -298 229 -264 255 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 259 -262 257 -292 231 -300 231 -296 263 -236 299 -264 233 -302 229 -298 229 -262 257 -292 231 -266 259 -292 265 -272 267 -268 233 -300 231 -262 259 -258 259 -260 295 -262 269 -268 265 -234 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 233 -268 259 -292 231 -300 265 -268 273 -268 233 -262 261 -262 257 -290 233 -298 231 -298 269 -238 265 -260 261 -292 267 -234 261 -292 231 -298 265 -268 267 -266 235 -298 231 -264 261 -262 257 -258 293 -262 267 -266 265 -236 299 -266 233 -302 231 -262 261 -296 261 -236 299 -266 235 -300 231 -262 257 -290 231 -268 259 -292 231 -300 263 -236 301 -266 233 -300 231 -264 261 -262 257 -258 291 -262 267 -268 265 -268 273 -268 233 -262 261 -296 229 -296 229 -262 257 -290 231 -300 263 -270 -RAW_Data: 267 -266 235 -300 229 -264 257 -258 259 -294 267 -234 261 -290 231 -300 263 -270 267 -266 235 -300 229 -296 229 -296 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -270 271 -268 231 -298 229 -262 257 -290 231 -298 265 -236 301 -266 235 -300 229 -296 229 -264 259 -262 257 -292 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 263 -234 299 -264 269 -266 233 -262 261 -294 231 -262 257 -292 231 -298 231 -296 263 -270 271 -268 233 -264 261 -294 229 -262 257 -258 293 -294 241 -276 239 -268 263 -260 257 -288 231 -300 231 -298 263 -268 271 -270 231 -296 229 -264 255 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -264 257 -290 263 -272 269 -266 235 -300 231 -296 231 -262 257 -256 291 -262 267 -234 261 -292 265 -272 267 -266 235 -300 231 -264 257 -290 231 -298 231 -298 231 -262 293 -234 299 -266 235 -302 231 -262 257 -256 293 -262 235 -266 259 -292 265 -272 269 -266 233 -268 259 -292 231 -298 265 -270 265 -266 235 -300 231 -294 231 -262 257 -290 231 -266 259 -292 231 -300 265 -236 301 -264 235 -298 231 -298 229 -262 257 -290 231 -266 259 -292 233 -298 265 -236 301 -266 233 -300 229 -264 257 -290 265 -272 275 -270 231 -264 261 -262 255 -258 293 -262 269 -272 269 -266 235 -300 231 -262 261 -262 257 -290 231 -266 261 -292 231 -300 265 -268 273 -268 233 -262 257 -290 231 -298 233 -296 263 -236 299 -264 233 -302 231 -264 261 -294 229 -264 257 -290 231 -300 265 -268 267 -266 235 -300 231 -262 261 -294 263 -268 267 -266 233 -300 231 -296 229 -264 255 -258 293 -262 267 -266 233 -264 293 -268 271 -270 233 -264 261 -262 255 -258 291 -264 267 -268 271 -274 235 -264 263 -262 255 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -266 233 -262 261 -294 231 -262 257 -290 265 -272 267 -268 235 -300 231 -262 257 -258 259 -294 267 -236 259 -292 231 -300 263 -236 301 -266 233 -300 231 -262 257 -292 229 -300 231 -296 263 -236 299 -266 233 -300 231 -296 231 -262 257 -256 291 -230 293 -264 269 -266 265 -236 299 -264 235 -300 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 231 -296 263 -268 271 -270 231 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -294 231 -294 229 -264 257 -258 259 -294 267 -268 265 -268 273 -268 231 -264 261 -262 257 -290 233 -266 259 -326 237 -276 237 -268 257 -290 231 -264 261 -292 -RAW_Data: 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 261 -262 257 -290 265 -274 267 -268 233 -300 231 -296 229 -264 261 -294 263 -268 267 -266 233 -300 231 -264 261 -294 229 -264 257 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 229 -294 231 -294 229 -296 261 -268 267 -266 233 -300 231 -298 229 -262 261 -262 257 -290 265 -272 275 -270 233 -264 255 -290 231 -298 233 -296 263 -236 299 -264 233 -300 231 -298 229 -294 229 -262 257 -290 233 -300 265 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -300 231 -264 259 -290 229 -300 265 -270 267 -264 235 -300 231 -294 231 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -292 231 -298 231 -296 263 -270 271 -268 233 -264 261 -262 261 -294 261 -270 273 -268 233 -264 261 -294 229 -262 257 -292 231 -266 259 -292 231 -300 263 -270 267 -266 235 -300 229 -296 229 -264 261 -262 257 -290 265 -272 275 -270 233 -262 257 -258 257 -294 267 -274 269 -266 235 -300 231 -296 229 -294 229 -264 257 -290 231 -300 263 -236 301 -266 233 -300 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 261 -262 257 -292 231 -298 265 -270 273 -268 233 -262 261 -262 257 -258 293 -262 235 -266 259 -292 231 -300 263 -270 267 -266 235 -300 229 -296 229 -296 227 -262 257 -292 231 -300 231 -298 263 -268 271 -268 231 -264 263 -260 257 -290 233 -298 265 -270 273 -268 231 -264 261 -294 229 -296 229 -264 255 -292 231 -298 265 -236 301 -266 233 -300 231 -264 257 -256 293 -262 233 -302 263 -236 299 -234 261 -262 293 -264 233 -302 231 -264 293 -234 301 -266 233 -300 231 -296 231 -262 257 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -258 291 -270 271 -270 235 -302 231 -264 261 -262 255 -258 291 -264 269 -266 265 -236 299 -264 235 -300 231 -294 231 -262 257 -258 259 -294 267 -274 269 -266 235 -300 229 -264 257 -290 231 -300 263 -270 267 -266 235 -300 229 -296 229 -262 257 -292 231 -266 259 -292 265 -272 269 -266 235 -300 229 -296 229 -296 229 -296 227 -296 229 -296 261 -236 299 -266 233 -300 231 -296 231 -262 257 -290 231 -298 265 -270 273 -268 233 -262 261 -294 229 -264 257 -292 231 -298 231 -296 263 -236 299 -264 235 -300 233 -262 257 -258 259 -294 267 -266 233 -264 295 -232 299 -266 235 -300 231 -298 229 -262 261 -294 229 -264 257 -292 229 -300 263 -270 -RAW_Data: 273 -236 261 -292 231 -298 231 -296 229 -296 261 -236 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -270 265 -266 235 -300 231 -262 263 -294 261 -236 299 -264 235 -302 231 -264 261 -294 229 -262 259 -256 291 -262 269 -268 265 -234 299 -266 233 -300 231 -296 229 -264 257 -258 257 -328 239 -278 239 -268 257 -258 257 -294 267 -268 231 -264 295 -234 297 -266 235 -302 231 -262 257 -292 229 -300 231 -298 263 -234 299 -264 235 -300 233 -262 257 -290 265 -272 267 -234 263 -296 233 -298 231 -298 229 -262 257 -258 291 -264 233 -300 231 -296 263 -268 273 -268 231 -264 257 -290 231 -298 231 -298 229 -264 293 -268 267 -266 233 -300 231 -264 261 -262 257 -292 231 -298 233 -296 263 -268 271 -268 233 -296 229 -264 255 -290 231 -300 231 -296 265 -234 299 -266 233 -300 231 -264 257 -290 231 -298 231 -264 259 -290 231 -298 265 -236 301 -266 233 -300 231 -296 229 -296 229 -262 257 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 227 -296 261 -270 273 -268 233 -262 261 -262 257 -258 291 -264 233 -268 259 -292 265 -272 273 -272 231 -264 261 -294 229 -296 229 -296 261 -268 271 -270 231 -266 255 -290 231 -266 259 -260 261 -294 267 -266 265 -236 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 265 -272 267 -268 235 -268 259 -290 231 -300 231 -296 263 -268 271 -268 233 -296 229 -264 259 -262 257 -292 231 -298 265 -236 301 -266 233 -300 231 -262 257 -292 231 -298 265 -270 271 -270 233 -262 261 -294 229 -264 257 -258 259 -294 267 -266 233 -296 263 -268 271 -270 231 -264 257 -258 257 -294 267 -268 233 -296 263 -268 271 -268 231 -298 229 -262 261 -294 231 -294 231 -294 261 -268 267 -232 263 -294 267 -236 259 -292 231 -266 259 -292 265 -270 269 -266 235 -302 229 -296 229 -296 229 -262 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 233 -262 261 -262 257 -290 231 -266 261 -292 231 -300 263 -270 273 -268 233 -262 261 -294 229 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -264 267 -268 231 -264 293 -234 299 -266 267 -268 233 -262 257 -290 231 -264 261 -292 265 -272 275 -236 261 -292 231 -264 259 -292 233 -298 265 -236 301 -264 233 -300 231 -296 229 -264 255 -292 231 -266 259 -292 233 -298 265 -236 299 -266 235 -300 229 -296 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 261 -262 255 -292 231 -300 231 -296 263 -270 271 -268 -RAW_Data: 231 -264 261 -296 229 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -294 229 -296 229 -296 229 -262 289 -298 241 -274 235 -264 261 -262 261 -262 255 -292 231 -300 263 -270 267 -266 235 -300 231 -294 229 -264 257 -258 259 -260 295 -262 269 -268 265 -234 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -236 261 -292 231 -264 261 -290 231 -300 265 -234 301 -266 235 -298 231 -296 229 -296 229 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -294 229 -264 287 -266 269 -268 271 -268 231 -264 259 -262 257 -258 291 -264 233 -302 231 -264 293 -234 301 -266 235 -300 229 -296 229 -264 255 -292 231 -300 229 -298 269 -238 265 -294 231 -300 231 -294 229 -296 263 -268 271 -268 233 -264 261 -262 255 -292 231 -266 259 -294 265 -272 267 -268 233 -300 231 -296 229 -296 261 -268 267 -266 233 -300 231 -264 261 -262 257 -258 291 -264 233 -268 259 -292 231 -300 263 -270 273 -268 231 -264 257 -290 231 -266 259 -292 233 -298 265 -270 265 -266 235 -298 231 -264 261 -296 229 -262 257 -290 233 -298 265 -270 265 -234 261 -262 293 -232 293 -264 235 -300 263 -236 299 -266 235 -300 229 -296 229 -264 255 -258 291 -230 295 -264 267 -274 267 -266 235 -300 231 -294 229 -296 229 -262 257 -292 231 -266 259 -292 231 -300 265 -236 299 -266 235 -298 231 -264 257 -290 231 -300 265 -270 271 -268 233 -262 261 -262 257 -290 233 -266 259 -292 233 -298 265 -236 299 -266 233 -300 231 -296 229 -262 257 -258 259 -328 241 -276 239 -268 263 -262 255 -256 291 -264 233 -302 265 -234 299 -232 295 -264 233 -300 231 -296 229 -264 255 -258 291 -264 233 -302 265 -268 271 -270 231 -264 257 -288 231 -300 263 -270 273 -270 231 -264 261 -262 255 -292 263 -268 231 -298 263 -234 299 -264 235 -300 231 -264 257 -290 231 -298 231 -298 269 -272 235 -266 259 -256 257 -262 293 -264 269 -266 233 -264 293 -234 299 -266 235 -300 231 -296 229 -264 255 -258 291 -230 295 -262 269 -272 269 -232 263 -294 233 -302 231 -296 229 -264 259 -262 257 -290 233 -298 231 -298 263 -234 301 -264 235 -300 231 -264 255 -290 231 -266 261 -292 231 -300 265 -234 301 -266 233 -300 231 -296 229 -264 261 -260 257 -292 231 -298 265 -270 267 -266 235 -300 229 -296 229 -262 257 -290 233 -298 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 293 -268 267 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -260 -RAW_Data: 261 -294 267 -272 269 -266 235 -300 229 -264 257 -290 231 -298 233 -296 269 -272 235 -300 229 -264 259 -262 257 -290 231 -300 265 -270 267 -264 235 -300 231 -296 229 -262 257 -258 259 -294 267 -274 267 -268 235 -300 229 -296 229 -296 261 -236 299 -232 295 -264 233 -300 231 -296 229 -264 261 -260 257 -258 293 -262 235 -300 263 -270 273 -268 233 -262 261 -262 257 -258 291 -264 267 -268 265 -234 299 -266 235 -300 231 -262 261 -296 229 -294 231 -294 231 -262 295 -268 271 -270 231 -264 263 -260 261 -294 229 -296 231 -294 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -264 257 -290 231 -300 263 -270 267 -266 235 -300 229 -296 229 -264 255 -258 291 -264 233 -302 265 -234 299 -266 233 -268 259 -292 231 -298 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 257 -258 259 -260 295 -264 267 -274 269 -266 235 -300 231 -262 257 -258 291 -230 295 -304 241 -274 235 -264 257 -256 259 -294 267 -234 261 -292 231 -298 265 -236 299 -266 235 -300 229 -264 257 -258 259 -262 293 -262 269 -268 265 -268 273 -234 261 -292 231 -298 231 -296 263 -268 271 -268 233 -264 261 -294 229 -296 229 -296 229 -296 261 -236 299 -264 267 -268 231 -264 261 -294 229 -296 263 -268 273 -268 231 -264 261 -262 257 -292 231 -266 259 -292 231 -300 231 -296 263 -234 299 -266 233 -302 231 -264 255 -258 291 -264 267 -268 231 -264 293 -268 267 -266 233 -300 231 -296 229 -264 255 -258 291 -262 269 -266 233 -262 295 -234 299 -266 235 -300 231 -296 229 -264 255 -290 231 -300 231 -296 231 -294 263 -268 273 -268 231 -296 231 -262 257 -256 291 -230 293 -264 269 -268 265 -234 299 -266 233 -300 231 -296 229 -264 261 -262 257 -290 231 -300 265 -270 271 -270 231 -262 261 -296 229 -296 261 -236 299 -266 233 -302 231 -264 261 -262 255 -258 293 -228 293 -264 269 -272 269 -266 235 -300 231 -294 231 -262 261 -294 263 -268 273 -268 233 -296 227 -262 257 -258 293 -262 235 -300 265 -236 299 -264 235 -300 231 -262 257 -258 261 -294 267 -266 233 -264 293 -268 271 -270 233 -264 261 -294 229 -294 263 -234 299 -266 235 -300 231 -296 229 -262 257 -258 291 -230 295 -264 233 -300 265 -268 273 -268 233 -262 261 -262 257 -258 291 -262 269 -266 233 -296 263 -268 271 -268 233 -264 261 -262 255 -292 231 -266 291 -302 239 -274 235 -264 261 -262 261 -294 229 -296 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -296 229 -264 -RAW_Data: 255 -258 259 -294 267 -268 231 -298 261 -236 299 -264 235 -300 231 -264 257 -290 231 -298 231 -298 263 -234 299 -232 295 -264 233 -268 259 -292 229 -300 263 -270 267 -266 235 -300 229 -296 229 -262 257 -258 259 -260 295 -264 267 -274 269 -266 235 -300 231 -262 257 -258 291 -268 273 -270 237 -300 231 -294 229 -296 229 -264 255 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -258 259 -294 267 -268 231 -296 269 -238 263 -296 231 -266 259 -292 231 -298 265 -270 273 -268 231 -264 261 -294 229 -296 229 -296 229 -296 229 -296 261 -270 271 -268 231 -296 231 -262 289 -264 267 -270 271 -268 231 -264 261 -292 229 -264 257 -258 291 -264 233 -300 231 -296 263 -268 273 -268 231 -264 261 -296 229 -294 231 -294 229 -296 263 -234 299 -264 235 -300 233 -262 261 -262 257 -292 231 -298 231 -298 229 -296 261 -270 271 -236 259 -260 259 -292 267 -268 265 -236 301 -230 295 -264 233 -300 231 -262 259 -290 231 -266 259 -260 291 -262 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 261 -294 229 -296 229 -264 293 -268 267 -266 233 -300 231 -264 257 -290 231 -300 263 -270 273 -268 233 -294 229 -262 257 -258 291 -264 233 -268 261 -292 263 -272 267 -268 235 -300 229 -296 229 -296 229 -296 229 -294 269 -272 235 -266 259 -290 231 -264 261 -258 261 -294 267 -266 265 -236 299 -264 235 -300 233 -262 257 -258 291 -262 235 -300 233 -262 295 -268 271 -270 231 -264 261 -294 229 -296 261 -270 271 -270 231 -264 261 -294 229 -264 255 -292 231 -300 231 -296 263 -268 271 -270 231 -264 257 -258 257 -262 293 -296 241 -276 239 -302 231 -262 261 -260 257 -258 291 -264 233 -300 265 -234 301 -232 263 -296 231 -300 231 -264 257 -290 233 -298 231 -296 231 -294 263 -236 299 -264 235 -300 231 -262 257 -260 259 -294 267 -234 259 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 255 -258 291 -264 233 -300 265 -236 299 -234 261 -296 233 -298 231 -264 257 -258 293 -228 295 -262 269 -272 269 -266 235 -300 231 -294 231 -294 263 -234 299 -266 233 -302 231 -264 261 -262 255 -258 293 -262 235 -268 259 -292 231 -298 265 -268 273 -268 233 -264 255 -258 291 -230 293 -296 241 -276 239 -268 263 -262 255 -290 231 -298 231 -298 263 -234 301 -264 233 -302 231 -264 261 -294 229 -296 229 -296 229 -294 261 -270 273 -268 233 -262 261 -296 -RAW_Data: 229 -296 261 -236 299 -266 233 -300 231 -264 261 -262 257 -290 231 -268 259 -292 231 -300 265 -268 273 -268 233 -262 261 -296 229 -296 229 -294 231 -262 293 -268 267 -266 235 -300 231 -296 229 -262 261 -296 229 -262 257 -290 265 -272 275 -270 233 -264 255 -290 229 -268 259 -292 231 -300 265 -268 267 -266 235 -300 231 -262 261 -294 229 -264 257 -290 231 -300 231 -296 263 -236 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 229 -296 263 -234 299 -264 235 -300 233 -262 257 -290 231 -300 263 -236 301 -266 235 -298 231 -296 229 -264 261 -262 255 -292 231 -300 263 -270 267 -266 235 -300 231 -294 229 -296 229 -296 261 -270 271 -268 231 -298 229 -262 257 -258 291 -262 235 -300 231 -264 295 -232 301 -266 233 -300 231 -264 257 -290 231 -298 233 -296 231 -262 293 -268 273 -270 231 -264 257 -290 231 -298 265 -236 301 -266 233 -300 231 -262 257 -292 229 -266 261 -292 231 -300 263 -270 273 -268 231 -264 261 -262 257 -258 291 -304 243 -274 235 -264 261 -262 255 -258 291 -264 267 -234 261 -290 231 -300 263 -236 301 -266 233 -300 231 -262 257 -258 259 -262 293 -264 269 -266 265 -270 271 -268 233 -262 257 -290 231 -300 231 -264 257 -292 229 -300 265 -270 265 -234 261 -296 233 -300 231 -264 295 -234 297 -266 269 -268 231 -262 261 -262 257 -292 231 -298 233 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -290 265 -266 233 -296 263 -234 299 -264 235 -300 233 -262 257 -290 231 -300 265 -234 301 -266 235 -300 229 -296 229 -262 257 -290 231 -268 259 -292 231 -300 265 -268 273 -268 233 -262 257 -258 291 -262 267 -266 233 -296 269 -272 235 -266 257 -292 229 -300 231 -296 229 -296 261 -236 299 -264 235 -300 231 -264 257 -290 231 -298 231 -298 229 -264 293 -268 273 -268 233 -264 261 -262 261 -294 263 -268 267 -266 235 -300 229 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -264 261 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -296 227 -262 257 -258 293 -262 269 -272 269 -266 233 -300 231 -296 229 -262 259 -256 293 -262 267 -266 265 -236 299 -232 295 -264 233 -300 231 -264 257 -290 231 -266 259 -260 259 -296 267 -266 265 -236 299 -264 235 -300 231 -264 261 -294 229 -264 257 -290 265 -272 267 -268 235 -266 259 -292 231 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -292 265 -272 -RAW_Data: 267 -268 235 -300 231 -294 229 -296 263 -234 299 -266 267 -268 231 -262 261 -262 257 -292 231 -266 259 -260 259 -296 267 -266 265 -270 271 -270 231 -264 259 -296 229 -262 257 -292 231 -298 271 -274 235 -268 257 -258 257 -294 267 -266 267 -236 299 -264 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -298 229 -262 255 -290 265 -272 269 -266 235 -300 231 -296 229 -264 261 -262 257 -290 231 -300 231 -298 263 -268 271 -268 231 -296 231 -262 257 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -290 231 -300 231 -298 229 -262 295 -234 299 -266 235 -300 231 -294 231 -294 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -296 229 -264 255 -258 291 -262 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 261 -294 229 -264 257 -290 265 -272 267 -268 233 -300 231 -264 257 -258 259 -292 269 -268 265 -236 299 -264 235 -300 231 -296 229 -264 261 -262 255 -292 231 -300 229 -298 263 -268 271 -270 231 -264 261 -296 229 -262 289 -266 273 -274 233 -266 261 -262 255 -290 231 -300 231 -264 257 -292 231 -298 265 -270 273 -268 233 -262 261 -294 229 -264 257 -290 231 -300 265 -236 299 -266 233 -300 231 -296 229 -264 257 -256 293 -228 293 -264 269 -268 265 -234 299 -266 233 -300 231 -296 229 -296 229 -262 261 -296 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -258 259 -260 295 -262 269 -268 265 -234 299 -232 295 -262 235 -300 231 -296 229 -264 255 -258 291 -264 267 -268 265 -268 271 -268 233 -262 257 -290 231 -300 263 -270 267 -266 235 -300 229 -296 229 -296 229 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -294 231 -262 261 -262 289 -300 241 -272 235 -264 261 -262 261 -262 257 -258 261 -294 267 -266 265 -236 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -270 271 -236 261 -260 259 -294 265 -268 265 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -296 231 -262 255 -292 265 -270 275 -270 233 -264 261 -294 229 -262 257 -258 291 -262 267 -268 233 -264 293 -234 299 -266 235 -300 231 -264 257 -290 231 -266 259 -292 265 -272 267 -268 235 -300 231 -294 229 -296 229 -296 229 -296 229 -294 231 -294 263 -268 271 -236 261 -292 231 -298 265 -268 273 -268 233 -262 257 -290 231 -266 259 -292 233 -298 231 -296 263 -234 301 -264 235 -300 231 -296 229 -296 229 -262 257 -290 -RAW_Data: 231 -300 231 -296 263 -236 299 -264 235 -300 231 -264 257 -258 257 -260 295 -264 267 -268 265 -236 299 -264 235 -300 231 -264 257 -290 231 -298 231 -266 257 -290 231 -298 265 -270 273 -268 233 -262 261 -296 229 -296 229 -294 231 -294 269 -238 263 -296 231 -266 259 -260 259 -292 267 -268 265 -236 301 -264 233 -300 231 -296 231 -262 261 -294 229 -296 231 -294 263 -268 271 -270 231 -296 229 -264 261 -294 263 -234 301 -264 235 -300 231 -294 231 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -264 261 -262 257 -292 231 -266 259 -292 231 -300 265 -268 273 -268 233 -262 263 -260 257 -258 291 -264 267 -268 231 -264 295 -234 297 -266 269 -268 231 -262 257 -290 231 -266 259 -294 231 -298 231 -296 263 -236 299 -266 235 -300 229 -264 257 -258 291 -262 235 -266 259 -292 231 -300 263 -270 267 -266 235 -300 229 -264 257 -258 259 -262 293 -264 267 -268 265 -268 273 -268 231 -264 261 -262 255 -292 231 -300 263 -270 267 -266 235 -300 231 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -296 229 -262 295 -268 267 -264 235 -300 231 -296 229 -262 257 -258 259 -294 267 -234 261 -292 231 -298 265 -270 271 -270 231 -264 261 -262 255 -292 231 -300 231 -296 271 -270 235 -266 259 -290 231 -264 261 -292 265 -272 267 -266 235 -300 231 -296 229 -264 261 -260 257 -292 231 -298 265 -236 301 -266 235 -300 229 -296 229 -294 263 -268 267 -266 235 -300 229 -296 229 -264 255 -292 231 -266 259 -292 233 -298 265 -236 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 267 -274 267 -268 233 -300 231 -296 229 -294 229 -296 229 -262 257 -290 231 -300 265 -268 273 -270 231 -264 255 -258 291 -264 233 -302 265 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -264 257 -290 231 -300 265 -268 273 -270 231 -264 261 -262 255 -260 291 -262 267 -268 231 -296 263 -234 299 -266 233 -302 229 -264 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -296 229 -264 255 -290 233 -298 231 -296 263 -270 271 -268 233 -296 229 -262 261 -262 257 -258 291 -304 243 -274 235 -264 261 -262 257 -256 291 -264 233 -300 231 -298 261 -236 299 -264 235 -300 231 -264 257 -258 289 -264 267 -268 265 -236 299 -264 233 -268 259 -292 231 -300 263 -270 267 -266 233 -300 231 -264 255 -290 233 -266 259 -292 233 -298 265 -270 271 -270 231 -262 261 -262 257 -292 231 -298 233 -264 257 -290 231 -298 265 -270 267 -266 -RAW_Data: 233 -300 231 -264 261 -262 257 -258 291 -264 267 -274 267 -266 235 -300 229 -296 229 -264 257 -290 231 -298 233 -296 231 -262 293 -236 299 -266 235 -300 229 -296 229 -296 229 -262 257 -258 291 -264 233 -300 265 -236 299 -266 235 -300 229 -264 257 -258 259 -294 267 -268 231 -296 269 -272 235 -298 231 -262 257 -256 291 -262 269 -268 265 -234 299 -266 233 -300 231 -264 261 -296 229 -296 229 -296 229 -262 293 -268 273 -270 231 -264 261 -294 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -262 257 -258 291 -264 267 -268 265 -268 271 -270 231 -264 261 -294 229 -296 229 -296 267 -272 237 -298 231 -262 261 -262 257 -258 259 -294 267 -268 231 -264 295 -234 299 -264 269 -268 231 -264 255 -290 231 -298 233 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 265 -234 301 -266 233 -300 231 -264 257 -258 257 -296 267 -266 265 -236 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -296 229 -262 261 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -302 231 -264 261 -294 229 -296 261 -236 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -270 271 -270 231 -264 257 -290 231 -298 231 -298 229 -264 293 -268 273 -236 261 -258 259 -260 295 -262 235 -300 263 -270 267 -266 233 -300 231 -296 229 -296 229 -262 257 -256 293 -262 235 -300 265 -270 271 -268 231 -296 231 -262 255 -290 265 -272 269 -266 235 -300 231 -264 257 -290 231 -266 259 -292 231 -300 265 -268 273 -268 233 -262 261 -262 257 -258 293 -228 295 -296 241 -276 239 -268 263 -260 261 -262 255 -292 265 -266 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 261 -262 255 -292 231 -300 263 -270 267 -266 235 -300 229 -296 229 -296 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 255 -258 291 -262 267 -268 265 -236 301 -264 233 -300 231 -296 231 -262 257 -256 293 -262 233 -302 263 -270 273 -268 231 -264 261 -294 229 -296 263 -234 299 -266 233 -300 231 -296 229 -264 257 -258 259 -294 267 -268 231 -296 263 -268 273 -268 231 -264 261 -262 255 -292 231 -266 259 -326 239 -276 237 -300 231 -262 255 -290 231 -298 231 -298 263 -268 273 -268 231 -296 231 -262 261 -294 229 -296 229 -296 261 -268 267 -266 233 -300 231 -264 -RAW_Data: 261 -296 261 -236 299 -266 235 -300 231 -294 229 -264 257 -256 293 -262 233 -268 259 -292 265 -272 267 -268 235 -300 231 -294 229 -296 229 -264 259 -296 261 -270 267 -232 263 -294 233 -300 231 -264 257 -290 231 -300 231 -264 259 -290 263 -272 273 -238 261 -260 259 -292 267 -268 231 -264 295 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 231 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 229 -264 293 -268 273 -268 233 -264 257 -256 291 -262 269 -272 269 -266 235 -300 231 -262 261 -294 231 -294 231 -262 257 -290 231 -300 265 -268 273 -270 231 -264 261 -262 257 -290 231 -266 293 -300 241 -272 235 -264 261 -262 261 -262 255 -260 291 -264 267 -268 265 -234 299 -266 233 -300 231 -264 257 -290 231 -300 231 -298 263 -234 299 -264 233 -302 231 -264 255 -290 231 -300 265 -270 271 -270 231 -264 261 -262 257 -290 231 -268 259 -292 265 -272 267 -268 233 -300 231 -264 257 -258 291 -228 295 -304 243 -274 235 -264 263 -260 257 -256 291 -264 233 -302 231 -264 293 -234 301 -266 233 -300 231 -296 231 -262 261 -294 229 -296 229 -296 263 -234 299 -264 235 -300 233 -262 261 -296 229 -296 229 -262 257 -290 231 -300 263 -270 267 -232 263 -294 233 -300 231 -264 257 -292 231 -298 233 -296 231 -262 293 -268 267 -266 233 -300 231 -264 257 -258 291 -262 267 -266 233 -296 263 -234 299 -264 235 -300 231 -296 229 -264 257 -256 293 -262 233 -302 263 -270 267 -266 233 -300 231 -294 229 -296 263 -236 299 -264 233 -300 231 -298 229 -262 257 -290 231 -266 261 -292 231 -300 263 -270 271 -270 231 -264 261 -294 229 -264 257 -258 291 -302 243 -274 235 -266 255 -290 231 -264 261 -292 231 -300 265 -234 301 -266 233 -300 231 -296 229 -264 261 -294 229 -296 263 -234 299 -264 235 -300 231 -296 229 -296 263 -234 299 -232 295 -264 267 -266 231 -264 261 -296 229 -262 257 -290 233 -298 265 -270 265 -266 235 -300 231 -294 229 -296 229 -296 229 -262 261 -296 261 -270 265 -266 235 -300 231 -294 231 -294 231 -262 257 -288 265 -272 275 -270 233 -264 257 -290 229 -266 261 -260 259 -294 233 -300 265 -236 299 -266 235 -300 231 -262 263 -260 257 -292 231 -266 259 -294 231 -298 265 -268 267 -266 235 -300 231 -294 229 -296 229 -294 229 -296 229 -296 263 -268 271 -236 261 -260 257 -262 293 -262 269 -274 267 -232 295 -264 233 -300 231 -296 229 -264 255 -292 231 -266 259 -292 -RAW_Data: 233 -298 265 -236 301 -264 233 -300 231 -296 229 -296 229 -296 261 -270 271 -268 233 -264 261 -294 229 -262 257 -258 259 -296 267 -266 265 -236 299 -266 233 -300 231 -264 257 -290 231 -298 231 -266 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -274 269 -266 235 -300 231 -294 231 -262 257 -258 259 -294 267 -268 231 -296 263 -234 299 -266 233 -302 231 -264 261 -294 229 -262 257 -292 231 -298 231 -298 261 -236 299 -266 235 -300 231 -294 231 -294 229 -264 255 -290 231 -300 265 -270 271 -236 261 -292 231 -298 231 -296 231 -294 263 -234 299 -266 233 -302 231 -264 261 -294 229 -262 259 -290 231 -298 265 -236 301 -266 233 -300 231 -296 229 -262 295 -268 265 -266 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 231 -296 263 -234 301 -266 233 -300 231 -296 229 -262 257 -258 291 -296 241 -276 237 -268 259 -256 257 -294 267 -268 231 -298 263 -268 271 -268 231 -264 263 -260 257 -290 231 -268 259 -292 265 -272 269 -266 235 -300 231 -262 257 -290 265 -272 267 -234 263 -296 233 -300 231 -296 231 -262 257 -290 231 -298 231 -298 263 -234 299 -266 267 -268 231 -262 257 -290 231 -300 231 -296 231 -262 295 -268 265 -266 235 -300 231 -264 261 -262 257 -290 231 -266 261 -292 265 -272 273 -270 233 -264 261 -294 229 -294 229 -296 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 291 -230 295 -264 235 -300 263 -236 299 -266 235 -300 229 -296 229 -264 261 -262 257 -290 231 -300 265 -270 265 -266 235 -300 231 -262 257 -290 233 -298 265 -270 271 -270 231 -296 227 -262 257 -292 231 -300 231 -264 257 -290 265 -272 273 -272 233 -262 261 -294 229 -296 229 -296 261 -268 273 -268 233 -264 257 -290 231 -264 261 -258 261 -294 267 -268 265 -234 301 -264 235 -300 231 -296 229 -262 257 -258 259 -294 267 -268 265 -268 273 -268 231 -264 261 -294 229 -296 263 -236 299 -230 295 -264 235 -300 229 -264 257 -290 233 -266 259 -292 265 -270 269 -266 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 263 -234 299 -264 235 -300 231 -296 229 -264 257 -290 231 -298 231 -298 263 -268 271 -268 233 -264 261 -262 255 -292 231 -266 259 -294 231 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 229 -296 229 -296 229 -296 261 -270 271 -268 231 -264 257 -258 257 -294 269 -234 261 -292 -RAW_Data: 231 -298 263 -236 301 -266 233 -300 231 -296 231 -262 259 -296 229 -296 263 -234 299 -266 233 -268 259 -292 231 -298 231 -298 261 -236 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -292 265 -272 269 -266 235 -300 231 -264 255 -290 265 -272 267 -266 235 -302 231 -264 261 -262 255 -258 293 -262 267 -234 261 -292 231 -298 265 -268 273 -270 231 -264 255 -290 231 -266 259 -294 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -298 229 -262 295 -268 271 -270 231 -264 257 -290 231 -298 265 -236 301 -266 233 -300 231 -296 229 -262 257 -258 291 -262 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 255 -258 291 -230 295 -264 233 -300 265 -234 301 -266 233 -300 231 -264 257 -258 257 -296 267 -272 269 -266 235 -300 231 -264 261 -294 229 -296 229 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -294 229 -264 257 -258 291 -294 241 -276 239 -268 263 -262 261 -294 229 -294 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 233 -298 231 -298 263 -234 299 -264 269 -266 233 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -294 229 -262 257 -292 231 -266 259 -292 265 -272 267 -268 235 -300 231 -262 257 -290 231 -266 261 -292 231 -298 265 -270 271 -270 231 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -268 273 -268 231 -296 231 -262 257 -256 291 -264 267 -274 267 -266 235 -300 231 -294 231 -294 229 -296 229 -296 229 -296 261 -236 299 -264 233 -300 231 -264 257 -292 231 -298 265 -236 301 -266 233 -300 231 -264 255 -290 231 -266 259 -294 231 -300 263 -270 273 -268 233 -262 261 -262 257 -290 233 -298 231 -264 259 -290 231 -300 263 -270 273 -268 231 -264 261 -262 257 -290 231 -300 231 -296 263 -270 271 -268 233 -264 255 -290 231 -298 233 -264 257 -292 231 -298 265 -236 301 -264 235 -300 229 -296 229 -264 257 -290 231 -298 265 -270 267 -232 263 -262 293 -264 233 -300 265 -234 301 -266 233 -300 231 -296 229 -264 255 -290 231 -266 261 -292 265 -272 275 -268 233 -264 261 -260 257 -258 293 -228 295 -304 243 -274 235 -264 263 -260 261 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 229 -296 229 -264 255 -290 233 -298 265 -270 273 -268 231 -264 261 -294 229 -296 229 -264 293 -268 267 -266 233 -300 231 -264 261 -262 257 -292 231 -266 259 -292 267 -270 269 -266 235 -300 231 -294 231 -262 257 -290 231 -266 259 -294 -RAW_Data: 231 -300 263 -270 273 -268 231 -264 261 -294 229 -296 261 -236 299 -266 233 -302 231 -264 255 -290 231 -298 231 -298 231 -294 263 -234 299 -266 267 -268 231 -264 261 -260 257 -292 231 -266 259 -260 261 -294 267 -266 265 -270 271 -270 231 -264 261 -260 257 -258 293 -262 235 -300 263 -270 273 -236 259 -292 231 -266 259 -292 231 -298 265 -270 267 -266 233 -300 229 -296 231 -262 257 -290 231 -300 231 -296 263 -236 297 -266 235 -300 231 -296 229 -262 295 -234 299 -266 267 -268 233 -262 261 -262 257 -290 231 -268 259 -292 231 -300 263 -270 267 -266 233 -300 231 -264 255 -290 233 -298 231 -298 269 -272 235 -266 263 -262 259 -262 257 -290 233 -300 265 -236 299 -266 233 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 265 -234 301 -266 235 -298 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 231 -296 263 -234 299 -232 295 -232 261 -294 235 -300 263 -270 267 -266 233 -300 231 -296 229 -294 231 -262 257 -290 231 -298 231 -298 263 -234 299 -266 235 -300 231 -296 229 -262 257 -258 291 -230 293 -264 235 -300 265 -270 271 -268 231 -264 261 -294 229 -296 229 -296 263 -268 271 -268 233 -264 261 -294 229 -264 257 -290 231 -298 233 -296 263 -234 299 -266 233 -300 231 -298 229 -262 261 -262 257 -290 265 -272 275 -238 261 -292 229 -298 231 -298 229 -294 263 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -230 295 -264 267 -272 267 -268 233 -300 231 -296 229 -296 229 -294 263 -268 273 -268 231 -296 229 -264 257 -256 291 -230 293 -264 267 -268 265 -270 271 -268 233 -262 257 -258 291 -262 235 -300 233 -294 269 -238 263 -294 233 -300 229 -264 257 -290 233 -298 265 -270 265 -266 235 -298 231 -296 229 -296 229 -264 259 -296 229 -296 263 -268 271 -270 231 -264 261 -262 257 -258 291 -262 267 -268 231 -264 295 -234 299 -264 269 -268 231 -264 261 -294 229 -296 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 231 -264 259 -290 229 -300 263 -270 267 -266 235 -300 231 -296 229 -262 257 -258 291 -262 267 -268 231 -296 263 -268 271 -268 233 -264 261 -262 257 -290 231 -266 261 -324 239 -276 237 -300 231 -262 255 -258 291 -262 267 -266 233 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 263 -236 299 -264 267 -268 231 -264 261 -294 229 -296 263 -234 299 -266 233 -302 231 -296 229 -262 257 -290 231 -266 259 -294 265 -272 267 -266 235 -300 231 -296 229 -264 -RAW_Data: 255 -290 265 -272 275 -270 233 -262 261 -294 231 -294 229 -264 257 -290 231 -300 263 -270 267 -266 233 -302 229 -264 255 -292 231 -298 231 -298 229 -264 293 -268 271 -270 233 -264 261 -262 255 -290 265 -234 261 -292 231 -298 231 -296 263 -234 299 -266 235 -268 259 -258 259 -294 267 -268 265 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -260 261 -294 267 -268 265 -234 301 -264 233 -300 231 -296 231 -262 257 -290 231 -298 231 -298 263 -234 301 -264 233 -302 231 -264 255 -290 231 -300 265 -268 273 -270 231 -264 261 -262 255 -292 231 -300 231 -264 257 -290 265 -272 267 -268 235 -302 229 -264 261 -262 257 -290 231 -300 271 -272 237 -298 231 -262 261 -262 255 -258 291 -264 267 -274 269 -232 263 -294 233 -300 231 -264 259 -258 257 -260 295 -264 267 -268 265 -270 271 -268 231 -296 231 -262 261 -294 263 -268 273 -268 233 -262 261 -262 257 -258 293 -262 233 -302 231 -264 293 -268 271 -270 233 -264 257 -290 229 -266 261 -324 239 -276 237 -300 231 -262 261 -262 255 -290 233 -298 231 -298 263 -234 299 -232 295 -264 233 -300 231 -296 229 -264 261 -294 229 -296 263 -268 271 -270 231 -264 263 -260 257 -290 231 -268 259 -292 231 -300 263 -270 267 -266 233 -300 231 -264 257 -290 229 -300 265 -270 267 -264 235 -300 231 -294 231 -294 229 -264 257 -290 231 -298 231 -298 263 -236 299 -264 233 -300 231 -296 231 -262 257 -290 231 -266 261 -292 231 -298 265 -270 271 -270 231 -264 261 -294 229 -264 257 -290 265 -272 273 -272 231 -264 261 -262 255 -292 231 -300 231 -298 229 -262 293 -268 267 -266 235 -300 231 -296 229 -262 261 -262 257 -292 263 -272 269 -266 235 -300 231 -264 255 -290 233 -298 265 -236 301 -266 233 -300 231 -296 229 -264 261 -262 255 -260 259 -294 267 -272 269 -266 235 -302 229 -296 229 -296 227 -296 261 -270 267 -266 233 -300 231 -296 229 -296 229 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -296 229 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -262 261 -262 257 -290 231 -266 261 -292 265 -272 267 -268 235 -300 231 -262 257 -290 231 -266 261 -292 231 -298 265 -270 271 -270 233 -262 261 -294 229 -264 257 -290 231 -298 265 -270 267 -232 263 -294 233 -302 231 -296 229 -264 261 -262 255 -292 231 -300 231 -296 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 265 -270 267 -266 233 -300 231 -296 227 -294 231 -262 257 -292 231 -298 -RAW_Data: 265 -236 301 -266 233 -300 231 -262 257 -290 233 -298 265 -270 271 -270 231 -264 261 -262 257 -258 291 -264 233 -302 231 -264 293 -234 301 -266 233 -300 231 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -268 233 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -264 257 -290 231 -266 259 -292 233 -298 265 -270 271 -270 231 -264 261 -262 255 -260 291 -302 243 -274 235 -266 261 -262 255 -290 231 -300 231 -264 257 -290 231 -300 263 -270 273 -270 231 -264 261 -262 255 -260 291 -262 235 -300 265 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -228 295 -264 267 -268 265 -236 299 -232 293 -264 233 -300 231 -296 263 -236 297 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -264 257 -292 231 -298 265 -236 301 -264 233 -300 231 -296 231 -262 257 -290 231 -298 231 -298 263 -234 301 -264 233 -300 231 -264 257 -292 231 -298 265 -270 271 -270 231 -296 229 -262 261 -296 229 -262 257 -292 231 -298 231 -298 261 -270 271 -268 231 -264 257 -258 259 -294 267 -268 231 -298 267 -272 235 -268 257 -290 229 -300 231 -298 263 -234 299 -230 295 -264 235 -300 231 -262 257 -258 291 -262 269 -268 231 -262 295 -268 271 -270 233 -262 261 -294 229 -296 263 -236 299 -264 233 -302 231 -264 261 -294 229 -264 257 -290 265 -272 267 -268 235 -300 231 -262 257 -258 259 -260 295 -262 269 -268 265 -268 273 -268 231 -264 257 -258 257 -294 267 -268 265 -236 301 -264 233 -300 231 -296 229 -296 229 -264 255 -292 231 -298 265 -236 301 -266 233 -300 231 -294 229 -296 231 -262 257 -290 231 -300 265 -236 299 -264 233 -302 231 -264 261 -294 229 -296 263 -268 271 -270 231 -296 229 -264 261 -262 257 -290 231 -266 259 -294 231 -300 263 -236 299 -266 233 -300 231 -296 231 -294 229 -264 257 -290 231 -298 231 -298 263 -234 301 -264 233 -300 231 -296 231 -262 257 -256 291 -298 239 -278 237 -300 231 -262 255 -290 231 -266 259 -292 233 -298 265 -270 265 -266 235 -300 231 -294 231 -262 257 -256 293 -262 267 -266 267 -270 271 -268 231 -264 261 -294 229 -296 263 -236 299 -264 233 -302 231 -264 261 -294 229 -264 257 -290 231 -300 263 -270 267 -266 235 -300 229 -264 261 -294 229 -264 289 -298 241 -274 235 -264 261 -262 255 -258 291 -264 267 -268 265 -234 299 -266 233 -300 231 -296 229 -296 229 -296 229 -296 229 -262 293 -268 273 -270 231 -264 261 -262 261 -294 263 -268 267 -234 261 -296 265 -268 231 -296 -RAW_Data: 231 -262 257 -290 231 -298 231 -298 263 -268 271 -270 231 -264 261 -294 229 -296 229 -296 229 -264 261 -294 261 -270 271 -270 231 -264 261 -294 229 -264 257 -290 265 -272 267 -266 235 -302 231 -264 261 -262 255 -260 291 -262 235 -300 263 -236 301 -264 235 -300 231 -296 229 -264 259 -296 229 -262 257 -292 231 -298 231 -298 263 -234 299 -264 269 -266 233 -262 261 -294 231 -294 231 -294 263 -268 265 -234 295 -228 295 -230 293 -264 235 -300 265 -236 299 -264 233 -302 231 -296 229 -262 257 -290 231 -266 259 -260 261 -294 267 -266 265 -236 299 -266 233 -300 231 -264 257 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -262 257 -258 259 -296 267 -266 265 -270 271 -270 231 -264 261 -260 257 -292 231 -266 259 -294 231 -298 265 -236 301 -264 235 -298 231 -296 231 -262 257 -290 231 -266 259 -292 267 -270 269 -266 235 -300 231 -262 257 -258 291 -262 269 -234 261 -290 231 -300 263 -236 301 -266 233 -300 231 -294 231 -262 257 -258 259 -294 267 -268 231 -296 263 -234 299 -266 233 -302 231 -264 261 -260 257 -292 231 -298 265 -270 273 -268 233 -262 257 -290 231 -298 231 -298 229 -296 263 -234 299 -266 233 -300 231 -298 229 -262 257 -258 291 -262 269 -272 269 -266 233 -300 231 -296 229 -296 261 -236 299 -232 295 -262 267 -268 231 -264 261 -262 257 -290 231 -300 231 -298 229 -262 295 -268 271 -270 231 -264 263 -260 257 -258 291 -296 241 -276 237 -302 229 -264 255 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 229 -296 263 -268 271 -268 233 -264 261 -294 229 -296 263 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 231 -262 295 -268 271 -270 231 -264 261 -294 229 -296 229 -264 255 -292 265 -272 267 -234 263 -294 233 -300 231 -264 257 -258 291 -264 233 -300 265 -270 271 -270 231 -264 261 -294 229 -262 257 -292 231 -298 265 -270 267 -264 235 -300 231 -296 229 -262 257 -258 291 -230 295 -264 233 -300 265 -234 299 -232 295 -264 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -270 271 -270 231 -264 257 -290 231 -298 265 -236 301 -266 233 -300 231 -296 229 -262 261 -296 229 -296 229 -294 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 261 -270 271 -270 233 -262 261 -294 229 -264 257 -290 231 -300 231 -296 263 -234 301 -264 235 -300 233 -262 261 -294 229 -296 229 -296 229 -296 261 -270 271 -268 231 -264 257 -290 -RAW_Data: 231 -300 263 -270 267 -266 235 -300 229 -264 257 -258 259 -262 293 -264 267 -268 265 -268 273 -268 231 -264 261 -262 255 -292 265 -272 269 -266 235 -300 231 -262 257 -290 231 -266 259 -260 261 -294 267 -266 267 -234 299 -266 233 -300 231 -296 231 -294 229 -264 255 -290 231 -300 265 -270 267 -266 233 -300 231 -296 229 -294 229 -296 229 -264 255 -290 233 -298 231 -298 263 -268 271 -268 233 -296 229 -262 261 -262 257 -258 291 -262 269 -266 265 -270 273 -268 231 -264 261 -294 229 -296 229 -264 261 -294 229 -296 263 -234 299 -266 233 -302 231 -264 255 -258 291 -264 233 -302 231 -264 293 -268 271 -270 231 -264 257 -290 231 -298 265 -270 267 -266 235 -300 229 -264 261 -294 229 -296 229 -264 255 -290 233 -298 265 -270 273 -268 231 -264 261 -262 257 -258 293 -302 243 -272 235 -266 261 -262 261 -294 229 -262 259 -290 231 -300 265 -236 299 -266 235 -298 231 -296 229 -262 257 -290 231 -300 265 -270 271 -270 231 -264 257 -290 231 -298 231 -298 263 -234 299 -264 269 -266 233 -262 261 -296 229 -296 229 -294 231 -294 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 293 -262 235 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -270 271 -270 237 -300 231 -296 229 -262 257 -258 291 -264 233 -300 231 -296 263 -234 301 -264 233 -300 231 -264 257 -258 259 -296 267 -234 259 -292 231 -300 263 -236 299 -266 233 -300 231 -296 231 -262 257 -258 259 -292 269 -268 265 -270 271 -236 259 -292 231 -298 231 -296 263 -236 299 -264 233 -302 229 -298 229 -262 261 -294 231 -294 231 -294 229 -296 263 -268 271 -270 231 -264 261 -294 263 -234 299 -266 269 -266 233 -262 261 -262 257 -290 233 -298 231 -264 259 -290 231 -300 263 -270 273 -268 231 -264 261 -294 229 -296 229 -296 229 -296 267 -272 235 -268 257 -290 231 -266 259 -292 265 -272 269 -266 233 -300 231 -296 229 -296 229 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -294 229 -296 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -264 257 -290 231 -300 263 -270 273 -268 231 -296 229 -262 257 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -266 233 -262 261 -294 231 -294 231 -262 257 -290 231 -300 265 -236 299 -232 263 -294 233 -300 231 -298 229 -264 259 -296 261 -270 271 -270 231 -264 261 -294 229 -296 229 -264 255 -292 231 -298 233 -296 263 -268 271 -268 233 -264 257 -290 231 -298 231 -296 -RAW_Data: 231 -294 263 -234 301 -230 297 -262 235 -298 231 -298 261 -236 299 -232 295 -262 235 -298 231 -298 229 -262 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 231 -264 257 -290 263 -272 269 -266 235 -302 229 -296 229 -264 255 -258 259 -294 267 -268 265 -236 299 -264 235 -300 233 -262 257 -258 291 -262 267 -266 267 -270 271 -236 261 -290 231 -298 231 -296 231 -294 263 -234 299 -266 233 -302 231 -264 261 -294 229 -296 229 -296 229 -296 261 -236 299 -264 233 -300 231 -264 257 -258 259 -294 267 -268 233 -296 263 -234 299 -264 235 -300 231 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -264 257 -256 291 -264 233 -268 259 -292 231 -298 265 -236 301 -266 233 -300 231 -294 231 -294 229 -264 257 -290 231 -298 231 -298 263 -234 299 -266 235 -300 231 -264 257 -256 259 -294 267 -268 231 -298 267 -272 235 -268 261 -262 257 -256 291 -264 267 -268 265 -236 299 -264 235 -300 231 -296 229 -262 261 -296 229 -296 229 -262 295 -268 271 -270 231 -264 263 -294 229 -294 263 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -262 267 -268 265 -270 271 -268 233 -264 261 -294 229 -262 257 -292 231 -298 271 -274 237 -266 261 -262 255 -290 231 -300 233 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 293 -262 233 -302 263 -270 267 -266 233 -300 231 -296 229 -262 295 -268 265 -266 235 -300 231 -296 229 -264 261 -260 257 -292 231 -298 265 -270 273 -268 233 -262 261 -262 257 -290 233 -266 259 -292 265 -272 269 -266 235 -300 231 -294 229 -264 257 -290 231 -300 231 -296 263 -234 299 -266 233 -300 231 -298 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 233 -302 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 263 -236 301 -232 261 -296 267 -266 231 -264 257 -258 259 -260 293 -264 269 -268 265 -268 273 -234 261 -292 231 -266 259 -292 263 -272 269 -266 235 -300 231 -296 227 -262 257 -292 231 -266 261 -292 231 -298 265 -270 271 -270 233 -262 261 -262 257 -258 291 -304 243 -274 235 -264 261 -262 261 -294 229 -264 257 -290 231 -300 263 -236 301 -266 233 -300 231 -296 229 -264 255 -258 291 -264 233 -300 265 -268 273 -236 259 -292 231 -300 229 -298 261 -236 299 -266 233 -300 231 -296 231 -262 257 -290 231 -298 231 -298 263 -268 271 -270 231 -264 261 -294 229 -296 263 -268 273 -268 231 -296 229 -264 261 -294 229 -262 257 -292 231 -298 231 -298 261 -236 299 -266 235 -300 -RAW_Data: 231 -294 229 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 231 -296 263 -234 299 -232 297 -230 261 -262 293 -264 233 -302 265 -236 299 -264 233 -300 231 -298 229 -294 229 -262 257 -290 233 -300 231 -298 261 -236 297 -266 233 -300 231 -296 231 -294 229 -264 257 -258 259 -294 267 -272 269 -266 235 -300 231 -296 229 -294 231 -294 263 -234 299 -232 295 -264 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -262 261 -262 257 -292 231 -298 265 -270 273 -268 233 -262 257 -290 231 -266 259 -260 261 -294 267 -268 265 -234 299 -266 233 -300 231 -264 257 -258 291 -262 267 -266 267 -236 299 -264 235 -266 259 -292 231 -298 265 -270 273 -268 233 -262 261 -294 229 -296 231 -294 229 -294 263 -270 271 -270 231 -296 229 -262 257 -290 231 -298 233 -296 269 -272 235 -268 261 -262 261 -262 257 -290 231 -300 233 -296 263 -234 299 -264 235 -300 233 -262 261 -296 229 -296 229 -294 263 -236 299 -264 233 -302 231 -264 257 -288 231 -300 231 -264 257 -292 231 -298 265 -270 267 -266 233 -300 231 -262 257 -292 265 -270 269 -266 235 -300 231 -264 261 -294 229 -264 257 -258 259 -294 267 -268 231 -296 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 231 -264 259 -290 263 -272 267 -268 235 -300 231 -262 257 -290 233 -298 231 -298 263 -268 271 -268 233 -262 257 -258 291 -262 267 -268 231 -264 295 -268 265 -266 235 -300 231 -296 229 -262 261 -296 229 -296 229 -296 261 -270 271 -268 231 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -264 255 -290 233 -266 259 -292 231 -300 263 -270 273 -268 231 -264 261 -296 229 -294 263 -234 299 -266 235 -300 233 -262 257 -290 231 -264 261 -292 231 -300 265 -268 267 -266 235 -300 229 -264 257 -258 257 -294 269 -266 267 -236 299 -264 235 -266 259 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -298 229 -262 261 -262 257 -290 233 -298 265 -270 265 -266 235 -300 231 -262 257 -258 259 -260 295 -264 267 -268 265 -236 299 -264 235 -300 231 -296 229 -296 229 -262 289 -266 267 -270 235 -302 231 -264 257 -290 229 -300 231 -264 257 -292 231 -298 265 -270 271 -270 231 -264 261 -294 229 -264 257 -290 231 -300 231 -296 229 -296 263 -234 299 -266 233 -300 231 -264 257 -258 291 -262 269 -266 233 -262 295 -268 271 -270 233 -264 255 -258 259 -292 269 -268 263 -236 299 -266 -RAW_Data: 233 -300 231 -296 231 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -296 229 -264 293 -234 301 -266 233 -300 231 -296 229 -262 257 -258 291 -264 233 -300 265 -270 265 -266 235 -300 229 -264 257 -258 259 -260 295 -262 269 -274 267 -268 233 -300 231 -264 255 -290 233 -298 265 -270 265 -234 261 -296 265 -268 231 -296 231 -262 257 -256 291 -264 233 -300 265 -236 299 -266 233 -300 231 -296 231 -262 295 -268 265 -266 235 -300 231 -264 261 -262 257 -290 231 -266 261 -258 261 -294 267 -272 269 -266 235 -300 231 -294 229 -264 257 -258 259 -294 267 -272 269 -266 235 -300 231 -296 229 -264 255 -290 231 -266 261 -258 261 -294 267 -272 275 -238 261 -258 259 -260 293 -264 267 -268 265 -236 299 -264 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 231 -262 295 -268 265 -234 295 -262 235 -300 229 -264 257 -258 291 -262 235 -300 265 -236 299 -264 235 -300 231 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -264 257 -256 291 -264 267 -268 265 -268 271 -270 231 -296 229 -264 255 -258 291 -296 239 -276 239 -302 231 -262 261 -260 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -262 257 -258 291 -262 235 -300 265 -268 267 -266 233 -300 231 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -264 257 -258 291 -230 293 -264 233 -300 265 -236 301 -264 235 -298 231 -296 229 -296 229 -262 257 -292 263 -272 267 -268 235 -300 231 -296 229 -262 261 -262 257 -292 231 -300 231 -296 263 -236 299 -264 233 -302 231 -264 261 -294 229 -296 229 -264 255 -292 231 -298 233 -296 263 -268 271 -268 233 -264 257 -290 229 -266 261 -292 231 -300 271 -272 235 -268 257 -258 257 -260 295 -262 269 -268 265 -234 299 -266 235 -300 231 -296 229 -262 261 -262 257 -292 231 -298 265 -236 301 -266 233 -300 231 -296 229 -296 261 -236 299 -232 293 -264 233 -300 231 -298 229 -262 257 -290 231 -266 261 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 289 -264 267 -270 271 -270 231 -262 261 -294 229 -296 229 -262 257 -292 231 -298 265 -236 301 -266 233 -300 231 -296 229 -262 257 -290 231 -298 233 -296 263 -270 271 -268 231 -296 231 -262 255 -258 291 -230 295 -264 233 -300 265 -234 301 -232 263 -294 233 -300 231 -298 229 -264 293 -234 299 -266 235 -300 231 -294 231 -294 229 -264 257 -290 -RAW_Data: 231 -298 233 -296 263 -236 299 -264 233 -300 231 -298 229 -262 257 -290 231 -300 231 -298 229 -262 295 -268 271 -270 231 -264 261 -294 229 -296 263 -234 299 -266 233 -302 231 -264 261 -294 229 -262 257 -292 231 -298 231 -298 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 231 -298 269 -272 235 -266 257 -290 231 -298 231 -298 229 -296 261 -268 265 -266 235 -300 231 -296 229 -264 255 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 293 -268 267 -266 233 -300 231 -264 257 -290 231 -266 259 -292 233 -298 265 -270 265 -266 235 -300 231 -294 229 -264 257 -256 293 -294 241 -276 239 -268 263 -262 259 -294 231 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -262 261 -262 257 -258 291 -264 267 -268 265 -268 273 -268 231 -264 257 -256 293 -262 267 -234 259 -292 231 -300 263 -270 267 -266 233 -300 231 -264 261 -294 263 -234 301 -266 233 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 265 -234 301 -232 295 -264 233 -300 231 -296 229 -262 257 -290 231 -300 231 -296 231 -262 295 -268 271 -270 231 -264 261 -262 257 -258 291 -262 269 -272 275 -270 231 -264 257 -290 229 -266 261 -292 231 -300 231 -296 263 -234 299 -266 267 -268 231 -264 255 -258 291 -262 235 -300 265 -236 299 -232 293 -232 293 -264 233 -300 231 -296 263 -236 297 -266 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -264 255 -292 265 -272 267 -268 233 -300 231 -264 261 -294 229 -264 257 -258 259 -294 267 -268 265 -236 299 -266 233 -300 231 -264 261 -262 257 -290 231 -300 265 -236 301 -266 233 -300 231 -294 231 -262 257 -258 259 -294 267 -268 231 -264 295 -234 299 -266 235 -266 259 -292 231 -298 231 -296 231 -294 263 -234 301 -264 235 -300 231 -296 229 -264 255 -290 233 -266 259 -292 231 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 231 -294 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -262 255 -292 231 -266 259 -294 231 -300 263 -270 273 -268 231 -296 229 -294 229 -296 229 -296 267 -274 235 -300 229 -262 261 -294 229 -264 255 -292 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -262 261 -296 229 -296 261 -236 299 -264 235 -300 231 -264 257 -290 231 -300 265 -268 273 -268 233 -262 261 -262 257 -258 293 -228 295 -264 267 -274 267 -266 235 -300 231 -262 257 -258 -RAW_Data: 259 -262 293 -304 243 -274 235 -266 261 -262 259 -262 257 -290 233 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -258 259 -260 295 -264 267 -268 265 -268 273 -268 231 -296 231 -262 259 -262 257 -292 231 -298 233 -296 263 -236 299 -264 233 -302 231 -264 261 -294 229 -296 263 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 231 -300 263 -236 301 -266 233 -300 231 -296 229 -296 229 -262 261 -294 229 -296 229 -296 263 -268 271 -270 231 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 231 -298 265 -270 267 -266 233 -300 231 -262 257 -292 231 -298 231 -296 231 -294 269 -272 235 -268 257 -256 259 -294 267 -268 231 -298 261 -236 297 -266 233 -300 231 -296 231 -294 229 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -300 231 -262 257 -292 229 -300 231 -298 229 -262 295 -268 265 -266 235 -300 231 -296 229 -264 255 -290 231 -266 259 -294 231 -300 265 -234 301 -232 295 -262 267 -266 233 -262 263 -262 255 -258 293 -262 235 -300 265 -270 271 -268 231 -264 261 -294 229 -296 231 -294 263 -268 271 -270 231 -264 261 -294 229 -296 229 -264 257 -290 231 -298 265 -270 273 -268 231 -264 261 -262 257 -290 231 -266 261 -324 239 -276 237 -302 229 -262 255 -290 231 -300 233 -296 263 -234 299 -264 235 -300 231 -296 229 -296 227 -296 229 -296 229 -296 263 -234 299 -266 233 -300 231 -264 257 -290 265 -272 267 -268 235 -300 231 -262 261 -262 257 -290 233 -266 259 -292 265 -272 269 -266 235 -300 231 -264 261 -294 229 -296 229 -296 267 -272 235 -268 257 -258 257 -294 267 -268 231 -298 229 -262 295 -234 299 -266 235 -300 231 -262 257 -258 291 -262 267 -268 231 -296 263 -270 271 -268 231 -296 231 -262 261 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 263 -268 271 -270 233 -264 261 -260 257 -258 291 -264 233 -268 259 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -262 257 -290 265 -268 231 -296 263 -236 297 -266 235 -300 231 -296 229 -262 261 -262 289 -266 267 -270 271 -270 231 -262 255 -258 291 -262 269 -266 233 -262 295 -234 299 -266 235 -300 231 -264 255 -290 231 -300 231 -296 263 -236 299 -232 295 -230 293 -264 267 -268 231 -264 293 -268 265 -266 235 -300 231 -296 229 -296 229 -262 261 -262 -RAW_Data: 257 -290 265 -274 267 -268 235 -300 231 -262 257 -256 291 -270 271 -272 235 -300 231 -296 229 -264 261 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -294 229 -264 257 -258 259 -294 267 -274 267 -268 233 -268 259 -290 231 -300 231 -296 263 -234 301 -264 233 -300 231 -296 231 -262 257 -290 231 -300 231 -296 229 -296 263 -268 271 -270 231 -264 261 -294 231 -262 257 -290 231 -300 231 -296 263 -268 271 -270 231 -264 261 -262 257 -258 293 -262 267 -274 273 -270 231 -264 263 -260 257 -258 291 -262 235 -300 233 -262 295 -268 265 -266 235 -300 231 -296 229 -264 261 -294 229 -262 257 -292 231 -298 265 -236 301 -264 235 -300 231 -296 229 -264 255 -258 291 -264 233 -300 265 -268 273 -236 259 -292 231 -298 231 -298 229 -262 295 -268 265 -266 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -296 261 -236 299 -264 235 -300 233 -262 261 -294 229 -296 231 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -296 241 -276 237 -268 259 -290 229 -266 259 -294 231 -298 265 -236 299 -266 233 -300 231 -264 257 -258 291 -230 295 -262 269 -272 267 -266 235 -300 231 -262 257 -292 265 -270 269 -234 263 -294 233 -300 233 -296 229 -264 255 -258 291 -262 267 -268 231 -264 295 -268 271 -268 233 -264 257 -290 231 -266 259 -292 233 -298 265 -234 301 -266 233 -300 231 -296 229 -262 257 -258 291 -262 267 -268 265 -270 271 -270 231 -264 259 -262 257 -292 231 -298 233 -296 263 -236 299 -264 233 -302 231 -264 257 -290 229 -300 231 -264 257 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -264 233 -300 265 -234 301 -266 233 -300 231 -296 229 -296 229 -294 263 -268 273 -268 231 -296 229 -264 255 -258 291 -264 233 -268 259 -292 231 -298 265 -270 267 -266 233 -300 231 -262 261 -262 257 -290 233 -298 265 -270 273 -268 233 -264 261 -262 255 -258 291 -264 267 -268 231 -264 293 -268 273 -270 231 -264 255 -258 291 -264 233 -300 231 -296 269 -238 263 -262 261 -294 233 -266 261 -292 265 -270 269 -234 263 -294 233 -300 231 -264 257 -290 231 -300 231 -296 231 -294 263 -236 299 -264 233 -300 231 -296 231 -294 229 -264 257 -290 231 -300 231 -296 263 -234 299 -266 233 -302 231 -296 229 -262 257 -258 291 -230 295 -262 235 -300 263 -236 299 -266 233 -300 231 -296 231 -294 231 -262 261 -294 229 -296 263 -234 299 -266 -RAW_Data: 235 -300 231 -264 261 -294 229 -264 257 -290 231 -300 263 -270 267 -266 233 -302 229 -264 257 -258 291 -268 271 -270 237 -304 231 -262 261 -292 229 -264 257 -290 231 -298 233 -296 263 -236 299 -264 235 -300 231 -264 257 -258 289 -262 269 -268 231 -296 269 -238 263 -296 231 -298 231 -296 231 -262 293 -268 273 -268 233 -264 261 -262 257 -290 231 -266 259 -294 265 -272 267 -266 235 -300 231 -296 229 -262 295 -268 267 -266 233 -300 231 -296 229 -262 261 -262 257 -292 231 -266 259 -292 233 -298 265 -270 271 -270 231 -296 229 -264 259 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -264 261 -294 229 -296 231 -262 257 -290 231 -300 263 -270 273 -236 259 -260 259 -292 267 -268 265 -236 299 -264 235 -300 231 -264 257 -258 291 -230 293 -230 295 -264 267 -274 267 -232 295 -262 267 -268 231 -296 231 -262 255 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -300 231 -264 255 -290 233 -298 265 -270 273 -268 231 -264 261 -262 257 -290 231 -266 261 -260 259 -294 267 -274 267 -268 233 -300 231 -296 229 -262 257 -258 291 -296 239 -276 239 -268 263 -262 255 -258 291 -264 233 -300 265 -236 299 -232 263 -294 267 -268 231 -264 257 -256 291 -230 295 -264 233 -300 265 -268 273 -268 233 -264 255 -290 231 -298 265 -270 273 -270 231 -264 261 -260 257 -290 233 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -292 231 -298 231 -296 269 -274 235 -266 259 -288 231 -266 259 -292 231 -300 231 -296 263 -234 299 -266 233 -302 231 -296 229 -262 257 -258 291 -262 235 -300 233 -262 295 -268 265 -266 235 -300 231 -264 261 -262 257 -258 291 -230 295 -262 235 -300 263 -236 299 -266 235 -300 231 -262 257 -258 259 -294 267 -268 233 -264 293 -234 299 -266 233 -302 231 -296 229 -262 257 -258 291 -262 235 -300 265 -236 299 -264 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -296 261 -236 299 -266 233 -300 231 -296 231 -262 257 -288 231 -268 259 -260 259 -294 267 -274 267 -268 235 -300 229 -264 255 -292 231 -298 233 -296 269 -272 235 -300 229 -262 261 -262 257 -290 231 -300 265 -236 299 -266 235 -300 231 -294 229 -262 257 -290 233 -300 265 -236 299 -264 235 -300 231 -296 229 -264 261 -294 261 -236 299 -266 235 -300 231 -294 231 -294 229 -264 257 -258 259 -294 267 -268 265 -268 273 -268 231 -264 261 -262 257 -258 291 -264 267 -268 263 -236 299 -266 -RAW_Data: 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -268 273 -270 231 -264 255 -258 291 -230 295 -264 233 -300 265 -234 299 -266 235 -300 231 -296 229 -264 261 -294 229 -262 259 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -268 259 -290 231 -300 231 -296 263 -234 301 -266 233 -300 231 -296 229 -262 257 -258 291 -230 293 -264 269 -272 269 -266 233 -302 229 -264 257 -258 259 -294 267 -272 275 -270 233 -262 257 -258 291 -262 235 -300 231 -296 229 -296 261 -236 299 -264 235 -300 231 -264 257 -258 257 -262 293 -264 269 -266 265 -270 271 -236 261 -290 231 -300 231 -296 263 -268 271 -268 233 -296 229 -262 261 -296 229 -262 257 -292 263 -272 267 -268 235 -300 231 -296 229 -294 231 -262 287 -300 241 -272 235 -266 261 -262 255 -290 231 -266 259 -260 261 -294 267 -266 265 -236 301 -264 235 -300 231 -296 229 -294 229 -264 255 -290 231 -300 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -268 231 -296 263 -234 299 -266 233 -302 229 -298 229 -262 261 -294 231 -294 231 -294 229 -296 263 -268 271 -270 231 -296 229 -264 255 -258 291 -230 293 -264 269 -266 265 -236 299 -264 235 -300 231 -296 229 -262 257 -258 291 -262 235 -300 265 -270 271 -268 233 -262 261 -294 229 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -262 255 -292 231 -300 263 -270 267 -266 235 -300 231 -294 229 -296 229 -262 289 -300 241 -272 235 -264 261 -262 257 -256 291 -264 267 -268 265 -234 299 -266 235 -300 231 -262 259 -290 229 -300 231 -298 229 -262 295 -268 271 -268 233 -264 261 -294 229 -296 263 -234 301 -264 235 -300 231 -296 229 -262 257 -258 291 -262 269 -266 233 -262 295 -268 271 -270 233 -262 261 -262 257 -290 231 -300 231 -298 229 -264 293 -268 271 -270 233 -264 261 -262 255 -258 291 -264 267 -274 273 -270 233 -262 261 -262 257 -258 291 -264 233 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 233 -298 231 -264 257 -292 231 -298 265 -236 301 -266 233 -300 231 -296 229 -262 257 -290 231 -298 233 -296 263 -270 271 -234 261 -292 231 -266 259 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 267 -274 267 -268 235 -300 229 -296 229 -264 259 -296 261 -236 299 -266 235 -300 231 -294 229 -264 257 -290 231 -298 233 -296 231 -294 261 -268 273 -270 231 -264 261 -262 -RAW_Data: 257 -258 291 -296 241 -276 237 -302 229 -262 261 -262 255 -258 293 -262 269 -268 231 -262 295 -234 299 -266 235 -300 229 -264 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 233 -262 257 -290 231 -266 259 -292 233 -298 265 -268 267 -234 261 -296 233 -298 231 -296 231 -296 261 -236 299 -264 235 -300 233 -262 261 -294 229 -296 229 -264 257 -290 265 -270 269 -234 295 -262 233 -300 231 -266 257 -290 231 -266 259 -292 233 -298 265 -236 299 -266 233 -300 231 -296 229 -264 261 -262 257 -290 265 -272 269 -266 235 -300 231 -262 257 -258 291 -262 267 -268 233 -264 293 -234 299 -266 235 -300 231 -264 257 -258 257 -260 295 -264 267 -268 265 -270 271 -270 231 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -264 255 -292 231 -298 231 -298 229 -296 261 -268 271 -270 233 -264 261 -262 255 -290 265 -272 275 -270 233 -264 261 -262 255 -292 231 -300 231 -296 229 -296 263 -268 271 -268 233 -296 229 -264 259 -296 229 -296 229 -296 261 -270 271 -268 231 -264 257 -258 291 -262 235 -300 263 -236 301 -266 233 -300 229 -296 231 -294 229 -264 257 -290 231 -298 265 -236 301 -266 233 -300 231 -264 261 -294 229 -264 257 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 229 -294 263 -236 299 -264 235 -300 231 -264 257 -290 231 -266 259 -260 259 -294 267 -268 265 -270 271 -268 233 -262 261 -294 229 -264 257 -290 231 -300 231 -298 229 -262 295 -268 265 -266 235 -300 231 -296 229 -296 227 -262 257 -292 263 -274 273 -272 231 -264 257 -288 231 -300 231 -296 231 -294 263 -236 299 -264 233 -300 231 -298 229 -262 257 -258 259 -294 267 -274 269 -266 233 -300 231 -296 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -296 229 -262 257 -290 233 -298 231 -296 263 -268 273 -268 231 -296 229 -264 257 -256 291 -296 241 -276 239 -300 231 -262 255 -290 229 -300 231 -298 263 -234 299 -266 235 -300 231 -296 229 -262 261 -294 231 -296 229 -294 263 -268 273 -268 231 -264 263 -292 229 -296 263 -234 301 -266 233 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 263 -270 273 -268 233 -262 261 -262 257 -258 291 -264 233 -300 265 -270 271 -270 231 -264 261 -294 229 -262 259 -290 231 -300 231 -296 263 -268 271 -268 233 -296 229 -262 261 -262 257 -292 231 -298 265 -270 267 -266 233 -302 229 -296 229 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -264 233 -300 231 -298 -RAW_Data: 229 -294 231 -294 229 -296 229 -262 295 -268 267 -266 233 -300 231 -264 257 -290 231 -298 265 -236 301 -266 233 -302 229 -296 229 -262 261 -262 257 -292 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 229 -294 263 -268 273 -268 231 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -264 257 -290 231 -298 233 -296 231 -262 295 -266 273 -268 233 -264 257 -290 229 -300 265 -236 301 -264 235 -300 231 -262 257 -290 231 -266 259 -292 233 -298 265 -270 271 -270 231 -296 229 -262 255 -260 291 -304 243 -274 235 -264 261 -262 257 -256 291 -264 233 -268 259 -292 231 -298 265 -270 267 -266 233 -300 231 -264 255 -258 291 -262 267 -268 265 -236 299 -264 235 -300 233 -262 257 -256 293 -262 267 -234 261 -292 231 -298 265 -236 299 -264 235 -300 231 -296 229 -264 293 -234 301 -232 295 -264 233 -300 231 -264 257 -258 257 -294 267 -234 261 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -296 229 -296 229 -294 261 -270 267 -266 233 -300 231 -264 255 -292 231 -298 265 -270 273 -268 231 -264 261 -262 257 -290 231 -266 261 -260 259 -294 267 -268 265 -268 273 -268 231 -264 257 -256 291 -264 233 -302 231 -296 269 -270 237 -266 257 -258 257 -294 267 -268 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 259 -296 229 -296 229 -296 261 -270 271 -268 233 -264 261 -294 229 -296 261 -236 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 229 -296 263 -268 271 -268 233 -264 261 -294 229 -264 257 -290 231 -300 271 -272 237 -266 257 -290 229 -266 261 -292 231 -300 263 -236 301 -232 263 -294 233 -300 231 -264 257 -290 231 -268 259 -292 231 -300 263 -270 273 -268 231 -264 261 -262 257 -290 231 -266 261 -260 259 -294 267 -268 265 -234 299 -266 267 -268 231 -264 259 -262 257 -292 231 -266 259 -294 265 -272 267 -266 235 -300 231 -264 261 -262 255 -292 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 257 -292 231 -266 259 -292 265 -272 269 -266 235 -300 229 -296 229 -296 263 -234 299 -264 235 -300 231 -296 229 -264 255 -292 231 -266 259 -260 259 -294 267 -268 265 -270 271 -268 231 -296 231 -262 261 -262 257 -290 231 -300 271 -274 235 -268 257 -256 257 -294 267 -268 265 -236 301 -264 233 -302 231 -296 229 -262 257 -290 231 -298 231 -298 263 -268 271 -270 231 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -296 229 -262 261 -262 -RAW_Data: 257 -258 291 -264 269 -266 265 -270 271 -268 233 -262 261 -262 257 -258 291 -262 267 -268 231 -298 263 -234 299 -264 233 -302 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 271 -238 265 -262 259 -294 267 -234 261 -290 265 -272 267 -268 233 -300 231 -296 229 -296 229 -262 257 -258 291 -262 267 -266 267 -236 299 -264 235 -300 231 -296 229 -262 261 -296 229 -262 257 -292 265 -272 267 -266 235 -302 229 -296 229 -264 261 -294 261 -270 265 -266 235 -300 231 -296 229 -262 257 -258 291 -262 267 -268 231 -298 263 -268 271 -268 231 -264 257 -290 231 -298 231 -298 269 -272 235 -266 259 -258 257 -294 267 -234 259 -292 231 -300 263 -270 267 -266 233 -302 229 -296 229 -296 229 -262 261 -294 229 -296 263 -270 271 -270 231 -264 255 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 229 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -262 255 -292 231 -300 271 -272 237 -266 263 -262 259 -262 257 -258 293 -262 269 -266 265 -270 271 -268 231 -264 261 -262 257 -258 291 -264 233 -300 265 -236 299 -266 233 -300 231 -298 229 -262 257 -258 291 -262 235 -300 263 -236 299 -266 233 -302 229 -298 229 -262 257 -258 291 -262 269 -272 269 -266 233 -300 231 -296 229 -262 257 -292 231 -266 259 -292 231 -300 265 -234 301 -266 233 -300 231 -264 261 -294 229 -264 257 -290 231 -266 261 -292 265 -272 267 -266 235 -300 231 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -292 269 -268 231 -296 263 -268 271 -270 231 -264 257 -258 257 -294 267 -268 233 -296 263 -234 299 -232 295 -264 233 -300 231 -296 263 -234 299 -266 233 -300 231 -296 229 -264 255 -292 231 -298 233 -296 231 -262 293 -268 271 -270 233 -264 261 -262 255 -290 265 -272 275 -270 233 -264 261 -262 255 -290 233 -266 259 -292 233 -298 265 -270 271 -270 231 -264 261 -262 257 -290 231 -266 261 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -264 255 -292 231 -298 231 -298 263 -268 271 -270 231 -296 229 -264 255 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 255 -258 291 -230 295 -264 233 -300 265 -234 299 -232 297 -262 235 -298 231 -298 229 -262 257 -290 231 -300 231 -296 263 -236 299 -264 233 -300 231 -298 229 -294 231 -294 263 -234 299 -266 267 -268 231 -264 255 -290 231 -266 261 -292 265 -272 267 -268 233 -300 231 -296 229 -296 229 -262 289 -266 275 -272 -RAW_Data: 235 -264 261 -262 261 -262 257 -258 291 -264 233 -300 265 -236 299 -266 235 -298 231 -296 229 -296 229 -264 255 -290 231 -300 265 -270 271 -236 261 -290 231 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -300 231 -296 263 -268 273 -268 231 -264 261 -294 229 -296 263 -268 273 -268 231 -296 231 -262 261 -262 257 -290 231 -266 261 -292 231 -300 263 -236 301 -264 233 -300 231 -264 257 -292 231 -266 259 -292 265 -272 267 -268 235 -300 229 -296 229 -296 229 -296 229 -294 229 -296 229 -296 263 -234 299 -264 235 -268 259 -260 257 -294 267 -268 265 -234 299 -266 235 -300 231 -296 229 -264 255 -258 291 -262 267 -268 231 -296 263 -236 299 -264 235 -300 231 -264 261 -294 229 -264 257 -258 259 -294 267 -272 269 -266 235 -302 229 -296 229 -296 229 -262 295 -268 265 -266 235 -300 231 -264 257 -256 291 -262 267 -234 261 -292 231 -300 263 -270 273 -268 231 -264 257 -290 231 -266 259 -294 231 -298 271 -240 263 -296 231 -266 259 -258 259 -294 267 -266 267 -236 299 -264 235 -300 231 -296 229 -296 229 -262 257 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 263 -234 299 -266 233 -300 231 -264 257 -258 291 -262 267 -268 231 -264 295 -268 271 -270 231 -264 261 -262 257 -290 231 -300 233 -296 229 -264 293 -268 271 -270 231 -264 263 -260 261 -262 257 -292 231 -300 231 -296 263 -236 299 -264 235 -300 231 -264 257 -290 231 -298 231 -264 259 -290 231 -298 265 -270 267 -266 233 -300 231 -262 257 -258 293 -262 267 -234 259 -292 231 -300 263 -236 301 -266 233 -300 231 -262 257 -292 231 -266 259 -292 231 -300 263 -270 273 -268 233 -294 229 -262 257 -290 231 -300 265 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -262 261 -294 263 -268 267 -266 235 -300 231 -262 263 -262 255 -258 293 -262 267 -234 261 -292 231 -298 265 -268 273 -268 233 -262 263 -262 255 -292 231 -300 231 -296 269 -272 235 -268 261 -262 261 -262 255 -292 265 -272 269 -266 235 -300 231 -262 261 -296 229 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -300 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -262 235 -300 231 -296 263 -234 301 -266 233 -300 231 -262 257 -258 -RAW_Data: 291 -230 293 -264 267 -268 265 -236 299 -264 235 -300 231 -264 257 -288 231 -268 259 -260 259 -294 267 -268 265 -268 273 -268 231 -296 231 -262 261 -294 229 -296 229 -296 263 -268 271 -236 259 -260 259 -292 267 -268 265 -236 299 -232 295 -264 233 -300 231 -296 229 -264 255 -258 291 -264 233 -302 265 -234 299 -266 233 -300 231 -296 229 -264 293 -268 267 -266 233 -302 231 -262 261 -262 257 -292 231 -298 233 -296 263 -234 299 -266 267 -268 231 -264 255 -258 291 -230 295 -264 267 -272 273 -238 261 -292 231 -298 231 -296 229 -264 293 -234 299 -266 235 -300 231 -296 229 -264 255 -290 231 -300 231 -298 229 -262 295 -268 271 -270 233 -264 259 -294 229 -264 257 -258 291 -230 295 -264 233 -300 265 -234 299 -266 235 -300 231 -296 229 -262 261 -296 229 -262 257 -292 231 -300 263 -270 273 -268 231 -296 229 -262 257 -290 231 -268 259 -292 265 -272 267 -268 233 -300 231 -264 261 -262 257 -258 259 -296 267 -234 259 -292 231 -300 263 -236 301 -266 233 -300 231 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -262 257 -292 229 -266 261 -292 231 -300 263 -236 301 -264 235 -300 231 -296 229 -264 255 -258 291 -296 241 -276 237 -300 231 -262 261 -262 255 -258 293 -262 235 -300 265 -236 299 -264 233 -300 231 -298 229 -262 261 -262 257 -290 233 -298 265 -270 273 -268 233 -262 257 -258 291 -262 267 -234 261 -292 231 -298 265 -268 267 -266 235 -300 229 -296 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -260 259 -294 267 -268 265 -270 271 -268 231 -296 231 -262 261 -262 255 -292 231 -266 261 -292 265 -272 267 -268 235 -300 229 -296 229 -264 255 -258 291 -264 267 -274 275 -270 231 -264 261 -260 257 -258 291 -262 269 -266 233 -264 293 -234 299 -264 269 -268 231 -264 261 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -294 229 -296 263 -234 299 -264 235 -300 231 -296 229 -264 257 -258 259 -294 267 -268 231 -296 263 -268 271 -270 231 -264 259 -296 229 -296 263 -234 299 -266 233 -300 231 -264 257 -258 259 -294 267 -268 231 -264 295 -234 299 -264 235 -302 231 -264 255 -290 231 -300 231 -296 263 -236 299 -264 235 -300 233 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -262 293 -264 269 -272 269 -266 235 -300 229 -264 257 -290 231 -300 231 -296 229 -296 263 -234 299 -266 233 -300 231 -296 229 -264 261 -262 289 -264 269 -270 -RAW_Data: 271 -268 231 -262 261 -294 229 -296 231 -262 257 -290 231 -300 265 -234 301 -266 235 -298 231 -296 229 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -266 233 -300 231 -264 257 -290 231 -298 233 -296 231 -262 293 -268 273 -268 233 -264 255 -258 291 -264 233 -302 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -300 231 -264 261 -294 263 -268 267 -232 263 -294 267 -268 231 -264 261 -262 257 -290 231 -266 261 -292 265 -270 269 -266 235 -300 231 -262 259 -258 257 -262 293 -306 243 -274 235 -264 261 -262 257 -256 291 -262 267 -268 231 -298 263 -234 299 -264 233 -302 229 -298 229 -262 257 -258 291 -264 233 -300 265 -268 273 -270 231 -262 261 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -266 233 -300 231 -296 231 -262 261 -294 263 -234 299 -266 269 -266 233 -262 261 -262 257 -258 291 -262 267 -268 233 -264 293 -234 299 -266 267 -268 233 -262 261 -294 229 -264 257 -290 231 -298 233 -296 263 -270 271 -268 231 -264 263 -260 257 -290 265 -266 267 -234 301 -264 235 -300 231 -296 229 -262 257 -258 259 -294 267 -234 261 -292 231 -298 265 -270 267 -264 235 -300 231 -262 261 -262 257 -258 291 -264 267 -274 273 -270 233 -264 259 -296 229 -262 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 231 -264 257 -258 259 -292 269 -266 233 -264 295 -266 273 -268 233 -264 261 -262 255 -292 231 -266 259 -292 233 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -264 293 -268 267 -266 233 -300 231 -264 261 -262 257 -292 231 -266 259 -292 233 -298 265 -236 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 231 -262 261 -294 263 -268 273 -268 233 -264 261 -262 261 -294 261 -270 267 -266 233 -300 231 -296 229 -296 229 -262 257 -258 291 -262 267 -268 265 -268 273 -270 231 -264 261 -262 255 -292 231 -300 231 -296 269 -272 235 -266 259 -256 259 -294 267 -266 233 -296 263 -234 299 -266 233 -300 231 -298 229 -262 261 -294 229 -296 231 -294 263 -234 299 -266 233 -302 231 -264 255 -290 265 -272 269 -266 235 -300 231 -264 261 -294 229 -296 229 -264 257 -288 265 -272 269 -266 235 -300 231 -296 229 -262 257 -290 231 -300 271 -274 235 -266 259 -256 257 -294 269 -234 261 -292 231 -298 263 -236 301 -266 233 -300 231 -264 257 -258 289 -230 295 -264 267 -268 263 -270 271 -268 233 -262 263 -262 255 -258 293 -262 235 -300 231 -296 -RAW_Data: 263 -234 299 -266 233 -300 231 -296 229 -296 229 -296 261 -270 271 -268 233 -264 261 -262 255 -258 293 -262 267 -234 261 -292 231 -298 265 -236 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -296 231 -262 257 -256 291 -264 267 -274 275 -270 231 -264 261 -292 229 -264 257 -258 291 -264 233 -300 265 -234 301 -266 233 -300 231 -264 257 -258 289 -264 267 -268 265 -234 301 -230 295 -230 295 -262 235 -300 231 -296 263 -234 299 -266 233 -302 229 -264 261 -296 229 -262 257 -292 229 -300 265 -270 265 -266 235 -300 231 -262 257 -258 291 -270 269 -272 237 -302 231 -262 261 -262 257 -290 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -296 227 -262 257 -290 265 -274 267 -268 235 -300 231 -262 257 -290 231 -300 265 -268 267 -266 233 -300 231 -264 261 -262 257 -290 231 -266 261 -292 265 -272 267 -268 233 -302 229 -264 261 -296 229 -296 229 -262 261 -294 231 -296 261 -270 271 -268 233 -264 261 -262 257 -290 231 -300 263 -270 273 -268 233 -264 259 -262 257 -258 293 -262 267 -266 233 -264 295 -232 301 -266 233 -300 231 -296 231 -262 257 -290 229 -300 231 -264 257 -292 231 -300 263 -270 273 -268 233 -262 261 -296 229 -262 257 -290 231 -300 231 -296 271 -270 237 -266 263 -260 261 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -302 231 -264 261 -294 229 -296 229 -296 261 -236 299 -264 235 -300 231 -262 257 -292 231 -300 263 -270 273 -268 233 -262 261 -262 257 -292 231 -266 259 -292 265 -272 267 -268 235 -300 231 -262 261 -262 257 -258 293 -296 239 -276 239 -266 259 -258 257 -294 267 -268 231 -296 263 -234 299 -266 233 -300 231 -264 257 -292 231 -266 259 -292 265 -272 267 -266 235 -302 231 -262 257 -290 265 -272 267 -234 295 -262 233 -302 231 -264 261 -262 257 -258 291 -264 233 -302 231 -262 295 -268 271 -270 233 -264 255 -290 231 -300 231 -296 229 -296 263 -234 299 -266 233 -302 231 -264 259 -262 257 -292 231 -298 231 -298 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 255 -258 291 -230 295 -264 233 -300 265 -236 299 -266 233 -300 231 -296 229 -296 229 -262 257 -290 231 -300 263 -270 267 -266 235 -266 259 -292 231 -298 265 -236 301 -264 233 -300 231 -296 231 -262 261 -294 229 -264 257 -290 233 -298 231 -296 263 -234 301 -264 235 -300 231 -296 229 -264 255 -290 -RAW_Data: 231 -300 265 -270 273 -268 231 -264 257 -288 231 -266 259 -294 231 -300 231 -296 263 -268 271 -270 233 -262 257 -256 293 -262 267 -266 233 -296 269 -270 237 -266 257 -258 257 -262 293 -264 269 -268 265 -234 299 -266 233 -300 231 -296 229 -262 257 -292 231 -298 231 -296 263 -270 271 -268 233 -264 261 -262 255 -290 233 -266 259 -292 233 -298 265 -270 265 -266 235 -300 229 -296 231 -294 229 -264 293 -268 273 -268 233 -264 261 -260 257 -290 233 -266 259 -292 233 -298 265 -236 299 -266 235 -300 229 -296 231 -262 261 -262 257 -290 231 -266 261 -292 231 -300 263 -270 273 -268 233 -296 229 -262 257 -288 231 -300 231 -298 269 -272 235 -268 261 -262 261 -262 255 -292 231 -300 233 -264 293 -234 299 -266 235 -300 231 -264 257 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 231 -294 263 -234 299 -266 233 -300 231 -296 231 -262 257 -258 259 -292 267 -234 261 -294 265 -270 269 -266 235 -300 229 -264 257 -258 259 -294 267 -274 275 -270 231 -264 257 -288 231 -300 231 -296 231 -262 295 -268 265 -266 235 -300 231 -296 229 -264 255 -258 291 -264 233 -300 265 -268 273 -268 233 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -290 233 -266 259 -292 231 -300 263 -270 273 -268 233 -262 263 -294 229 -262 257 -290 233 -298 265 -270 265 -266 235 -300 231 -294 231 -294 229 -264 261 -262 287 -300 241 -274 235 -264 261 -262 257 -288 231 -268 261 -292 231 -298 265 -268 267 -266 235 -298 231 -264 261 -262 257 -258 293 -262 267 -266 233 -296 263 -234 299 -264 235 -300 231 -296 229 -262 257 -258 291 -264 233 -300 265 -236 301 -264 235 -300 229 -296 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 255 -292 231 -298 231 -264 257 -292 265 -270 269 -234 295 -264 233 -300 231 -264 257 -290 231 -298 265 -270 271 -270 231 -264 257 -256 291 -262 269 -234 261 -292 231 -298 231 -296 263 -268 271 -268 233 -296 229 -262 257 -290 231 -266 259 -260 261 -294 267 -268 265 -234 299 -264 235 -300 233 -262 261 -262 257 -292 263 -274 273 -270 233 -296 227 -296 229 -296 229 -262 257 -292 231 -298 265 -236 301 -232 261 -294 267 -268 231 -264 257 -290 231 -266 259 -260 259 -294 267 -268 265 -270 271 -268 233 -262 261 -262 257 -258 291 -230 295 -264 235 -300 269 -274 235 -266 257 -290 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 229 -264 255 -292 231 -298 231 -298 -RAW_Data: 263 -234 299 -266 233 -300 231 -298 229 -262 295 -268 265 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -260 259 -296 267 -272 269 -266 235 -300 231 -262 257 -290 231 -268 259 -258 293 -302 243 -274 235 -264 261 -262 255 -290 233 -298 231 -298 263 -234 301 -264 233 -300 231 -264 257 -292 229 -300 231 -298 229 -262 295 -268 271 -270 231 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 233 -298 265 -270 265 -266 235 -300 231 -294 229 -296 229 -296 229 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -294 229 -264 257 -258 259 -294 267 -268 231 -296 263 -268 271 -270 231 -262 261 -296 229 -296 229 -296 261 -270 271 -268 231 -296 231 -262 261 -262 257 -258 291 -264 267 -268 265 -234 299 -266 233 -300 231 -296 231 -294 229 -264 261 -294 261 -270 271 -236 261 -260 259 -292 267 -268 231 -264 295 -234 299 -264 235 -302 231 -264 261 -262 255 -260 291 -230 295 -264 267 -272 267 -266 235 -300 231 -296 229 -294 231 -294 263 -268 271 -270 231 -296 229 -264 255 -258 291 -262 267 -268 231 -298 261 -236 297 -266 233 -300 231 -296 231 -294 229 -264 257 -258 259 -294 267 -268 265 -234 299 -266 233 -302 231 -296 229 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -262 255 -292 231 -300 231 -296 231 -262 295 -234 299 -264 235 -300 231 -298 229 -262 261 -294 229 -264 257 -292 231 -298 231 -296 263 -236 299 -264 235 -300 233 -262 257 -290 231 -298 231 -298 263 -234 299 -232 295 -264 233 -268 259 -292 231 -298 265 -268 267 -266 235 -300 231 -294 229 -264 255 -258 293 -228 295 -262 269 -274 267 -266 235 -300 231 -262 263 -294 229 -296 263 -234 299 -264 235 -300 231 -296 229 -264 257 -290 231 -266 259 -292 233 -298 265 -270 271 -270 231 -264 255 -258 291 -230 295 -264 233 -300 271 -238 265 -294 233 -264 261 -290 231 -300 263 -270 273 -268 233 -262 261 -296 229 -262 257 -290 231 -300 231 -298 261 -270 271 -268 231 -298 229 -262 257 -288 231 -268 259 -292 231 -300 265 -268 267 -266 235 -300 231 -294 229 -296 229 -264 255 -290 233 -298 265 -236 301 -266 233 -300 231 -294 229 -296 229 -264 255 -292 231 -298 231 -296 263 -236 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -292 233 -298 265 -270 265 -266 235 -300 231 -262 257 -258 291 -262 267 -272 275 -272 233 -262 261 -262 255 -258 291 -264 267 -268 231 -264 -RAW_Data: 293 -268 267 -266 233 -302 231 -262 263 -260 257 -258 293 -262 267 -266 267 -268 271 -270 231 -264 257 -290 229 -300 265 -268 267 -266 235 -300 231 -264 261 -262 257 -290 231 -300 231 -298 229 -262 293 -268 273 -270 231 -264 261 -294 229 -296 263 -268 271 -270 231 -264 263 -260 257 -290 231 -300 231 -296 231 -262 295 -268 271 -270 233 -264 255 -290 231 -298 231 -298 229 -296 263 -268 271 -268 233 -296 229 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -292 231 -298 231 -298 263 -234 299 -264 235 -300 231 -296 229 -296 229 -296 229 -262 257 -290 231 -300 265 -236 299 -266 235 -300 229 -296 229 -264 255 -292 231 -266 259 -292 233 -298 265 -270 265 -266 233 -300 231 -296 229 -296 229 -264 255 -290 233 -298 265 -270 265 -266 235 -300 231 -294 229 -296 229 -264 255 -290 233 -298 265 -270 265 -266 235 -300 231 -294 231 -294 229 -296 263 -268 271 -268 233 -264 261 -262 255 -260 291 -262 235 -300 231 -296 263 -234 299 -266 233 -300 231 -298 229 -262 257 -290 231 -300 231 -296 231 -262 293 -268 273 -270 231 -264 261 -262 257 -290 231 -300 263 -270 267 -266 235 -300 231 -294 229 -264 257 -258 259 -294 267 -268 265 -234 301 -264 233 -300 231 -298 229 -262 257 -258 291 -262 267 -268 265 -236 299 -264 233 -302 231 -264 261 -294 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 267 -268 231 -264 295 -234 299 -266 233 -302 229 -296 229 -296 229 -264 255 -258 291 -264 233 -300 265 -236 299 -266 233 -300 231 -296 231 -262 257 -256 293 -296 239 -276 237 -302 231 -262 255 -290 231 -266 259 -292 233 -298 265 -270 265 -266 235 -300 231 -262 257 -258 291 -230 295 -262 235 -300 263 -270 273 -268 231 -264 257 -290 229 -300 265 -270 265 -266 235 -300 231 -294 231 -294 229 -264 257 -290 231 -298 231 -298 263 -268 273 -268 231 -264 261 -262 257 -258 291 -304 243 -274 235 -264 261 -262 261 -262 257 -290 231 -300 263 -270 267 -232 263 -294 267 -268 231 -264 261 -294 229 -296 229 -296 263 -268 271 -268 233 -296 229 -262 261 -296 229 -296 261 -236 299 -264 235 -300 233 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -270 231 -296 229 -262 261 -294 231 -294 231 -294 231 -294 263 -268 271 -270 231 -264 261 -294 229 -264 255 -292 265 -272 275 -270 231 -264 261 -262 255 -292 231 -300 231 -296 263 -270 271 -268 231 -264 261 -294 229 -264 257 -258 -RAW_Data: 291 -262 269 -272 269 -232 263 -296 233 -300 231 -296 229 -262 257 -292 231 -266 259 -292 265 -272 267 -268 235 -300 229 -296 231 -262 257 -290 231 -300 231 -296 263 -234 299 -266 233 -302 231 -264 261 -262 255 -292 231 -266 259 -294 265 -272 267 -266 235 -300 231 -296 229 -294 263 -268 265 -266 235 -300 231 -296 229 -264 255 -290 231 -266 261 -260 259 -294 267 -268 265 -234 299 -266 233 -300 231 -264 257 -258 259 -294 267 -268 265 -270 271 -268 233 -262 263 -260 257 -292 231 -298 233 -296 263 -234 299 -232 295 -264 233 -300 231 -264 257 -258 257 -294 269 -266 267 -236 299 -264 235 -300 229 -264 257 -258 291 -264 233 -300 231 -298 261 -236 299 -232 293 -264 233 -302 231 -264 257 -288 265 -272 269 -266 235 -300 231 -262 257 -258 291 -230 295 -264 233 -300 265 -236 299 -264 235 -300 231 -296 229 -264 261 -260 257 -258 293 -262 269 -266 265 -236 299 -264 235 -300 231 -264 261 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -294 229 -264 257 -258 259 -294 267 -268 231 -296 263 -268 271 -268 233 -262 257 -258 291 -264 233 -302 231 -262 295 -234 301 -232 261 -296 267 -268 231 -262 295 -268 267 -264 235 -300 231 -294 231 -262 257 -290 231 -300 231 -296 231 -294 263 -268 273 -268 231 -296 231 -262 257 -288 265 -272 275 -270 233 -264 261 -260 257 -290 231 -266 261 -292 231 -300 263 -270 273 -270 231 -264 261 -260 257 -258 293 -262 267 -266 267 -268 271 -270 231 -264 257 -256 291 -262 267 -268 265 -236 301 -264 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -236 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 231 -294 263 -234 299 -266 235 -300 231 -296 229 -296 229 -262 295 -234 299 -266 235 -300 231 -264 255 -258 259 -294 267 -268 265 -236 299 -264 235 -300 231 -264 261 -294 229 -264 257 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -300 231 -296 229 -262 257 -258 291 -262 235 -300 263 -270 273 -268 233 -262 257 -258 259 -262 293 -262 269 -268 265 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -296 229 -262 293 -270 265 -266 235 -300 229 -296 231 -262 257 -258 291 -262 235 -300 231 -296 263 -268 271 -270 231 -264 261 -262 257 -258 291 -296 241 -276 237 -302 229 -264 255 -290 229 -300 231 -298 263 -234 299 -264 235 -300 233 -262 261 -294 231 -262 257 -290 231 -300 265 -268 267 -266 235 -300 -RAW_Data: 229 -296 231 -262 293 -236 299 -266 235 -300 229 -296 229 -264 255 -260 291 -262 267 -234 261 -292 231 -298 265 -268 273 -268 233 -262 261 -262 257 -290 233 -266 259 -292 233 -298 265 -270 265 -266 235 -300 229 -296 231 -262 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 233 -262 257 -258 291 -262 267 -266 233 -296 263 -234 299 -264 269 -266 233 -262 257 -258 291 -262 267 -234 261 -292 231 -298 265 -270 271 -270 231 -264 255 -290 231 -266 259 -294 231 -300 271 -238 265 -294 233 -266 259 -258 259 -294 267 -266 265 -236 301 -264 233 -302 229 -298 229 -262 261 -262 257 -290 233 -298 265 -270 267 -266 233 -300 231 -296 229 -296 261 -236 299 -264 235 -300 231 -264 257 -258 257 -294 267 -268 233 -296 263 -268 271 -268 231 -298 229 -262 257 -290 231 -298 231 -298 269 -272 235 -266 259 -258 257 -260 295 -262 269 -268 231 -264 293 -268 267 -266 233 -300 231 -264 257 -290 231 -298 231 -298 263 -234 299 -266 235 -300 231 -262 259 -290 229 -266 261 -292 231 -300 263 -270 267 -232 263 -294 267 -268 231 -262 257 -290 265 -272 269 -266 235 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -294 229 -264 257 -290 233 -298 265 -270 265 -266 235 -300 231 -294 229 -296 229 -264 255 -258 291 -304 243 -274 235 -264 261 -262 257 -290 231 -266 259 -260 259 -294 267 -268 265 -270 271 -268 231 -264 263 -294 229 -294 231 -294 229 -296 263 -268 271 -236 261 -292 231 -266 259 -290 231 -300 263 -270 267 -266 233 -302 229 -296 229 -296 229 -262 257 -290 233 -298 265 -270 265 -266 235 -300 231 -294 231 -294 263 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -292 233 -298 265 -236 301 -266 233 -300 231 -294 229 -264 257 -258 259 -294 267 -272 269 -266 235 -300 231 -296 229 -294 231 -294 229 -264 257 -290 231 -300 231 -296 269 -272 235 -268 257 -288 231 -298 231 -298 263 -234 301 -264 233 -300 231 -296 231 -262 257 -258 291 -262 267 -268 231 -296 263 -236 297 -266 233 -300 231 -296 231 -262 257 -258 291 -228 295 -264 267 -274 267 -268 235 -300 229 -264 255 -290 231 -300 265 -270 267 -266 233 -300 231 -294 231 -262 261 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -296 229 -264 255 -258 291 -296 241 -276 237 -300 231 -262 255 -258 291 -262 269 -266 233 -262 295 -234 299 -266 235 -300 231 -294 231 -262 -RAW_Data: 257 -258 291 -264 233 -300 265 -234 299 -266 235 -266 259 -292 231 -300 263 -270 267 -266 235 -300 229 -264 255 -292 231 -298 231 -298 229 -296 263 -268 271 -268 233 -296 229 -262 261 -294 231 -294 263 -270 271 -268 231 -264 257 -258 291 -262 267 -234 261 -292 231 -298 265 -236 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 263 -236 299 -264 267 -268 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -268 259 -258 257 -294 269 -274 267 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -264 257 -292 231 -298 265 -268 267 -266 235 -300 231 -294 229 -264 255 -258 293 -262 233 -302 263 -270 267 -266 233 -300 231 -296 229 -262 261 -262 257 -290 265 -272 275 -270 233 -264 261 -294 229 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -296 229 -262 261 -294 229 -296 231 -294 263 -268 273 -236 259 -260 257 -294 267 -268 231 -264 295 -234 299 -266 235 -300 231 -262 263 -262 255 -260 291 -262 235 -300 263 -236 301 -264 233 -300 231 -296 231 -294 263 -234 301 -264 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -236 299 -266 233 -300 231 -264 257 -258 257 -262 293 -264 269 -272 275 -236 261 -292 231 -298 231 -296 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -300 231 -296 263 -234 299 -266 233 -300 231 -264 257 -258 259 -260 295 -264 267 -268 265 -236 299 -264 235 -300 231 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -294 229 -296 231 -262 261 -294 229 -296 229 -296 263 -234 299 -266 233 -300 231 -298 229 -262 261 -262 257 -258 291 -264 233 -302 265 -234 299 -266 233 -300 231 -264 257 -258 259 -262 293 -264 267 -268 271 -274 235 -266 261 -262 255 -258 291 -264 267 -268 265 -234 299 -266 233 -302 231 -264 261 -294 229 -296 229 -296 229 -262 295 -268 271 -270 231 -264 263 -260 261 -294 263 -270 265 -266 235 -300 231 -294 231 -294 231 -262 257 -256 293 -262 267 -268 265 -270 271 -268 231 -264 261 -294 229 -296 229 -296 267 -272 235 -300 231 -262 261 -262 257 -258 291 -262 269 -272 269 -266 235 -300 229 -296 231 -262 257 -256 291 -264 233 -302 265 -234 299 -266 233 -300 231 -296 231 -262 293 -268 267 -232 295 -264 233 -300 231 -296 229 -264 255 -290 231 -266 261 -292 265 -272 267 -268 235 -300 231 -262 257 -258 291 -230 295 -262 235 -300 263 -236 301 -264 233 -300 231 -296 231 -262 257 -290 231 -266 -RAW_Data: 291 -300 243 -272 235 -264 257 -256 259 -292 269 -268 231 -296 231 -262 293 -268 273 -270 231 -264 261 -262 255 -292 231 -266 259 -260 261 -294 267 -266 265 -236 299 -264 235 -300 231 -264 257 -258 259 -294 267 -268 231 -296 263 -268 273 -234 261 -292 229 -266 259 -292 231 -300 265 -234 301 -234 261 -296 231 -300 231 -296 231 -262 257 -258 259 -294 267 -268 265 -236 299 -266 233 -300 231 -296 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -264 257 -290 231 -300 265 -268 273 -268 233 -264 261 -262 257 -258 291 -228 295 -296 241 -276 239 -268 263 -260 261 -262 257 -258 291 -262 267 -268 265 -236 301 -264 233 -300 231 -296 229 -264 261 -262 255 -292 265 -272 269 -266 235 -300 231 -262 257 -258 291 -262 269 -234 261 -290 231 -300 263 -236 299 -266 233 -300 231 -264 257 -292 263 -272 267 -268 235 -300 231 -294 229 -296 229 -296 229 -262 257 -292 231 -298 231 -298 263 -268 271 -268 233 -262 261 -262 257 -258 293 -262 267 -234 261 -292 231 -298 265 -270 271 -270 231 -264 261 -262 257 -290 231 -300 271 -274 235 -266 263 -260 261 -262 257 -290 233 -298 231 -298 263 -234 299 -232 295 -264 233 -300 231 -296 229 -264 255 -292 231 -298 265 -270 271 -270 231 -264 261 -294 229 -296 263 -236 299 -264 235 -300 231 -294 231 -262 257 -258 291 -230 293 -264 267 -268 265 -268 273 -268 231 -264 261 -294 229 -296 263 -234 301 -264 235 -300 231 -264 255 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -266 233 -262 257 -290 231 -298 231 -298 263 -234 299 -266 233 -302 229 -264 261 -296 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 291 -230 295 -264 267 -274 267 -266 235 -300 231 -262 257 -258 259 -294 267 -268 231 -296 263 -236 299 -264 235 -300 231 -296 229 -262 261 -294 263 -270 265 -266 235 -300 231 -262 257 -292 229 -300 231 -264 257 -292 231 -298 265 -236 301 -264 235 -300 229 -296 231 -262 257 -256 293 -262 269 -266 233 -262 295 -234 299 -264 235 -300 231 -264 257 -290 231 -300 231 -296 231 -262 295 -268 271 -270 231 -264 261 -262 255 -292 265 -266 265 -236 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 267 -268 265 -268 273 -268 231 -296 229 -264 261 -294 263 -234 299 -266 267 -268 231 -264 261 -262 257 -258 291 -262 235 -300 231 -296 263 -268 271 -270 231 -296 229 -264 255 -290 231 -266 261 -324 239 -276 237 -268 257 -290 231 -266 -RAW_Data: 259 -292 231 -300 263 -236 299 -266 235 -300 231 -296 229 -262 261 -296 229 -296 229 -296 261 -236 299 -264 235 -300 233 -262 257 -290 231 -298 231 -266 257 -290 231 -300 263 -236 301 -266 233 -300 231 -264 257 -288 231 -300 231 -298 263 -268 271 -270 231 -296 229 -264 261 -262 255 -292 231 -300 231 -296 229 -296 263 -234 299 -266 233 -300 231 -296 229 -296 229 -262 257 -292 231 -298 231 -298 263 -268 271 -270 231 -264 261 -264 255 -290 265 -272 267 -268 235 -300 231 -264 255 -258 289 -264 267 -236 259 -292 231 -298 265 -236 299 -266 235 -300 231 -262 257 -256 293 -262 267 -268 265 -270 271 -268 231 -264 257 -290 231 -298 231 -298 263 -234 299 -266 233 -302 231 -296 229 -262 257 -290 231 -298 233 -296 263 -236 299 -264 235 -300 231 -264 261 -264 293 -234 299 -266 235 -300 231 -264 257 -290 231 -298 231 -298 229 -264 293 -234 301 -266 233 -300 231 -264 261 -294 229 -264 257 -290 265 -272 275 -270 233 -262 261 -262 257 -290 231 -300 265 -236 299 -234 261 -296 265 -268 231 -264 257 -258 257 -262 293 -264 269 -274 267 -268 233 -300 231 -262 257 -290 231 -266 261 -260 259 -294 267 -274 267 -266 235 -300 231 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 261 -262 257 -290 231 -300 231 -296 263 -234 301 -264 235 -300 231 -296 229 -264 255 -258 291 -262 269 -266 233 -264 293 -234 299 -266 235 -300 231 -296 229 -262 257 -258 291 -230 293 -264 267 -268 271 -274 235 -266 261 -262 255 -258 291 -264 267 -268 265 -234 301 -264 233 -300 231 -296 231 -262 257 -258 291 -262 267 -268 265 -236 299 -264 235 -300 231 -264 261 -294 263 -234 299 -266 235 -300 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 263 -270 273 -268 231 -264 261 -294 229 -264 257 -258 291 -304 241 -274 235 -266 261 -262 259 -296 229 -262 257 -292 231 -300 263 -236 301 -266 233 -300 231 -262 261 -296 229 -262 257 -292 265 -272 269 -266 235 -300 229 -264 261 -264 261 -260 257 -258 293 -262 269 -268 265 -234 299 -266 233 -268 259 -292 229 -300 231 -296 229 -296 263 -234 299 -266 235 -300 231 -262 263 -294 229 -296 229 -264 255 -290 233 -298 265 -268 267 -266 235 -300 231 -296 229 -262 257 -290 231 -298 233 -296 231 -262 293 -268 273 -270 231 -264 261 -262 261 -294 263 -268 267 -266 235 -300 231 -262 261 -296 229 -262 257 -292 231 -298 231 -298 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 -RAW_Data: 231 -296 269 -272 235 -268 257 -258 289 -262 269 -268 231 -264 293 -234 299 -266 235 -300 231 -296 229 -264 259 -296 229 -296 229 -262 295 -236 299 -264 267 -268 231 -264 261 -294 263 -234 299 -266 269 -268 231 -262 261 -294 229 -264 257 -258 289 -264 267 -274 269 -266 235 -300 231 -262 261 -262 257 -258 291 -298 239 -276 237 -302 229 -264 255 -290 231 -266 259 -292 233 -298 265 -236 299 -264 235 -300 231 -264 257 -256 293 -228 295 -264 235 -300 263 -270 273 -268 231 -264 261 -262 257 -258 291 -262 267 -268 231 -264 295 -234 299 -264 269 -268 231 -264 261 -294 229 -296 263 -268 271 -270 231 -264 261 -262 257 -258 291 -264 267 -268 265 -234 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 265 -234 301 -232 263 -294 233 -300 231 -264 257 -258 291 -230 293 -264 269 -272 275 -270 231 -264 261 -294 229 -262 257 -292 231 -298 231 -296 263 -236 299 -266 233 -300 231 -264 257 -258 291 -264 233 -300 265 -234 299 -232 295 -264 235 -300 229 -296 231 -262 293 -234 301 -266 235 -300 229 -296 231 -262 257 -290 231 -300 231 -296 263 -234 299 -266 235 -300 231 -264 261 -262 289 -266 267 -270 271 -268 231 -264 255 -290 231 -266 259 -292 231 -300 263 -236 301 -266 235 -300 229 -264 261 -264 259 -262 257 -292 265 -272 267 -268 235 -300 231 -262 257 -290 231 -300 265 -236 299 -266 235 -300 231 -294 231 -262 257 -290 231 -266 259 -294 265 -272 267 -266 235 -300 231 -294 231 -262 261 -264 261 -294 229 -296 263 -234 299 -266 267 -268 231 -264 261 -262 257 -290 231 -300 265 -268 273 -270 231 -264 261 -262 255 -258 293 -262 269 -266 233 -262 295 -234 299 -266 235 -300 231 -294 229 -296 229 -264 255 -258 293 -262 267 -266 265 -236 299 -266 233 -302 231 -294 229 -296 229 -262 257 -292 231 -298 265 -270 271 -236 261 -292 231 -298 231 -296 229 -264 295 -234 299 -266 233 -302 231 -262 263 -262 261 -264 255 -292 231 -298 265 -270 267 -266 233 -300 231 -294 231 -294 263 -234 299 -266 235 -300 231 -296 229 -264 259 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -298 229 -262 257 -258 291 -296 241 -276 237 -268 259 -256 259 -294 267 -266 233 -296 263 -268 271 -268 231 -264 263 -262 255 -292 231 -266 259 -292 265 -272 269 -266 235 -300 231 -262 257 -290 265 -272 267 -234 297 -262 267 -266 231 -264 261 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -300 -RAW_Data: 231 -264 257 -290 231 -300 231 -264 257 -290 265 -272 267 -268 235 -302 231 -262 261 -294 229 -264 255 -292 231 -298 233 -296 269 -272 235 -266 263 -262 255 -258 291 -264 267 -274 267 -234 295 -262 267 -266 231 -264 263 -262 261 -262 257 -258 291 -264 267 -268 265 -234 299 -266 233 -300 231 -264 263 -262 261 -294 229 -296 229 -264 295 -234 299 -266 235 -300 231 -262 257 -292 231 -298 265 -268 273 -270 231 -264 261 -262 255 -292 265 -266 231 -264 263 -262 295 -268 271 -270 231 -264 261 -262 257 -258 291 -262 269 -272 269 -266 235 -300 231 -262 261 -262 257 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -268 231 -262 261 -264 257 -288 265 -268 231 -296 269 -272 235 -266 257 -258 259 -294 267 -266 233 -296 263 -234 299 -266 233 -300 231 -296 229 -264 255 -290 233 -298 265 -270 265 -266 235 -300 231 -296 229 -262 261 -294 231 -262 257 -290 265 -268 265 -236 299 -264 235 -300 231 -294 231 -262 261 -264 293 -268 273 -268 233 -264 261 -262 257 -290 231 -266 259 -294 231 -298 231 -298 261 -270 271 -268 233 -264 261 -262 255 -258 293 -262 269 -234 259 -292 231 -298 265 -270 271 -270 231 -264 261 -260 257 -292 265 -264 233 -296 269 -272 235 -266 263 -264 259 -296 229 -294 229 -264 261 -294 263 -268 273 -270 231 -264 261 -262 255 -260 291 -262 269 -266 265 -236 299 -264 269 -232 259 -292 231 -300 231 -264 295 -234 299 -266 235 -300 231 -262 263 -260 257 -258 293 -230 293 -264 267 -274 267 -268 235 -300 229 -264 255 -258 291 -264 267 -274 273 -270 233 -262 257 -290 263 -266 231 -296 231 -262 295 -236 299 -264 269 -268 231 -262 261 -262 257 -258 293 -262 267 -268 263 -270 271 -268 233 -264 255 -290 265 -266 265 -234 301 -266 235 -300 231 -262 261 -264 261 -262 263 -262 257 -290 265 -272 269 -266 235 -300 231 -262 261 -264 261 -264 255 -290 265 -266 265 -270 273 -268 233 -262 257 -258 289 -264 267 -234 261 -292 263 -272 275 -270 233 -262 261 -262 257 -290 265 -232 259 -292 233 -298 265 -236 301 -264 235 -300 231 -262 261 -262 257 -258 293 -262 269 -266 233 -262 295 -234 299 -264 269 -268 231 -262 261 -262 257 -258 293 -262 269 -266 265 -236 299 -264 267 -234 259 -292 231 -298 231 -298 263 -234 299 -266 267 -266 231 -264 263 -262 261 -294 229 -296 231 -262 293 -268 267 -266 235 -300 231 -262 263 -262 289 -264 269 -270 271 -268 231 -262 261 -262 257 -290 265 -266 233 -264 -RAW_Data: 261 -262 295 -234 301 -264 269 -266 231 -262 261 -296 229 -296 229 -262 297 -268 271 -268 233 -262 257 -290 265 -266 231 -296 263 -270 271 -268 233 -262 261 -262 257 -290 265 -234 261 -292 265 -270 267 -268 235 -300 231 -262 257 -290 265 -272 269 -266 235 -300 231 -262 261 -262 257 -292 265 -264 233 -264 257 -290 265 -266 263 -270 273 -268 233 -262 257 -290 231 -268 259 -292 231 -300 263 -270 273 -268 231 -264 261 -294 229 -296 229 -264 257 -258 291 -262 269 -266 265 -270 271 -268 231 -264 261 -294 229 -296 263 -234 299 -266 269 -266 231 -262 257 -258 291 -230 295 -264 233 -300 265 -234 301 -264 235 -300 231 -296 229 -264 259 -296 229 -262 257 -292 231 -300 231 -296 263 -268 271 -270 231 -264 257 -256 291 -262 269 -274 267 -268 233 -300 231 -264 261 -294 229 -296 229 -264 255 -290 233 -298 265 -236 299 -266 235 -300 231 -262 263 -262 257 -256 293 -296 241 -276 237 -300 231 -262 255 -290 265 -264 233 -296 263 -236 299 -232 295 -262 267 -266 233 -264 261 -294 229 -262 257 -292 231 -298 265 -270 273 -268 231 -264 257 -290 263 -266 265 -270 273 -268 233 -262 261 -262 257 -290 231 -266 261 -292 265 -272 269 -266 235 -300 229 -264 255 -292 265 -266 231 -296 269 -272 235 -300 229 -264 255 -256 291 -264 267 -268 265 -234 301 -264 267 -268 231 -264 261 -262 255 -258 293 -262 269 -272 269 -266 233 -300 231 -296 229 -264 261 -262 261 -262 257 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 261 -296 229 -296 263 -234 299 -266 233 -300 231 -264 263 -262 257 -290 231 -298 233 -296 231 -262 293 -236 299 -266 235 -300 229 -296 231 -262 261 -264 255 -290 231 -300 231 -296 263 -236 299 -264 235 -302 229 -296 229 -296 229 -264 287 -266 267 -270 271 -268 231 -262 257 -290 231 -266 259 -292 233 -298 265 -236 299 -266 235 -300 229 -264 257 -290 231 -298 231 -298 263 -234 299 -232 295 -232 293 -264 233 -300 231 -296 263 -234 299 -266 235 -300 231 -262 263 -262 261 -262 257 -258 293 -262 267 -274 269 -266 233 -300 231 -262 257 -292 265 -270 269 -266 235 -300 231 -296 229 -262 261 -262 257 -292 231 -300 263 -270 267 -266 235 -300 229 -264 257 -258 289 -230 295 -264 267 -268 265 -268 271 -236 261 -290 231 -300 231 -296 229 -262 295 -268 271 -270 233 -264 261 -262 261 -294 229 -296 229 -296 229 -264 293 -268 273 -268 233 -264 261 -262 255 -258 293 -262 269 -266 233 -262 295 -268 -RAW_Data: 271 -270 231 -264 261 -262 255 -260 291 -262 269 -272 275 -270 231 -264 261 -262 255 -258 291 -264 269 -266 233 -262 295 -234 299 -264 235 -300 231 -264 263 -262 257 -290 231 -266 259 -294 231 -298 265 -236 299 -266 233 -302 231 -264 261 -262 255 -258 293 -262 267 -268 265 -270 271 -234 261 -292 231 -266 259 -292 231 -300 263 -236 299 -266 233 -302 229 -264 261 -296 229 -296 229 -262 261 -296 261 -270 267 -266 233 -300 231 -296 229 -262 295 -268 265 -266 235 -300 231 -296 229 -264 259 -296 229 -262 257 -292 231 -298 265 -270 265 -266 235 -300 231 -294 229 -296 231 -262 261 -294 269 -272 237 -266 257 -290 231 -264 261 -292 231 -300 265 -234 301 -264 235 -300 231 -296 229 -264 255 -290 265 -266 233 -264 261 -294 263 -234 301 -266 233 -300 231 -296 229 -294 229 -296 229 -264 255 -290 233 -298 231 -298 263 -234 299 -232 295 -230 295 -262 267 -268 265 -234 299 -266 235 -300 231 -262 263 -294 229 -296 229 -262 257 -290 231 -300 265 -236 299 -266 235 -300 231 -296 229 -262 261 -294 229 -296 231 -294 229 -264 295 -234 299 -266 233 -300 231 -298 229 -262 257 -290 265 -270 269 -266 235 -302 229 -264 261 -264 257 -288 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 229 -296 229 -264 255 -290 265 -272 275 -236 263 -290 231 -298 231 -296 229 -296 263 -234 299 -266 233 -302 229 -298 229 -262 257 -258 291 -230 295 -262 269 -272 269 -266 233 -300 231 -296 229 -296 229 -262 295 -268 271 -270 231 -266 261 -260 257 -258 291 -230 295 -264 233 -300 265 -268 273 -268 231 -264 257 -258 291 -262 267 -268 231 -296 269 -238 265 -294 231 -298 231 -264 257 -292 229 -300 265 -236 301 -264 235 -300 229 -296 229 -296 229 -296 229 -262 261 -294 263 -270 271 -270 231 -264 261 -262 257 -290 231 -300 231 -298 229 -262 295 -234 299 -266 267 -268 231 -264 261 -294 229 -296 263 -268 271 -268 233 -296 229 -264 255 -290 231 -266 261 -258 261 -294 267 -268 265 -234 299 -266 233 -300 231 -264 261 -262 257 -292 231 -298 233 -296 231 -262 293 -268 273 -268 233 -264 261 -262 255 -292 231 -298 233 -296 269 -272 235 -300 229 -264 255 -256 291 -264 267 -268 231 -264 295 -234 297 -266 269 -268 231 -264 259 -294 229 -296 231 -294 263 -236 299 -264 235 -300 231 -264 261 -294 263 -234 301 -232 263 -294 267 -266 233 -296 229 -264 255 -290 231 -266 259 -292 267 -270 269 -266 235 -300 231 -264 261 -294 229 -296 -RAW_Data: 263 -268 273 -268 231 -264 261 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -264 257 -256 291 -264 267 -268 265 -236 299 -264 233 -300 231 -264 257 -292 231 -298 265 -236 299 -266 233 -302 231 -264 261 -294 229 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -258 259 -294 267 -234 261 -292 231 -298 265 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -264 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 263 -268 271 -270 231 -264 261 -262 255 -292 231 -300 231 -264 257 -290 265 -272 267 -268 235 -300 231 -296 229 -262 257 -258 291 -296 241 -276 237 -302 229 -262 261 -262 255 -292 231 -298 265 -270 267 -232 263 -294 233 -300 231 -264 257 -258 291 -228 295 -264 267 -268 265 -270 271 -268 231 -264 261 -294 231 -294 263 -268 271 -270 233 -264 261 -262 255 -258 291 -264 267 -268 231 -264 293 -268 271 -270 233 -264 257 -290 229 -300 231 -296 269 -272 235 -300 229 -264 259 -262 257 -290 233 -298 231 -298 263 -234 299 -266 233 -300 231 -264 261 -294 231 -294 231 -294 231 -294 263 -268 271 -270 231 -296 229 -264 261 -294 229 -264 257 -290 231 -300 263 -236 301 -266 233 -300 231 -296 229 -262 261 -296 261 -270 265 -266 235 -300 231 -294 231 -262 257 -258 291 -262 235 -300 233 -262 295 -234 299 -266 235 -300 231 -262 263 -262 255 -292 231 -266 259 -294 231 -300 263 -270 273 -268 231 -264 261 -294 229 -296 229 -296 263 -268 271 -268 233 -262 263 -262 255 -292 231 -300 231 -296 231 -262 295 -234 299 -266 235 -300 231 -294 229 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -264 257 -256 293 -262 269 -272 267 -268 233 -300 231 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -260 259 -294 267 -268 265 -268 271 -270 231 -264 261 -296 229 -294 229 -264 257 -288 265 -272 269 -268 235 -300 229 -264 257 -258 291 -262 267 -234 261 -292 231 -298 265 -270 271 -270 231 -262 257 -290 231 -266 259 -292 233 -298 265 -270 265 -266 235 -300 231 -296 229 -262 261 -294 231 -296 229 -294 231 -294 263 -234 299 -266 233 -302 231 -264 261 -260 257 -292 231 -300 231 -296 263 -236 297 -266 235 -266 259 -260 259 -294 267 -268 265 -234 299 -266 233 -300 231 -298 229 -262 261 -262 257 -290 233 -298 265 -236 -RAW_Data: 301 -266 233 -300 231 -262 257 -258 259 -294 267 -274 275 -270 233 -262 261 -262 257 -290 231 -300 231 -296 231 -262 295 -268 265 -266 235 -300 231 -264 257 -258 257 -294 267 -268 231 -266 293 -268 273 -268 233 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -264 257 -290 231 -266 259 -292 231 -300 265 -268 273 -270 231 -264 261 -262 257 -258 291 -302 243 -274 235 -266 261 -262 255 -290 231 -300 231 -264 257 -290 231 -300 265 -268 273 -270 231 -264 261 -294 229 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -230 293 -264 267 -268 265 -234 299 -232 295 -264 233 -300 231 -298 261 -236 297 -266 235 -300 231 -264 261 -262 257 -290 231 -266 261 -292 231 -300 263 -270 267 -232 263 -294 233 -300 231 -296 229 -264 255 -292 231 -300 231 -296 263 -234 299 -266 235 -300 231 -262 257 -292 229 -300 265 -270 271 -270 231 -264 261 -294 229 -296 229 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -296 269 -272 235 -268 257 -290 231 -298 231 -296 263 -234 299 -232 297 -262 235 -300 231 -262 257 -258 259 -296 267 -266 265 -236 299 -266 233 -300 231 -296 231 -262 261 -294 263 -234 301 -266 233 -300 231 -296 229 -294 231 -262 257 -258 291 -262 267 -268 265 -268 273 -268 231 -296 229 -264 255 -258 291 -264 233 -302 265 -268 271 -270 231 -264 259 -262 257 -292 231 -266 259 -294 231 -298 265 -236 299 -266 233 -300 231 -296 231 -262 257 -256 293 -262 267 -268 265 -236 299 -264 233 -300 231 -298 229 -262 257 -290 231 -266 261 -292 231 -300 263 -236 301 -264 235 -300 231 -296 229 -262 257 -258 291 -262 235 -300 231 -296 263 -268 271 -236 261 -258 259 -294 267 -268 231 -264 295 -234 297 -266 269 -268 231 -264 255 -290 231 -266 261 -292 265 -270 269 -266 235 -300 231 -262 257 -292 265 -270 269 -266 235 -300 231 -296 229 -264 261 -294 229 -264 257 -290 231 -298 231 -298 263 -268 273 -268 231 -264 255 -290 231 -268 261 -292 231 -298 271 -274 235 -266 259 -256 257 -294 267 -268 265 -236 299 -266 233 -300 231 -296 229 -264 255 -290 231 -300 231 -298 263 -268 271 -270 231 -264 261 -262 257 -290 265 -272 273 -272 231 -264 261 -294 229 -296 229 -264 255 -290 231 -300 231 -298 263 -268 271 -268 233 -264 261 -262 257 -290 231 -300 231 -296 263 -234 301 -264 235 -300 231 -296 229 -262 257 -258 291 -262 269 -266 233 -262 -RAW_Data: 295 -268 271 -270 233 -264 261 -262 259 -294 231 -294 263 -236 299 -264 235 -302 229 -298 229 -262 261 -294 231 -262 257 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 261 -294 229 -296 229 -296 263 -234 299 -266 233 -302 229 -298 229 -262 261 -294 263 -268 267 -266 235 -300 229 -296 229 -264 257 -290 231 -266 259 -292 265 -272 269 -266 235 -300 231 -264 257 -288 231 -300 231 -296 271 -270 235 -268 257 -290 231 -298 231 -264 257 -292 231 -298 265 -270 267 -266 233 -300 231 -262 257 -292 229 -300 231 -298 229 -262 295 -268 271 -270 233 -264 257 -288 231 -298 231 -298 263 -268 273 -268 231 -264 261 -262 257 -258 291 -262 267 -268 231 -298 263 -268 271 -268 231 -264 263 -294 229 -262 257 -258 259 -294 267 -268 265 -270 271 -270 231 -264 259 -262 257 -258 293 -262 235 -300 263 -236 299 -266 235 -300 231 -262 257 -258 259 -294 267 -234 261 -292 231 -300 263 -236 299 -266 233 -300 231 -298 229 -262 257 -290 231 -298 233 -296 231 -262 293 -268 267 -266 235 -300 231 -262 263 -294 229 -296 229 -264 293 -268 271 -270 233 -264 255 -290 231 -298 233 -296 231 -294 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 293 -262 267 -274 267 -268 233 -302 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 231 -296 231 -294 263 -268 271 -270 231 -296 229 -264 255 -258 291 -296 241 -276 239 -300 231 -262 255 -288 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -296 229 -296 229 -262 261 -294 263 -270 271 -270 231 -264 261 -294 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -300 231 -298 229 -262 295 -266 273 -268 233 -264 261 -262 261 -294 231 -294 231 -296 261 -236 299 -232 293 -264 233 -302 229 -264 257 -290 231 -266 261 -258 293 -302 243 -274 235 -264 261 -262 261 -262 257 -290 231 -300 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 259 -294 267 -268 231 -296 263 -234 299 -232 295 -264 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -270 271 -270 231 -264 257 -290 229 -300 265 -270 265 -266 235 -300 231 -294 231 -294 229 -296 229 -296 229 -294 263 -236 299 -264 233 -300 231 -298 229 -294 231 -294 263 -268 271 -270 231 -296 229 -264 261 -262 255 -292 231 -300 231 -296 263 -236 297 -266 235 -300 233 -262 261 -294 229 -296 231 -262 261 -294 263 -268 273 -268 233 -262 257 -290 231 -298 -RAW_Data: 233 -296 263 -236 299 -264 235 -300 231 -264 261 -294 229 -264 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -296 229 -262 257 -290 231 -300 265 -236 299 -266 235 -298 231 -296 229 -264 255 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -296 229 -264 255 -290 233 -298 265 -270 267 -266 233 -300 231 -296 229 -262 261 -294 231 -262 257 -292 231 -298 265 -270 267 -264 235 -300 231 -262 261 -294 231 -294 231 -296 269 -272 235 -298 231 -262 261 -294 229 -296 229 -294 229 -296 263 -234 299 -266 233 -300 231 -264 257 -258 259 -294 267 -268 231 -296 263 -270 271 -268 231 -264 257 -290 231 -298 265 -236 301 -266 233 -300 231 -296 229 -294 231 -294 229 -296 229 -262 261 -296 261 -270 273 -268 231 -264 261 -262 257 -258 291 -304 243 -274 235 -264 261 -262 261 -294 229 -264 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -264 255 -290 231 -300 265 -270 273 -268 231 -264 257 -290 229 -300 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 231 -262 293 -268 273 -268 233 -264 261 -294 229 -296 229 -264 255 -290 231 -300 265 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -268 271 -272 237 -302 231 -262 261 -262 255 -258 291 -264 267 -268 231 -264 295 -234 299 -266 235 -300 231 -262 257 -290 231 -300 231 -264 257 -292 229 -300 265 -270 265 -266 235 -300 231 -294 229 -264 257 -258 291 -262 269 -272 267 -266 235 -268 259 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -294 231 -294 229 -264 261 -294 229 -296 229 -296 263 -268 271 -270 231 -264 261 -294 263 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -264 257 -290 231 -300 265 -268 273 -270 231 -264 263 -260 261 -262 257 -292 231 -298 273 -272 237 -266 259 -256 257 -294 267 -268 231 -298 263 -234 299 -264 235 -300 233 -262 261 -262 257 -258 291 -264 233 -302 265 -234 299 -266 233 -300 231 -296 231 -262 261 -262 257 -290 231 -300 265 -268 267 -266 235 -300 229 -296 229 -296 229 -264 261 -294 229 -296 263 -234 299 -266 233 -302 229 -298 229 -262 261 -262 257 -258 291 -264 267 -274 267 -234 263 -294 233 -300 231 -296 229 -264 257 -290 231 -300 231 -296 263 -236 299 -264 233 -300 231 -298 229 -294 231 -262 257 -290 263 -272 277 -270 233 -262 261 -262 261 -262 257 -290 233 -298 231 -298 263 -268 271 -270 231 -264 255 -290 231 -300 231 -298 229 -264 -RAW_Data: 293 -234 301 -232 263 -294 267 -268 231 -264 293 -234 299 -266 269 -266 233 -262 261 -294 229 -296 229 -264 255 -292 231 -298 265 -270 271 -270 233 -264 261 -262 255 -290 265 -272 275 -270 233 -264 261 -294 227 -264 257 -258 259 -296 267 -266 265 -236 299 -266 233 -300 231 -264 257 -258 259 -292 269 -268 265 -270 271 -236 259 -260 257 -294 267 -266 233 -264 295 -234 299 -264 235 -302 231 -264 261 -294 229 -296 229 -262 261 -294 263 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -234 301 -264 235 -300 231 -296 229 -264 255 -290 265 -272 269 -266 235 -300 231 -262 257 -258 259 -296 267 -234 259 -292 231 -298 265 -236 301 -266 233 -300 231 -262 261 -296 229 -262 257 -292 231 -298 233 -296 263 -234 299 -266 233 -302 231 -262 257 -258 291 -262 235 -300 231 -296 269 -272 235 -300 231 -262 259 -262 257 -292 231 -298 265 -236 299 -266 233 -302 231 -264 261 -294 229 -296 229 -264 261 -294 261 -270 271 -270 233 -264 261 -262 259 -294 263 -270 267 -266 233 -300 231 -296 229 -264 259 -262 257 -292 231 -298 233 -296 263 -236 299 -264 233 -302 231 -264 257 -290 231 -298 265 -236 299 -266 233 -300 231 -264 257 -258 291 -262 269 -234 259 -292 231 -300 263 -236 299 -266 233 -300 231 -298 229 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -264 255 -258 291 -262 269 -266 233 -264 293 -234 299 -266 267 -268 231 -264 257 -290 231 -298 265 -236 299 -266 235 -300 231 -296 229 -262 257 -258 291 -262 269 -266 233 -262 295 -234 299 -266 235 -300 231 -294 229 -296 231 -262 257 -256 291 -264 267 -274 267 -266 235 -300 231 -264 261 -294 229 -296 263 -236 299 -264 233 -302 231 -264 255 -258 291 -262 267 -234 261 -292 231 -298 265 -270 271 -270 231 -264 261 -262 255 -260 291 -262 269 -266 273 -272 237 -264 263 -262 255 -258 291 -262 235 -300 263 -236 301 -266 233 -300 231 -296 229 -262 257 -258 291 -262 269 -266 265 -236 299 -266 233 -300 231 -296 229 -296 261 -236 299 -266 233 -300 231 -262 259 -258 291 -262 235 -300 231 -296 263 -268 271 -270 231 -264 261 -262 255 -292 231 -298 233 -296 269 -272 235 -300 229 -264 259 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -296 263 -236 299 -264 235 -300 231 -264 257 -290 231 -298 231 -264 259 -290 231 -298 265 -270 267 -266 233 -300 231 -262 257 -290 265 -272 269 -266 -RAW_Data: 235 -300 231 -296 229 -262 261 -262 257 -258 293 -262 267 -268 231 -264 295 -268 271 -270 231 -264 261 -262 257 -290 231 -300 231 -264 257 -292 263 -272 269 -266 235 -300 231 -262 257 -290 231 -300 231 -298 263 -268 271 -268 233 -296 229 -262 257 -290 231 -298 231 -298 263 -234 299 -266 235 -300 231 -296 229 -262 261 -296 229 -296 229 -262 295 -268 271 -270 233 -264 255 -290 231 -300 263 -236 301 -266 233 -300 231 -296 229 -264 255 -290 231 -300 231 -264 259 -290 231 -298 265 -270 271 -270 231 -264 261 -294 229 -296 229 -264 293 -268 273 -268 233 -264 261 -294 229 -264 257 -258 289 -262 269 -268 265 -234 301 -264 233 -300 231 -296 231 -262 257 -256 291 -264 267 -274 267 -268 235 -300 229 -296 229 -262 257 -290 233 -266 259 -260 259 -294 267 -274 275 -270 231 -264 255 -290 231 -298 265 -270 267 -266 235 -300 229 -296 229 -264 255 -258 291 -230 295 -264 233 -300 265 -236 299 -266 233 -300 231 -296 229 -296 229 -262 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 233 -262 261 -294 229 -296 263 -234 299 -266 235 -300 231 -264 261 -294 229 -264 257 -258 291 -262 235 -300 265 -268 273 -268 233 -262 261 -262 257 -258 291 -296 239 -278 237 -270 261 -262 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 233 -300 231 -298 229 -262 257 -258 291 -262 269 -268 265 -234 299 -266 233 -300 231 -296 229 -264 293 -234 301 -266 233 -300 231 -264 257 -258 259 -292 269 -234 261 -292 263 -272 275 -270 233 -262 261 -294 229 -296 229 -264 287 -300 241 -272 235 -264 261 -262 257 -290 231 -266 259 -294 231 -300 263 -236 299 -266 233 -300 231 -296 229 -296 229 -264 255 -290 265 -274 267 -268 233 -300 231 -296 229 -264 261 -262 255 -260 291 -262 235 -300 265 -236 299 -264 235 -266 259 -292 231 -300 265 -234 301 -266 233 -300 231 -296 229 -264 255 -258 291 -264 233 -268 261 -290 231 -300 263 -236 301 -266 233 -300 231 -294 229 -296 229 -264 255 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 261 -294 263 -268 267 -266 235 -300 229 -264 257 -292 229 -266 261 -260 259 -294 267 -268 265 -268 271 -270 231 -296 229 -264 261 -262 255 -292 231 -300 263 -270 273 -236 261 -258 259 -294 267 -266 265 -236 299 -232 295 -262 267 -268 231 -264 261 -262 257 -258 291 -264 233 -302 265 -234 299 -266 233 -300 231 -296 229 -264 261 -294 263 -234 301 -232 263 -294 267 -266 233 -264 261 -294 -RAW_Data: 229 -262 257 -292 231 -300 263 -236 301 -266 233 -300 231 -264 257 -256 291 -262 267 -268 233 -264 293 -234 299 -266 235 -300 231 -296 229 -262 257 -258 291 -264 267 -272 275 -270 233 -262 261 -294 229 -264 255 -292 231 -300 231 -296 263 -268 271 -270 231 -264 257 -258 257 -294 267 -236 259 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 265 -268 273 -236 259 -292 231 -266 259 -292 265 -272 267 -266 235 -300 231 -296 229 -262 257 -258 259 -294 267 -268 231 -298 261 -270 271 -268 231 -264 261 -262 257 -290 265 -272 275 -272 231 -264 261 -262 255 -290 231 -300 231 -264 257 -292 231 -298 265 -270 273 -268 233 -262 261 -262 257 -290 233 -266 259 -292 265 -272 275 -270 231 -264 261 -262 257 -290 265 -272 267 -268 235 -300 231 -294 229 -296 229 -264 255 -292 231 -298 265 -270 265 -266 235 -300 231 -264 259 -262 289 -266 269 -270 237 -300 231 -264 261 -294 229 -296 229 -264 255 -290 233 -298 265 -270 265 -266 235 -300 231 -294 231 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -264 261 -262 257 -258 291 -230 295 -264 233 -300 265 -234 301 -230 297 -262 235 -300 231 -264 261 -294 263 -234 301 -266 233 -300 231 -296 229 -294 231 -262 257 -290 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 231 -262 295 -268 271 -270 231 -264 263 -260 261 -294 263 -270 265 -266 235 -300 231 -296 229 -262 257 -258 291 -262 269 -266 233 -262 295 -268 271 -270 231 -264 263 -260 257 -290 231 -300 231 -298 269 -238 263 -262 261 -294 233 -298 231 -296 231 -294 263 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -264 233 -302 263 -236 299 -264 235 -300 231 -296 229 -296 263 -234 299 -266 233 -300 231 -264 257 -290 231 -266 259 -294 231 -298 265 -236 299 -266 233 -300 231 -296 231 -262 257 -258 291 -294 241 -276 239 -268 263 -262 259 -296 229 -262 257 -290 233 -298 265 -270 265 -266 235 -300 231 -294 231 -294 229 -264 255 -290 231 -300 265 -270 267 -264 235 -300 231 -294 231 -294 229 -296 229 -294 229 -264 257 -290 231 -300 263 -270 267 -266 235 -300 231 -262 257 -258 259 -262 293 -262 269 -268 231 -264 293 -234 301 -266 233 -268 259 -292 229 -266 261 -292 231 -300 263 -236 301 -264 233 -302 231 -264 261 -294 229 -264 257 -290 231 -298 265 -236 301 -266 233 -300 231 -296 229 -296 261 -236 299 -264 -RAW_Data: 235 -300 231 -296 229 -296 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 255 -258 291 -296 241 -276 237 -302 229 -264 255 -290 229 -300 231 -298 263 -268 271 -268 233 -296 229 -262 257 -290 231 -300 231 -296 263 -236 297 -266 235 -300 231 -262 257 -292 263 -272 267 -268 235 -300 231 -296 229 -296 229 -262 257 -290 231 -266 259 -292 265 -272 269 -266 235 -300 231 -264 257 -288 231 -300 231 -296 231 -296 261 -236 299 -264 235 -300 231 -262 257 -258 259 -296 267 -234 261 -292 263 -272 275 -236 261 -292 229 -300 231 -296 229 -264 293 -268 267 -266 233 -300 231 -296 229 -262 257 -290 231 -268 259 -292 231 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -294 229 -264 261 -294 229 -296 263 -268 271 -270 231 -264 261 -262 257 -292 231 -298 265 -270 271 -270 231 -264 261 -262 257 -290 231 -266 261 -292 231 -298 265 -270 273 -268 233 -262 261 -294 231 -294 231 -294 269 -272 235 -300 229 -262 261 -262 257 -258 291 -262 235 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 261 -294 231 -296 261 -236 299 -264 235 -300 231 -264 257 -290 231 -300 265 -268 273 -268 233 -262 261 -262 257 -292 231 -266 259 -292 267 -270 269 -266 235 -300 231 -262 257 -258 291 -230 295 -304 243 -272 235 -266 261 -260 261 -262 257 -290 233 -298 231 -296 265 -234 299 -266 233 -302 231 -262 259 -256 259 -260 295 -262 269 -268 265 -268 273 -268 233 -262 257 -256 293 -262 235 -300 231 -296 263 -268 271 -268 233 -264 261 -262 255 -292 231 -298 233 -296 263 -236 299 -264 235 -300 231 -296 229 -262 257 -258 291 -262 269 -266 233 -262 295 -234 299 -264 269 -268 231 -264 261 -262 257 -290 231 -266 261 -292 231 -298 231 -298 263 -234 299 -264 235 -300 231 -264 257 -290 265 -272 267 -268 235 -300 231 -262 261 -294 231 -294 231 -262 257 -290 231 -300 265 -268 273 -270 231 -264 261 -262 257 -258 291 -230 293 -296 241 -276 239 -268 259 -288 231 -264 261 -292 231 -300 231 -296 263 -234 299 -264 269 -266 233 -262 261 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -262 257 -290 233 -298 265 -270 267 -266 233 -300 231 -296 229 -294 229 -296 229 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 261 -262 255 -260 291 -304 243 -274 235 -264 261 -262 259 -262 257 -258 293 -262 235 -300 -RAW_Data: 263 -236 301 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -298 229 -262 295 -268 265 -266 235 -300 231 -296 229 -264 259 -262 257 -292 231 -298 265 -270 273 -268 233 -262 257 -290 231 -298 231 -298 263 -234 299 -266 233 -302 231 -262 261 -262 257 -292 231 -298 233 -296 263 -268 273 -268 231 -264 263 -294 229 -296 261 -270 271 -268 231 -266 261 -294 229 -262 257 -292 231 -298 231 -298 229 -264 293 -234 301 -266 233 -300 231 -296 229 -294 231 -262 257 -290 265 -272 275 -270 231 -264 257 -290 229 -300 265 -270 265 -266 235 -300 231 -294 231 -294 229 -264 255 -258 293 -262 267 -272 269 -266 235 -300 231 -262 257 -258 291 -270 271 -270 237 -300 233 -262 261 -262 255 -292 265 -232 261 -260 259 -294 267 -266 267 -268 271 -270 231 -264 257 -256 291 -264 233 -300 231 -296 263 -270 271 -268 231 -296 231 -262 255 -292 231 -266 259 -292 265 -272 267 -268 235 -268 257 -292 231 -298 231 -296 231 -294 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 263 -236 299 -266 235 -300 231 -296 229 -262 261 -296 229 -262 257 -292 231 -300 263 -270 273 -268 231 -264 261 -294 231 -294 263 -236 299 -264 235 -300 231 -296 229 -264 261 -260 257 -258 291 -264 267 -268 265 -268 273 -268 231 -264 261 -262 257 -290 231 -300 231 -298 269 -272 235 -266 257 -258 257 -294 267 -268 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -236 299 -266 233 -300 231 -264 257 -290 265 -272 267 -268 233 -302 231 -262 261 -296 229 -294 231 -262 257 -290 265 -272 267 -268 235 -300 231 -294 231 -262 257 -290 231 -300 271 -272 237 -266 257 -258 257 -294 267 -234 261 -292 231 -298 265 -236 301 -266 233 -300 231 -262 257 -258 291 -262 267 -268 231 -296 263 -268 273 -268 231 -296 231 -262 261 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 261 -270 271 -270 233 -264 261 -262 255 -258 291 -264 233 -268 259 -292 231 -300 263 -236 301 -266 233 -300 231 -296 229 -294 229 -264 255 -292 231 -298 233 -296 263 -268 271 -270 231 -264 263 -260 257 -290 231 -300 265 -270 271 -270 231 -264 257 -290 229 -266 261 -258 261 -294 267 -268 265 -234 299 -266 233 -300 231 -264 257 -258 259 -296 267 -266 265 -236 299 -232 295 -230 293 -264 233 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 -RAW_Data: 261 -236 299 -264 235 -300 231 -264 257 -258 289 -268 271 -272 237 -304 231 -262 261 -294 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -264 257 -258 259 -294 267 -268 231 -264 293 -268 273 -268 233 -264 261 -262 255 -292 231 -266 259 -292 233 -298 265 -270 267 -232 263 -260 293 -264 267 -268 265 -268 273 -268 231 -264 261 -294 229 -264 257 -290 231 -300 231 -296 231 -294 263 -234 299 -266 233 -302 231 -264 261 -294 229 -262 259 -258 259 -294 267 -268 265 -268 271 -268 233 -296 229 -262 257 -290 231 -300 231 -296 229 -296 263 -268 271 -270 231 -264 261 -262 257 -258 291 -262 267 -236 259 -292 265 -272 273 -270 233 -262 261 -294 231 -262 257 -290 265 -272 275 -270 233 -264 255 -290 231 -298 233 -264 257 -290 231 -298 265 -270 267 -266 233 -300 231 -264 261 -294 229 -264 257 -290 265 -272 267 -268 235 -266 259 -292 231 -298 231 -296 263 -270 271 -268 233 -264 261 -262 261 -260 259 -290 233 -298 265 -270 267 -264 235 -300 231 -262 261 -294 231 -294 263 -270 271 -268 233 -264 261 -294 229 -262 257 -258 293 -262 235 -300 231 -296 263 -268 271 -268 233 -262 257 -290 231 -300 231 -298 229 -262 295 -268 271 -270 231 -264 261 -262 257 -292 231 -298 231 -298 229 -296 263 -234 299 -232 293 -264 235 -268 259 -292 229 -300 263 -236 301 -266 233 -300 231 -296 229 -262 261 -262 257 -292 231 -300 231 -296 231 -294 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -298 233 -296 263 -270 271 -268 231 -264 261 -262 257 -290 231 -300 265 -236 299 -266 235 -300 231 -296 229 -262 261 -262 257 -258 291 -262 267 -268 265 -236 301 -264 233 -300 231 -298 229 -262 257 -258 291 -296 239 -278 237 -300 231 -260 257 -290 231 -266 261 -292 231 -298 265 -236 301 -264 235 -300 229 -264 257 -258 291 -230 293 -262 269 -268 265 -268 273 -268 231 -264 261 -294 229 -264 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 231 -296 229 -262 257 -258 291 -264 267 -268 263 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -264 267 -268 231 -264 293 -268 267 -266 233 -300 231 -296 229 -264 255 -290 231 -266 261 -292 231 -300 263 -270 273 -268 233 -262 261 -262 257 -292 265 -270 269 -266 235 -302 229 -296 229 -262 257 -290 231 -268 259 -260 259 -294 267 -274 267 -268 235 -300 229 -264 261 -262 255 -260 291 -296 241 -276 237 -302 229 -262 257 -256 291 -262 267 -268 265 -236 -RAW_Data: 299 -232 295 -262 235 -300 231 -296 229 -264 255 -258 291 -262 267 -268 265 -270 271 -268 231 -264 257 -290 231 -300 263 -270 273 -270 231 -264 261 -260 257 -290 265 -266 233 -298 263 -234 299 -264 235 -300 231 -264 255 -290 231 -300 231 -298 269 -272 235 -266 257 -290 231 -264 261 -292 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 261 -294 231 -296 229 -262 295 -268 271 -270 231 -264 263 -294 227 -296 231 -262 257 -290 231 -300 265 -236 299 -266 233 -300 231 -264 257 -290 231 -300 263 -270 267 -266 233 -300 231 -264 261 -262 257 -290 231 -300 231 -298 229 -262 295 -268 267 -264 235 -300 231 -294 231 -294 229 -296 229 -264 255 -290 233 -298 265 -270 273 -268 233 -262 261 -294 231 -294 229 -296 263 -268 271 -270 231 -264 261 -262 257 -290 231 -266 259 -294 231 -300 263 -236 299 -266 235 -300 231 -296 229 -262 257 -290 231 -300 231 -296 263 -270 271 -268 231 -264 257 -290 231 -298 231 -298 263 -234 299 -232 295 -264 267 -266 233 -264 255 -258 291 -262 269 -266 265 -236 299 -264 235 -300 231 -296 229 -264 259 -296 261 -270 265 -266 235 -300 231 -296 229 -262 261 -262 257 -258 291 -264 267 -268 265 -268 273 -268 231 -264 261 -294 229 -264 257 -258 291 -262 267 -268 231 -264 295 -268 271 -270 231 -264 261 -262 257 -258 291 -262 267 -234 261 -292 231 -298 265 -236 301 -266 233 -300 231 -262 261 -262 257 -292 231 -300 231 -296 263 -268 273 -268 231 -264 261 -294 229 -264 257 -258 259 -294 267 -268 231 -264 295 -268 271 -270 231 -264 257 -290 231 -266 259 -292 233 -298 271 -272 237 -266 257 -290 231 -266 259 -292 231 -300 265 -234 301 -264 235 -300 231 -296 229 -262 257 -258 291 -264 267 -272 269 -266 235 -300 231 -294 229 -296 229 -296 261 -270 271 -268 233 -264 261 -262 255 -292 231 -266 259 -294 231 -298 265 -270 271 -270 231 -264 255 -290 231 -266 261 -292 231 -300 271 -238 265 -294 233 -298 231 -262 259 -290 231 -298 265 -270 265 -266 235 -300 231 -264 261 -294 229 -296 229 -264 261 -294 263 -268 273 -268 233 -262 263 -260 257 -258 291 -264 267 -268 231 -264 293 -234 299 -266 269 -268 231 -264 259 -296 229 -294 263 -268 273 -268 231 -296 231 -262 261 -262 257 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -300 231 -296 229 -264 259 -262 257 -292 231 -298 233 -296 263 -236 299 -264 233 -302 229 -298 229 -262 257 -258 291 -296 239 -278 237 -300 -RAW_Data: 231 -262 257 -256 291 -230 293 -264 269 -266 265 -236 299 -264 235 -300 231 -296 229 -264 259 -262 257 -292 231 -298 265 -270 273 -268 233 -262 263 -294 227 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -264 267 -268 265 -234 299 -232 295 -264 233 -300 231 -296 229 -262 261 -296 261 -270 267 -266 233 -300 231 -264 257 -256 291 -262 267 -234 261 -292 233 -298 265 -268 273 -268 233 -262 261 -262 257 -290 233 -298 231 -296 263 -236 299 -266 233 -300 231 -264 261 -262 257 -258 291 -264 267 -268 231 -264 293 -268 273 -236 261 -292 229 -266 259 -292 233 -298 265 -234 301 -266 233 -300 231 -296 229 -262 257 -290 231 -266 261 -292 231 -300 265 -234 299 -266 235 -300 231 -264 261 -294 229 -296 229 -296 229 -264 293 -268 267 -266 233 -300 231 -296 231 -262 261 -294 263 -268 273 -268 233 -262 261 -262 257 -258 291 -264 233 -268 259 -292 265 -272 267 -268 233 -300 231 -296 229 -264 255 -290 231 -300 265 -270 265 -266 235 -300 231 -262 257 -290 233 -266 259 -292 231 -300 231 -296 263 -268 271 -270 231 -264 261 -294 229 -296 229 -296 229 -262 295 -268 267 -264 235 -300 231 -296 229 -264 261 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -260 257 -292 231 -298 265 -270 267 -266 235 -300 229 -296 229 -296 229 -262 257 -290 265 -266 233 -264 293 -234 299 -266 235 -302 231 -264 259 -294 229 -296 231 -262 257 -290 265 -272 269 -266 235 -300 229 -264 257 -290 231 -300 263 -270 267 -266 235 -300 229 -264 261 -294 229 -264 257 -290 231 -300 263 -270 267 -266 235 -300 229 -296 229 -296 229 -264 293 -268 273 -268 233 -262 261 -294 231 -262 257 -292 231 -298 231 -298 261 -236 299 -264 235 -302 231 -264 259 -296 229 -296 229 -262 261 -296 261 -270 271 -270 231 -264 255 -292 231 -298 265 -270 267 -264 235 -300 231 -262 257 -290 231 -266 261 -292 231 -300 263 -270 273 -268 233 -262 261 -262 257 -258 291 -304 243 -274 235 -264 261 -262 261 -262 257 -290 231 -266 261 -292 231 -300 263 -236 301 -266 233 -300 231 -296 229 -262 261 -262 257 -292 231 -298 265 -236 301 -266 233 -300 231 -264 261 -294 229 -264 257 -258 291 -262 267 -268 231 -264 295 -268 271 -270 231 -264 261 -262 261 -262 257 -260 291 -262 267 -268 265 -270 271 -268 233 -262 261 -294 231 -294 229 -264 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -266 -RAW_Data: 261 -292 231 -300 231 -296 269 -272 235 -268 257 -290 229 -266 259 -292 267 -272 267 -266 235 -300 231 -296 229 -262 257 -258 291 -264 233 -300 265 -268 273 -268 233 -262 261 -262 257 -290 265 -274 267 -268 233 -300 231 -296 229 -264 261 -294 229 -264 257 -290 231 -300 263 -270 273 -268 233 -264 259 -296 229 -262 257 -292 231 -298 265 -270 265 -234 261 -296 233 -298 233 -296 231 -262 261 -262 257 -258 291 -262 267 -268 271 -240 265 -260 259 -294 267 -266 233 -264 295 -232 299 -266 269 -268 231 -262 261 -262 257 -258 291 -264 267 -268 265 -268 271 -270 231 -264 261 -262 257 -290 231 -300 231 -298 229 -262 295 -234 299 -266 233 -302 231 -296 229 -262 257 -290 231 -300 263 -236 301 -266 235 -298 231 -296 229 -264 255 -258 291 -264 267 -268 231 -264 293 -268 271 -270 233 -264 261 -262 259 -264 257 -258 291 -270 271 -270 237 -302 231 -262 261 -294 229 -264 257 -290 231 -300 263 -270 267 -266 235 -300 229 -296 229 -262 257 -258 291 -264 233 -300 265 -270 271 -236 261 -258 259 -294 267 -266 233 -296 263 -234 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -236 299 -264 235 -302 231 -264 259 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 229 -264 257 -290 265 -272 267 -268 235 -300 229 -264 257 -258 291 -262 267 -234 261 -292 231 -298 265 -236 299 -264 235 -300 231 -296 229 -264 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -264 257 -258 259 -294 267 -268 231 -296 269 -272 235 -266 263 -262 259 -262 257 -292 231 -300 263 -270 267 -266 233 -300 231 -296 229 -264 261 -294 229 -296 229 -296 263 -234 299 -266 233 -268 259 -292 231 -298 231 -298 261 -270 271 -268 231 -298 229 -262 261 -294 229 -264 257 -292 229 -300 263 -270 267 -266 235 -300 229 -296 231 -262 261 -294 263 -268 273 -268 233 -264 261 -294 229 -296 229 -262 257 -290 233 -298 231 -296 263 -236 299 -264 235 -300 233 -262 261 -294 231 -262 257 -290 265 -272 267 -268 235 -300 231 -294 231 -294 229 -296 229 -296 229 -262 261 -294 263 -236 299 -266 235 -266 259 -260 257 -294 267 -268 265 -236 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 233 -300 265 -236 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -292 233 -298 265 -236 301 -264 235 -300 231 -262 261 -262 257 -290 231 -300 265 -236 301 -266 233 -300 231 -296 229 -262 261 -262 257 -292 -RAW_Data: 231 -300 263 -270 273 -268 233 -262 261 -294 231 -262 257 -290 231 -300 271 -240 265 -294 233 -266 257 -260 257 -294 269 -266 265 -236 299 -266 233 -302 231 -264 261 -260 257 -258 293 -262 267 -266 265 -236 299 -266 235 -300 229 -296 231 -294 263 -234 299 -266 235 -300 231 -262 259 -256 259 -294 267 -268 231 -298 261 -270 271 -268 233 -262 261 -262 257 -290 231 -300 231 -298 269 -272 235 -266 259 -290 229 -266 259 -292 231 -300 231 -296 263 -234 299 -266 235 -300 231 -296 229 -262 261 -296 229 -296 261 -236 299 -264 235 -300 231 -264 257 -290 231 -300 231 -264 257 -292 229 -300 265 -270 265 -266 235 -300 231 -262 257 -290 265 -272 269 -266 235 -300 229 -296 229 -296 229 -262 257 -292 231 -298 231 -298 229 -296 263 -268 271 -268 233 -262 263 -260 257 -290 231 -300 231 -264 259 -290 265 -272 267 -266 235 -302 229 -296 229 -296 229 -262 257 -258 293 -302 243 -272 235 -266 261 -262 255 -290 231 -300 231 -264 257 -292 231 -298 265 -270 273 -268 231 -264 261 -294 229 -264 257 -290 231 -300 263 -270 273 -236 261 -290 231 -266 259 -292 233 -298 265 -236 299 -266 233 -300 231 -296 229 -264 261 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -296 261 -236 299 -264 235 -302 231 -262 261 -262 257 -292 231 -266 259 -260 291 -262 267 -274 267 -268 233 -300 231 -296 229 -264 255 -258 291 -264 267 -274 267 -266 235 -300 231 -294 229 -296 229 -296 229 -262 257 -290 231 -300 265 -270 271 -236 261 -258 259 -260 295 -262 269 -268 265 -234 299 -266 233 -300 231 -296 229 -264 255 -292 231 -266 259 -260 259 -296 265 -268 265 -270 271 -270 231 -262 261 -262 257 -258 293 -262 235 -300 265 -236 299 -264 233 -302 231 -262 257 -290 231 -300 263 -270 267 -266 233 -302 229 -296 229 -296 229 -264 255 -258 291 -264 267 -268 263 -270 271 -268 233 -262 263 -262 255 -260 291 -294 241 -276 239 -268 263 -262 259 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 293 -262 267 -268 265 -236 299 -264 235 -266 261 -290 231 -300 263 -270 267 -266 233 -300 231 -264 255 -290 233 -298 231 -264 257 -292 265 -270 275 -270 233 -264 261 -294 229 -294 231 -262 289 -298 241 -274 233 -266 261 -262 255 -290 233 -266 259 -292 231 -300 265 -236 299 -264 235 -300 231 -296 229 -264 261 -262 257 -290 265 -272 267 -268 235 -300 231 -296 229 -262 261 -262 257 -258 291 -264 -RAW_Data: 233 -300 265 -236 301 -266 233 -266 259 -260 259 -292 267 -274 267 -268 235 -300 231 -294 231 -262 257 -290 231 -300 231 -264 257 -290 231 -300 263 -236 301 -266 233 -300 231 -264 261 -294 231 -262 257 -290 231 -298 265 -270 267 -266 235 -300 229 -296 231 -262 261 -294 263 -234 301 -266 233 -300 231 -264 257 -290 231 -266 259 -260 259 -294 267 -268 265 -270 271 -268 233 -262 263 -294 229 -262 257 -292 231 -298 265 -270 271 -236 261 -258 259 -294 267 -266 233 -296 263 -268 271 -268 233 -296 229 -262 261 -262 257 -258 293 -262 235 -300 263 -236 299 -266 233 -302 229 -298 229 -262 257 -290 265 -272 267 -268 235 -300 229 -296 231 -262 257 -256 293 -262 267 -234 261 -292 263 -272 267 -268 235 -300 229 -264 257 -258 291 -264 233 -300 231 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -300 263 -270 273 -268 233 -264 255 -258 259 -260 293 -264 269 -268 231 -296 263 -234 299 -264 235 -300 231 -296 229 -264 259 -262 257 -292 233 -298 265 -270 265 -266 235 -300 231 -262 257 -258 291 -262 267 -234 261 -292 265 -272 267 -266 235 -266 259 -260 259 -294 267 -268 263 -236 299 -266 233 -300 231 -296 231 -262 257 -256 293 -262 233 -302 229 -298 261 -270 271 -270 231 -264 261 -262 255 -292 265 -272 275 -270 231 -264 261 -262 255 -292 231 -266 259 -260 261 -294 267 -266 265 -270 271 -268 233 -296 229 -262 257 -258 291 -230 293 -264 267 -274 273 -238 261 -292 229 -266 259 -292 265 -270 269 -266 235 -300 231 -296 229 -294 231 -262 257 -290 231 -300 263 -236 301 -266 235 -300 231 -294 229 -262 289 -298 243 -272 235 -264 263 -260 261 -294 229 -264 257 -258 259 -294 267 -268 265 -236 299 -264 235 -300 233 -262 261 -262 257 -292 231 -298 231 -298 263 -268 271 -268 233 -296 229 -262 257 -258 291 -230 295 -264 233 -300 265 -234 299 -232 295 -230 293 -232 293 -264 235 -300 263 -236 299 -264 269 -268 231 -264 261 -294 229 -294 231 -262 257 -290 265 -272 269 -266 235 -300 231 -296 229 -262 261 -294 229 -296 231 -294 229 -296 263 -234 299 -266 267 -268 231 -262 261 -296 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 293 -262 267 -266 233 -296 263 -268 271 -268 233 -262 261 -262 257 -292 231 -298 231 -298 269 -238 265 -260 261 -294 233 -300 231 -296 229 -296 263 -234 299 -266 233 -302 231 -264 261 -260 257 -258 291 -264 267 -268 265 -236 299 -264 233 -300 231 -296 -RAW_Data: 231 -294 263 -236 299 -264 267 -268 231 -264 255 -290 231 -268 259 -292 231 -300 265 -234 301 -266 233 -300 231 -296 229 -264 255 -258 291 -296 241 -276 237 -302 231 -262 259 -262 257 -256 293 -262 269 -266 265 -236 299 -264 235 -300 231 -296 229 -262 257 -258 291 -262 267 -268 265 -270 271 -270 231 -264 255 -258 291 -262 267 -234 261 -292 231 -298 265 -270 265 -266 235 -300 231 -262 257 -290 265 -272 267 -268 235 -300 231 -262 261 -262 257 -258 293 -228 295 -264 269 -272 267 -266 235 -300 231 -294 229 -296 231 -262 257 -256 291 -264 233 -300 265 -236 301 -232 263 -294 233 -300 231 -296 229 -264 257 -258 257 -294 269 -274 273 -270 233 -264 259 -262 257 -258 291 -264 233 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -290 231 -300 265 -270 271 -270 231 -264 261 -294 229 -296 263 -234 301 -264 233 -302 231 -264 261 -262 257 -258 291 -262 235 -300 233 -262 295 -234 299 -266 235 -300 231 -262 263 -260 289 -266 269 -268 271 -268 231 -264 257 -256 291 -262 269 -266 233 -262 295 -234 299 -266 235 -300 231 -296 229 -262 261 -296 229 -296 261 -236 299 -264 235 -302 231 -264 255 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -266 261 -292 265 -272 269 -266 235 -300 229 -264 257 -290 231 -266 259 -294 231 -298 265 -236 301 -266 233 -300 231 -294 231 -262 261 -294 263 -236 299 -266 235 -300 229 -264 257 -258 291 -262 267 -234 261 -292 231 -298 265 -236 299 -264 235 -300 231 -296 229 -264 261 -262 255 -292 231 -300 231 -296 263 -236 299 -266 233 -300 231 -296 229 -296 229 -294 231 -294 229 -296 263 -268 271 -268 233 -296 229 -262 257 -290 231 -300 265 -236 299 -266 233 -300 231 -296 229 -264 261 -262 257 -290 231 -300 265 -268 267 -266 235 -300 231 -294 229 -264 293 -268 267 -266 233 -300 231 -298 229 -262 257 -258 291 -262 235 -300 231 -296 263 -268 271 -270 231 -264 261 -262 255 -258 293 -230 295 -296 241 -276 237 -300 231 -262 255 -290 231 -298 231 -298 263 -268 273 -268 231 -264 261 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -264 257 -290 265 -270 269 -268 233 -302 231 -262 261 -262 257 -258 291 -264 233 -268 259 -292 265 -272 267 -268 235 -300 231 -294 229 -264 255 -290 231 -300 231 -298 229 -296 261 -236 299 -264 235 -300 231 -296 229 -296 229 -262 257 -258 291 -264 233 -300 265 -234 301 -266 233 -300 231 -296 -RAW_Data: 229 -296 229 -294 229 -264 257 -290 265 -272 267 -268 233 -302 229 -264 257 -258 291 -262 267 -234 261 -292 231 -298 265 -234 301 -266 235 -298 231 -264 257 -258 259 -292 269 -268 263 -270 273 -268 233 -262 257 -256 293 -262 267 -266 265 -236 301 -264 233 -300 231 -296 229 -264 261 -294 229 -296 229 -296 263 -234 301 -264 235 -300 231 -264 257 -290 263 -272 267 -268 235 -302 231 -262 257 -290 229 -300 231 -298 229 -262 295 -268 265 -266 235 -300 231 -296 229 -264 261 -262 257 -290 265 -272 275 -270 231 -264 257 -256 291 -264 233 -300 231 -296 263 -236 299 -264 235 -300 231 -296 229 -264 255 -258 291 -264 267 -272 269 -266 235 -300 231 -294 229 -264 257 -290 231 -300 231 -296 229 -296 261 -236 299 -266 233 -302 231 -264 261 -294 229 -296 263 -234 299 -264 235 -300 233 -262 257 -258 289 -230 295 -264 267 -268 265 -234 299 -266 233 -302 231 -262 261 -262 257 -292 231 -298 233 -264 257 -290 231 -298 265 -270 273 -268 231 -264 261 -296 229 -296 229 -262 257 -324 237 -276 237 -302 229 -262 257 -288 231 -300 231 -296 263 -236 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 267 -268 265 -234 299 -266 235 -300 231 -262 263 -294 263 -234 301 -264 235 -300 231 -294 231 -262 257 -290 231 -266 259 -294 231 -300 263 -236 299 -266 233 -302 229 -264 257 -258 291 -230 295 -304 243 -272 235 -266 255 -290 229 -266 259 -294 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 261 -262 257 -290 265 -274 267 -268 235 -300 231 -294 229 -296 229 -262 295 -268 267 -266 233 -300 231 -264 261 -294 229 -264 257 -290 233 -298 265 -236 299 -266 235 -300 229 -296 231 -294 229 -294 229 -296 229 -296 263 -268 271 -268 233 -264 261 -294 229 -296 229 -262 257 -292 265 -270 275 -270 233 -264 261 -294 229 -262 257 -258 291 -264 233 -300 265 -236 299 -266 235 -300 229 -296 229 -262 257 -292 231 -298 231 -298 229 -294 263 -236 299 -264 235 -300 231 -296 229 -296 229 -296 229 -294 231 -262 293 -268 273 -268 233 -264 257 -290 231 -298 231 -296 263 -234 301 -266 235 -300 229 -296 229 -264 255 -292 231 -298 231 -298 263 -268 271 -268 233 -264 261 -262 261 -294 263 -268 273 -270 231 -264 261 -294 229 -264 257 -290 231 -266 259 -292 233 -298 265 -236 301 -266 233 -300 229 -296 231 -262 261 -262 257 -290 265 -272 275 -270 233 -264 255 -258 257 -294 267 -274 269 -268 233 -300 231 -296 229 -296 229 -262 -RAW_Data: 257 -290 231 -300 263 -236 301 -266 235 -298 231 -296 229 -262 259 -290 229 -266 261 -292 231 -300 263 -270 267 -266 235 -300 229 -296 229 -296 229 -262 257 -290 231 -300 265 -268 273 -270 231 -264 261 -262 255 -258 291 -264 269 -234 259 -292 231 -298 265 -234 301 -266 235 -298 231 -264 261 -296 229 -294 229 -296 231 -262 293 -268 267 -266 235 -300 229 -296 231 -262 261 -262 257 -290 265 -272 275 -272 231 -264 261 -262 255 -290 231 -268 259 -292 231 -300 265 -234 301 -266 235 -298 231 -264 257 -258 291 -262 235 -300 265 -236 299 -232 293 -230 295 -264 233 -300 231 -296 263 -234 299 -266 233 -302 231 -262 261 -262 257 -292 231 -298 233 -296 263 -234 299 -266 233 -300 231 -264 257 -258 293 -268 271 -270 237 -300 233 -262 261 -262 255 -258 293 -262 267 -268 265 -236 299 -264 267 -268 231 -264 261 -262 257 -258 291 -264 267 -272 269 -266 235 -300 231 -262 257 -290 231 -298 265 -270 267 -266 233 -300 231 -296 229 -264 255 -290 233 -266 259 -292 265 -272 269 -266 235 -300 231 -294 229 -264 257 -258 259 -294 267 -268 231 -264 295 -268 271 -268 233 -264 261 -262 255 -258 293 -268 271 -270 239 -302 231 -262 261 -262 257 -258 257 -294 269 -266 233 -296 263 -234 299 -264 269 -266 233 -262 261 -296 229 -296 229 -262 257 -290 233 -298 265 -270 265 -266 235 -300 229 -296 229 -264 261 -262 257 -290 231 -300 265 -270 271 -236 261 -292 229 -300 231 -296 229 -296 261 -236 299 -264 235 -300 231 -296 229 -264 261 -262 257 -290 231 -300 265 -270 265 -266 235 -300 231 -294 229 -296 263 -234 299 -266 233 -300 231 -296 229 -296 231 -262 257 -256 291 -264 233 -302 265 -236 299 -264 233 -300 231 -296 231 -262 257 -256 293 -296 239 -278 237 -268 257 -258 257 -294 267 -268 231 -264 295 -234 299 -266 235 -300 231 -264 257 -258 257 -260 295 -264 267 -268 265 -236 299 -264 235 -300 231 -296 229 -262 257 -258 291 -230 293 -264 269 -266 265 -236 299 -264 235 -300 231 -264 257 -256 291 -262 269 -268 265 -234 299 -266 233 -300 231 -296 229 -296 229 -264 255 -258 291 -262 267 -268 265 -236 299 -264 235 -300 233 -262 261 -262 257 -292 231 -266 259 -292 233 -298 265 -236 299 -264 235 -300 233 -262 257 -290 265 -272 267 -268 235 -300 231 -262 263 -294 229 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 233 -262 257 -290 231 -266 259 -294 265 -272 273 -238 259 -292 231 -266 259 -292 231 -300 -RAW_Data: 263 -236 301 -266 233 -300 229 -296 229 -296 229 -296 229 -262 257 -290 265 -272 269 -266 235 -300 231 -262 259 -290 229 -300 265 -270 271 -270 231 -264 257 -256 291 -230 295 -264 233 -302 231 -264 293 -268 271 -270 231 -264 257 -258 257 -294 269 -266 233 -296 269 -272 235 -266 257 -258 259 -260 293 -264 269 -268 265 -234 299 -266 233 -300 231 -296 229 -264 257 -288 231 -300 231 -298 263 -268 271 -268 233 -264 261 -262 257 -290 231 -266 259 -292 233 -298 265 -270 271 -270 231 -264 261 -294 229 -296 229 -296 261 -270 271 -268 233 -264 261 -262 255 -292 231 -266 259 -294 231 -298 231 -298 261 -270 271 -268 231 -298 229 -262 261 -262 257 -290 233 -266 259 -292 233 -298 265 -270 271 -270 231 -262 261 -262 257 -292 231 -298 233 -296 269 -272 235 -300 229 -264 259 -262 257 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -264 257 -290 231 -298 233 -296 263 -234 299 -266 233 -300 231 -298 229 -262 295 -234 299 -266 235 -300 231 -264 261 -262 257 -258 291 -264 233 -268 259 -290 265 -272 267 -268 235 -300 231 -262 257 -258 291 -262 267 -274 275 -270 231 -264 257 -290 229 -300 231 -298 229 -262 295 -268 267 -264 235 -300 231 -264 261 -294 229 -296 231 -262 257 -290 231 -300 229 -298 263 -234 299 -266 233 -300 231 -264 257 -258 259 -294 267 -234 261 -292 231 -300 263 -270 273 -234 261 -258 259 -294 267 -268 265 -234 299 -266 233 -302 231 -264 261 -262 257 -258 291 -262 235 -300 231 -296 263 -234 299 -232 263 -294 267 -268 231 -264 261 -262 257 -292 231 -298 231 -298 263 -234 299 -266 233 -300 231 -264 257 -290 231 -298 265 -270 267 -232 263 -294 233 -300 231 -298 229 -262 257 -258 291 -264 233 -302 265 -234 299 -266 233 -300 231 -264 257 -258 257 -294 267 -274 277 -270 231 -264 261 -294 229 -262 257 -290 231 -300 231 -296 263 -236 299 -264 235 -300 231 -262 259 -258 259 -260 295 -262 269 -268 265 -268 271 -236 261 -290 231 -300 231 -296 229 -296 261 -236 299 -264 269 -266 231 -264 261 -262 257 -290 231 -300 231 -298 263 -268 271 -270 231 -264 261 -262 255 -258 293 -230 293 -264 235 -300 263 -236 299 -266 233 -300 231 -264 257 -290 233 -298 265 -270 271 -270 231 -264 261 -294 229 -296 229 -262 257 -292 231 -298 265 -236 301 -232 261 -294 267 -268 231 -264 261 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -296 229 -296 229 -264 255 -292 231 -300 231 -296 -RAW_Data: 269 -272 235 -266 259 -256 259 -292 267 -268 233 -296 263 -234 299 -266 233 -300 231 -296 229 -264 255 -258 291 -264 267 -268 265 -268 271 -270 231 -264 257 -288 231 -300 265 -268 267 -266 235 -300 231 -294 229 -264 257 -290 231 -266 259 -292 267 -270 269 -266 235 -300 231 -262 257 -290 231 -300 231 -298 269 -272 235 -298 231 -262 261 -262 257 -290 231 -300 263 -270 267 -266 233 -300 231 -296 229 -262 257 -258 291 -262 267 -274 267 -268 235 -300 231 -294 229 -264 293 -268 267 -232 263 -296 233 -300 231 -296 229 -296 229 -262 257 -258 259 -296 267 -266 265 -270 271 -270 231 -262 261 -262 257 -292 231 -266 259 -292 233 -298 231 -296 263 -270 271 -268 231 -296 231 -262 257 -256 293 -262 233 -268 261 -292 231 -298 265 -236 299 -266 233 -300 231 -296 229 -262 257 -292 231 -298 231 -298 263 -268 271 -268 233 -264 261 -294 229 -264 257 -258 259 -294 233 -302 265 -234 299 -266 233 -300 231 -296 229 -264 257 -290 231 -298 233 -296 269 -272 235 -266 263 -262 255 -292 231 -300 231 -296 229 -296 261 -236 299 -264 235 -300 231 -264 257 -258 259 -292 269 -268 231 -296 263 -268 271 -270 231 -262 261 -296 229 -296 261 -236 299 -266 233 -300 231 -296 231 -262 257 -256 291 -230 295 -264 233 -302 263 -270 271 -268 233 -264 261 -262 257 -290 231 -300 231 -296 231 -294 263 -268 271 -270 231 -296 229 -264 255 -290 231 -300 265 -270 271 -270 231 -264 261 -262 255 -292 231 -298 233 -296 231 -262 295 -234 299 -266 235 -300 231 -294 231 -262 261 -294 229 -264 257 -290 233 -298 231 -296 263 -236 299 -266 235 -300 229 -264 257 -290 231 -300 231 -296 263 -234 299 -232 295 -264 233 -268 259 -292 231 -298 265 -236 299 -266 235 -300 231 -294 231 -262 257 -258 291 -228 295 -262 269 -274 267 -268 233 -300 231 -264 255 -258 291 -270 271 -270 237 -300 231 -296 229 -262 261 -262 257 -258 291 -264 267 -268 265 -236 299 -264 233 -300 231 -264 257 -258 259 -262 293 -264 269 -268 271 -238 263 -294 233 -266 259 -292 229 -300 263 -270 273 -270 231 -264 261 -294 229 -262 257 -292 231 -298 231 -296 263 -270 271 -270 231 -264 261 -262 255 -292 265 -272 273 -272 231 -264 261 -262 261 -262 257 -258 293 -262 267 -266 233 -264 295 -266 273 -268 233 -262 263 -294 229 -296 229 -264 259 -296 261 -236 299 -266 235 -300 231 -296 229 -262 257 -290 231 -266 259 -294 265 -272 267 -266 235 -268 259 -290 231 -266 259 -294 -RAW_Data: 231 -298 265 -270 273 -268 231 -264 261 -294 229 -296 229 -264 261 -262 255 -292 231 -300 263 -270 267 -266 235 -298 231 -296 231 -262 261 -294 229 -296 231 -262 293 -268 267 -266 235 -300 231 -262 263 -294 229 -296 263 -268 271 -268 233 -296 229 -262 257 -258 291 -262 267 -234 261 -292 263 -272 269 -266 235 -300 231 -262 261 -294 231 -294 231 -296 267 -272 235 -268 257 -290 231 -266 259 -260 259 -294 267 -268 265 -236 299 -264 235 -300 231 -262 257 -258 291 -262 267 -268 231 -264 295 -268 271 -270 231 -264 263 -294 227 -296 263 -268 273 -268 233 -262 261 -294 231 -262 257 -290 231 -300 231 -298 263 -268 271 -268 231 -264 261 -262 257 -258 293 -294 239 -278 239 -300 231 -260 261 -262 257 -258 291 -264 267 -268 231 -264 293 -234 301 -266 233 -300 231 -296 229 -262 257 -290 231 -300 265 -270 271 -270 231 -264 261 -262 257 -290 231 -266 261 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -294 231 -294 261 -268 267 -266 235 -300 231 -296 229 -262 261 -262 257 -290 233 -298 231 -298 263 -234 299 -266 233 -300 231 -296 231 -262 257 -256 291 -230 295 -264 235 -300 263 -236 299 -266 233 -300 231 -296 231 -262 257 -256 293 -268 271 -270 237 -300 231 -296 229 -264 255 -290 231 -300 231 -298 263 -234 299 -264 235 -300 231 -296 229 -264 257 -258 259 -294 267 -268 265 -270 271 -268 231 -264 255 -292 231 -298 265 -270 267 -266 233 -300 231 -296 229 -262 257 -290 231 -300 231 -296 231 -262 295 -268 271 -270 231 -264 261 -294 229 -296 263 -268 271 -270 231 -264 261 -262 257 -290 231 -300 231 -298 229 -262 295 -268 271 -270 233 -264 257 -288 231 -298 231 -298 231 -262 293 -268 273 -268 233 -264 261 -262 255 -292 231 -298 265 -270 273 -270 231 -264 261 -294 229 -262 259 -258 259 -294 267 -268 265 -234 299 -266 233 -300 231 -298 229 -262 261 -262 257 -290 231 -300 265 -270 267 -266 233 -300 231 -264 261 -294 229 -296 263 -268 271 -270 231 -264 261 -294 229 -296 229 -262 257 -290 231 -300 231 -298 263 -234 299 -266 233 -300 231 -264 257 -258 259 -294 267 -234 261 -292 231 -298 265 -268 267 -266 235 -300 231 -294 229 -296 229 -262 257 -290 265 -272 275 -270 233 -264 255 -258 259 -292 269 -266 267 -234 299 -266 235 -300 231 -262 263 -262 255 -260 291 -230 293 -264 267 -274 269 -266 233 -300 231 -294 231 -294 263 -236 299 -264 267 -268 231 -264 261 -262 257 -258 291 -264 267 -234 -RAW_Data: 259 -292 231 -300 263 -270 273 -268 231 -264 257 -256 291 -230 293 -298 239 -278 237 -300 231 -262 255 -290 231 -298 233 -296 263 -236 299 -264 235 -300 231 -296 229 -264 261 -294 229 -296 229 -296 261 -270 271 -268 233 -262 261 -296 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 257 -290 231 -266 259 -292 233 -298 265 -270 271 -270 231 -264 261 -294 229 -264 261 -294 229 -296 263 -234 299 -266 233 -300 231 -296 231 -262 261 -294 229 -264 257 -290 265 -272 275 -270 233 -264 261 -260 261 -262 259 -290 233 -298 265 -270 271 -270 231 -264 261 -294 229 -264 257 -258 289 -264 267 -268 265 -234 299 -266 233 -302 229 -298 229 -262 261 -262 257 -290 233 -298 231 -298 263 -268 271 -270 231 -264 261 -294 229 -296 229 -296 261 -236 299 -264 235 -302 231 -264 261 -294 229 -262 257 -292 229 -300 265 -270 265 -266 235 -300 231 -294 231 -294 229 -296 263 -268 271 -268 233 -296 229 -262 257 -258 291 -262 269 -266 233 -262 295 -234 299 -266 235 -300 231 -262 257 -290 265 -266 233 -264 261 -294 261 -270 271 -270 231 -264 257 -258 289 -264 267 -274 267 -268 235 -300 229 -264 261 -294 229 -264 257 -290 231 -300 263 -270 273 -268 231 -264 261 -262 257 -258 293 -302 243 -274 235 -266 261 -260 257 -256 291 -264 267 -236 259 -292 231 -298 263 -236 301 -266 235 -300 229 -264 255 -258 293 -262 235 -300 263 -236 299 -266 267 -268 231 -264 261 -260 257 -258 293 -262 269 -266 233 -262 295 -234 299 -264 269 -268 231 -264 261 -294 261 -236 299 -266 235 -300 231 -296 229 -262 257 -290 231 -298 233 -264 257 -290 231 -300 265 -236 299 -266 233 -300 231 -296 231 -262 257 -288 231 -300 231 -298 263 -234 299 -266 233 -300 231 -264 257 -290 231 -300 265 -270 271 -270 231 -262 261 -262 257 -292 231 -266 259 -294 231 -298 231 -298 261 -270 271 -268 231 -264 257 -258 291 -262 269 -266 233 -296 269 -270 235 -266 259 -256 291 -262 267 -268 233 -262 295 -234 299 -266 235 -300 231 -262 257 -290 231 -298 233 -296 231 -262 295 -268 271 -270 231 -264 261 -262 261 -294 263 -236 301 -266 233 -300 231 -296 229 -294 231 -262 257 -290 231 -300 263 -270 273 -268 233 -262 261 -294 231 -262 257 -292 231 -298 271 -274 235 -268 261 -262 255 -290 265 -266 233 -296 263 -234 299 -264 235 -300 231 -296 229 -264 257 -256 291 -264 267 -268 265 -234 299 -266 233 -300 231 -296 231 -262 257 -256 291 -264 267 -268 265 -234 -RAW_Data: 299 -266 233 -300 231 -296 231 -294 229 -264 293 -268 267 -266 233 -300 231 -296 229 -264 257 -290 231 -298 233 -296 231 -262 293 -234 301 -264 235 -302 231 -262 261 -294 229 -264 257 -258 293 -262 267 -266 265 -236 299 -266 233 -300 231 -296 229 -264 255 -258 293 -294 241 -276 239 -268 263 -260 257 -290 231 -264 261 -292 233 -298 265 -236 299 -264 269 -268 231 -262 257 -258 291 -230 295 -262 235 -300 263 -270 271 -270 231 -264 255 -290 231 -300 265 -236 301 -232 263 -294 233 -300 231 -296 229 -296 229 -264 255 -290 231 -300 265 -270 271 -270 231 -264 261 -262 257 -258 291 -304 241 -276 233 -266 261 -262 261 -262 255 -292 265 -266 263 -270 267 -266 233 -300 231 -296 229 -262 263 -262 263 -262 261 -294 263 -268 273 -268 233 -264 261 -262 293 -236 299 -264 269 -268 231 -262 263 -262 261 -294 231 -262 257 -290 265 -266 265 -270 271 -270 231 -264 261 -262 255 -292 265 -266 231 -296 263 -236 299 -266 267 -266 231 -262 263 -262 263 -262 257 -258 291 -264 267 -272 269 -266 235 -300 231 -262 261 -264 255 -258 293 -262 267 -266 265 -236 301 -230 295 -262 267 -268 231 -264 257 -290 263 -234 259 -260 293 -262 267 -266 265 -236 299 -266 267 -266 231 -264 261 -262 263 -262 257 -290 265 -272 269 -266 269 -234 259 -290 265 -264 231 -264 297 -234 299 -266 267 -266 231 -264 261 -264 255 -290 265 -234 261 -292 265 -270 269 -266 269 -266 231 -262 263 -262 293 -236 299 -266 269 -268 229 -264 261 -262 255 -292 265 -234 259 -294 231 -298 231 -264 293 -268 273 -270 231 -264 261 -262 261 -262 257 -292 265 -264 273 -274 235 -266 257 -258 289 -262 267 -268 265 -236 299 -266 267 -266 231 -264 261 -264 255 -290 265 -266 231 -264 295 -270 271 -270 231 -264 261 -262 255 -290 265 -272 269 -268 235 -268 263 -262 261 -262 261 -264 257 -290 265 -266 231 -264 295 -270 273 -268 231 -264 261 -260 257 -290 265 -268 231 -264 295 -234 299 -266 269 -266 231 -262 263 -262 diff --git a/assets/resources/subghz/Jamming/Jam_433.42.sub b/assets/resources/subghz/Jamming/Jam_433.42.sub deleted file mode 100644 index 5429a21de..000000000 --- a/assets/resources/subghz/Jamming/Jam_433.42.sub +++ /dev/null @@ -1,15 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 433420000 -Preset: FuriHalSubGhzPresetOok650Async -Protocol: RAW -RAW_Data: 45037 -268 199 -548 48975 -282 217 -544 48999 -244 217 -562 48941 -268 201 -548 49001 -250 217 -546 48981 -224 211 -560 48985 -248 253 -542 48967 -246 211 -566 48979 -228 219 -564 48973 -282 187 -560 48993 -250 215 -550 48963 -282 187 -560 48981 -282 217 -530 48961 -280 217 -526 48977 -282 217 -542 48979 -224 211 -562 48985 -242 245 -526 48977 -280 213 -530 48987 -248 217 -542 48979 -280 211 -532 48977 -282 217 -546 48973 -240 243 -524 48971 -280 211 -532 48997 -246 215 -574 48961 -250 211 -566 48965 -260 227 -528 48987 -280 181 -560 48981 -276 209 -526 48977 -280 217 -528 48981 -282 217 -542 48957 -278 211 -528 48971 -282 181 -564 48981 -270 203 -552 48983 -282 179 -576 48961 -280 217 -524 48973 -282 187 -560 48967 -280 217 -530 48979 -282 217 -524 48977 -248 251 -526 48973 -260 225 -532 48983 -276 217 -528 48987 -256 211 -562 48981 -252 215 -548 48965 -282 217 -542 48947 -280 217 -546 48949 -282 215 -552 48953 -274 219 -562 48965 -256 181 -594 48965 -282 185 -568 48957 -284 215 -544 48973 -238 253 -518 49005 -240 217 -532 49003 -244 217 -530 48979 -278 217 -530 48991 -248 211 -566 48957 -264 229 -540 48989 -246 193 -584 48971 -280 181 -558 48981 -248 215 -558 48987 -250 217 -552 48967 -284 217 -508 49051 -194 225 -570 48949 -246 253 -526 48989 -240 217 -566 48947 -282 215 -550 48947 -280 213 -566 48949 -282 217 -544 48979 -246 213 -570 48945 -282 217 -546 48979 -244 217 -562 48981 -228 217 -562 48983 -248 217 -554 48957 -284 185 -564 48995 -242 211 -566 48963 -262 191 -568 48977 -276 217 -524 48983 -262 223 -536 48983 -276 217 -524 48969 -284 185 -566 48965 -284 217 -544 48951 -272 205 -554 48989 -266 201 -546 48993 -232 231 -542 48999 -240 217 -564 48949 -272 217 -532 49003 -250 211 -534 48995 -258 191 -570 48973 -272 217 -532 48997 -248 187 -566 48973 -274 217 -524 49007 -250 215 -552 48969 -278 209 -526 48981 -270 203 -550 48993 -250 215 -552 48973 -246 253 -524 48975 -274 219 -526 48993 -242 219 -530 49007 -232 211 -562 48983 -246 253 -524 48977 -278 209 -526 48991 -246 215 -574 48961 -252 211 -564 48965 -284 217 -544 48947 -280 213 -532 48973 -280 211 -534 48985 -278 187 -560 48975 -276 217 -528 48965 -272 215 -566 48977 -242 217 -564 48967 -248 217 -556 48977 -248 253 -528 48953 -280 217 -528 48981 -284 217 -542 48967 -258 213 -560 48973 -238 253 -528 48979 -238 255 -528 48971 -240 253 -528 48967 -252 211 -564 48967 -264 229 -542 48965 -278 217 -530 49001 -248 215 -538 49003 -250 217 -548 48963 -278 211 -530 48969 -280 217 -556 48945 -276 217 -564 48953 -278 217 -528 48963 -286 181 -564 48983 -272 203 -552 -RAW_Data: 48975 -282 217 -542 48949 -278 219 -562 48957 -276 209 -528 48997 -246 215 -570 48975 -246 215 -534 49017 -238 217 -528 49025 -246 181 -576 48975 -238 203 -574 49021 -240 203 -546 48983 -242 207 -550 49023 -212 217 -540 48999 -240 217 -542 49019 -244 217 -542 48987 -236 201 -572 48999 -242 205 -548 49021 -202 219 -562 48995 -238 217 -556 48983 -238 217 -562 48997 -238 217 -524 49009 -240 217 -528 49023 -238 217 -528 49031 -202 219 -560 49003 -238 217 -528 48999 -232 223 -564 48993 -238 215 -530 49027 -206 237 -542 48993 -228 215 -560 49013 -240 217 -528 48999 -238 201 -570 49021 -194 215 -560 49027 -204 217 -562 48997 -232 211 -532 49015 -246 207 -550 49025 -202 219 -560 48995 -248 213 -528 49013 -248 215 -542 49013 -214 217 -536 49019 -212 247 -526 49013 -212 247 -526 49029 -214 217 -536 49017 -226 211 -564 48993 -238 219 -530 49013 -228 221 -560 48989 -238 215 -530 49017 -242 207 -548 49019 -214 191 -582 48995 -238 217 -530 49011 -246 217 -544 49005 -214 217 -540 49019 -240 217 -528 49027 -204 253 -528 49017 -204 253 -528 49013 -210 215 -558 49013 -214 217 -538 49015 -248 215 -546 48991 -246 217 -544 49001 -212 253 -506 49031 -214 247 -528 48995 -246 185 -566 49011 -212 253 -508 49031 -214 213 -558 49017 -216 215 -540 49007 -250 217 -534 49007 -246 217 -510 49027 -248 215 -528 48993 -242 217 -552 48993 -242 185 -568 49005 -244 215 -548 48997 -224 211 -566 49013 -232 195 -566 49011 -208 215 -568 48999 -228 189 -558 49003 -238 203 -572 49009 -212 221 -554 48999 -244 217 -546 48997 -248 185 -560 49003 -240 217 -530 49025 -208 251 -524 49021 -208 215 -558 49025 -210 217 -552 49013 -208 217 -556 48999 -250 213 -530 49009 -246 217 -544 48985 -248 215 -540 49025 -208 217 -554 49005 -212 253 -540 48993 -248 213 -526 49011 -240 217 -528 49013 -248 215 -542 48995 -240 219 -526 49029 -208 217 -554 48993 -228 215 -560 49019 -202 253 -528 49017 -206 237 -542 48991 -228 221 -540 49019 -238 217 -530 49013 -230 221 -564 48985 -240 181 -566 49009 -230 221 -530 49031 -212 211 -560 49025 -212 217 -538 49005 -244 215 -550 49003 -240 217 -526 49025 -202 219 -560 49025 -202 217 -564 49011 -238 181 -556 48997 -230 215 -562 49023 -206 215 -556 49011 -244 179 -578 48997 -246 213 -538 48997 -240 181 -566 49015 -240 205 -550 48991 -242 217 -550 49011 -246 175 -558 48997 -246 213 -538 49003 -242 215 -552 48991 -242 215 -552 49017 -212 215 -540 49015 -244 215 -546 49001 -246 211 -526 49013 -240 205 -552 49001 -238 217 -562 48997 -240 181 -562 49017 -238 181 -564 48989 -246 191 -582 49003 -238 181 -562 48999 -242 185 -570 49017 -236 219 -528 -RAW_Data: 49019 -238 217 -528 49001 -226 215 -562 48999 -246 215 -546 49009 -206 217 -556 49017 -240 217 -524 49019 -224 181 -596 48993 -246 211 -528 49011 -238 217 -528 49031 -202 219 -554 48999 -236 217 -556 49017 -202 217 -564 49005 -240 219 -524 49005 -246 213 -534 49019 -242 203 -546 49007 -242 205 -546 49011 -246 177 -560 49013 -240 219 -524 49019 -202 255 -526 49015 -240 217 -526 49009 -240 217 -530 49033 -238 217 -528 48999 -246 185 -560 49025 -202 219 -562 49009 -224 211 -564 49005 -206 203 -572 49001 -240 179 -568 49003 -238 233 -542 49005 -212 215 -576 48981 -244 215 -548 48985 -244 215 -552 49009 -246 181 -576 48975 -248 191 -580 48987 -238 217 -562 49005 -204 217 -562 49009 -238 217 -528 49021 -202 217 -564 48997 -244 185 -566 49025 -208 215 -558 49019 -208 215 -558 49017 -206 237 -542 49017 -212 211 -554 49011 -242 205 -546 48995 -248 213 -532 49027 -214 215 -540 49033 -214 191 -582 48983 -244 209 -554 49003 -246 213 -530 48999 -244 207 -554 49015 -248 175 -560 49009 -248 213 -528 49013 -248 211 -528 49009 -246 213 -530 49017 -246 217 -548 48969 -244 209 -554 49015 -240 217 -524 48999 -236 217 -564 49011 -204 217 -564 48989 -238 217 -528 49013 -238 217 -562 48985 -236 217 -564 49003 -208 215 -556 49023 -210 211 -556 49019 -238 181 -564 49013 -240 217 -524 49029 -208 215 -554 49009 -246 177 -560 49001 -244 207 -552 49019 -212 209 -556 49005 -244 185 -566 48997 -228 221 -538 49015 -244 207 -550 48995 -246 215 -536 49013 -246 217 -544 49009 -214 215 -540 49019 -246 217 -540 49011 -212 245 -522 49017 -214 215 -538 49019 -238 217 -530 49031 -204 217 -562 49017 -208 215 -556 49011 -242 217 -524 49017 -240 217 -524 49005 -246 215 -546 48991 -238 217 -528 49039 -204 217 -564 48991 -238 217 -530 49005 -228 223 -538 49041 -214 215 -540 48999 -242 215 -542 49013 -226 215 -562 49015 -208 215 -556 49005 -244 187 -560 49021 -204 217 -554 49025 -202 217 -554 49015 -232 179 -598 48979 -246 213 -534 49019 -238 217 -526 49015 -246 217 -544 48985 -244 217 -554 48979 -248 213 -536 49003 -244 207 -554 49023 -212 215 -538 49031 -212 215 -540 49035 -214 215 -536 49029 -214 215 -540 49005 -244 209 -554 49013 -208 251 -524 48999 -248 213 -534 49019 -212 251 -540 48991 -248 213 -528 49027 -194 211 -564 49009 -236 201 -570 48983 -242 217 -552 49019 -206 215 -556 48997 -242 209 -554 49017 -212 211 -556 49009 -242 205 -548 49005 -242 205 -548 48995 -244 207 -550 49011 -240 219 -524 49027 -208 215 -554 49017 -206 215 -560 49021 -208 215 -556 48993 -244 209 -554 49007 -242 205 -548 48989 -238 203 -572 49009 -240 205 -544 49003 -248 211 -528 -RAW_Data: 49013 -242 205 -548 48997 -242 207 -550 48999 -244 215 -548 49017 -208 215 -556 48997 -246 215 -546 49011 -206 217 -556 49005 -236 219 -556 48981 -238 211 -566 49003 -212 211 -558 49013 -248 175 -560 49007 -246 215 -532 49017 -240 179 -568 49001 -228 221 -540 49023 -240 205 -544 48993 -246 193 -580 49009 -202 217 -564 49009 -202 255 -554 48987 -240 217 -524 48997 -238 217 -562 48997 -246 185 -560 48997 -238 217 -562 48985 -244 215 -548 49009 -240 181 -558 49015 -246 181 -576 49005 -206 217 -556 48989 -244 215 -554 49003 -246 213 -528 49021 -240 217 -522 49013 -246 215 -544 49007 -210 215 -574 48979 -244 207 -552 49017 -212 215 -576 48971 -242 215 -552 48987 -244 215 -572 48999 -240 181 -572 48979 -232 225 -566 48999 -246 181 -574 48997 -246 181 -576 48995 -240 181 -560 48995 -242 185 -604 48993 -232 197 -570 49003 -238 179 -566 48999 -236 199 -572 48991 -228 217 -562 48987 -236 217 -562 48997 -236 197 -572 48989 -228 217 -562 49005 -238 181 -562 49005 -230 193 -594 49001 -242 181 -556 49001 -236 217 -562 48989 -228 221 -566 48967 -244 209 -558 48997 -236 217 -556 49005 -238 217 -528 49019 -238 217 -524 49007 -244 215 -548 48985 -242 215 -552 48995 -236 217 -564 48981 -244 193 -580 48995 -238 219 -526 49023 -240 181 -560 49009 -246 211 -530 48997 -246 215 -538 49019 -246 211 -528 49015 -246 177 -562 48999 -246 215 -536 49027 -212 215 -540 49019 -246 215 -544 48981 -246 215 -536 49035 -204 217 -562 48983 -242 217 -552 49007 -246 211 -526 49009 -246 213 -530 49027 -206 215 -572 48979 -232 225 -564 48995 -244 217 -542 49005 -238 181 -564 48997 -226 211 -566 48991 -242 209 -554 48991 -242 217 -554 48985 -242 217 -554 49019 -202 217 -564 49003 -236 217 -562 48987 -246 179 -576 48999 -246 179 -576 48995 -240 217 -526 49029 -202 217 -564 49021 -208 215 -554 48995 -246 215 -534 49009 -246 215 -546 48985 -242 217 -550 49007 -248 179 -576 49007 -248 217 -544 48979 -246 179 -578 48979 -244 217 -550 48995 -248 193 -546 49033 -212 191 -584 49011 -206 217 -556 49025 -208 215 -554 48991 -244 215 -552 49005 -246 185 -558 48999 -244 185 -566 49021 -206 251 -560 48987 -212 191 -582 48999 -226 215 -562 48989 -246 215 -532 49033 -208 215 -574 48985 -238 217 -528 49009 -246 213 -534 49029 -206 215 -556 49023 -202 217 -564 48985 -236 217 -562 48989 -236 211 -564 49009 -232 195 -566 48983 -242 187 -570 49013 -238 219 -526 49035 -204 203 -574 49011 -242 203 -542 48989 -238 201 -572 48993 -242 207 -550 48989 -238 203 -576 48983 -246 209 -552 48997 -244 209 -554 49019 -204 203 -574 49013 -210 211 -558 49005 -246 185 -562 49007 -228 213 -562 -RAW_Data: 49011 -212 211 -556 48995 -244 215 -552 49017 -212 211 -554 49007 -248 213 -528 49005 -248 213 -532 49025 -212 217 -538 49013 -244 217 -546 48993 -240 217 -530 49023 -212 253 -506 49009 -244 209 -554 49007 -248 213 -526 49003 -248 215 -532 48999 -244 215 -552 49021 -210 215 -554 48993 -244 217 -548 49003 -208 251 -526 49003 -248 213 -534 49009 -248 213 -530 49025 -214 215 -540 49033 -214 215 -536 49021 -212 247 -524 49025 -214 215 -540 49003 -244 215 -552 49013 -212 211 -558 48997 -242 217 -550 49021 -214 215 -536 49031 -214 215 -540 49011 -248 213 -530 49007 -246 215 -546 48989 -248 215 -532 49025 -212 217 -540 49021 -246 217 -540 49009 -214 217 -536 49025 -212 213 -558 49013 -212 251 -542 48981 -246 215 -548 49001 -212 251 -540 49003 -212 215 -542 49037 -208 215 -556 49015 -204 253 -528 48997 -228 213 -562 48995 -248 213 -532 49021 -212 215 -576 48993 -242 205 -546 48995 -244 207 -550 49005 -240 217 -528 49031 -208 215 -544 49015 -236 219 -528 49013 -246 185 -564 49025 -208 217 -554 49011 -212 251 -508 49027 -226 211 -532 49043 -198 211 -562 49007 -232 211 -564 49009 -202 211 -564 49009 -240 181 -566 49003 -246 185 -568 49015 -234 197 -566 48989 -228 221 -536 49041 -204 217 -562 49013 -198 227 -564 48989 -228 221 -538 49027 -240 217 -528 49009 -238 219 -526 49015 -248 213 -528 49005 -248 215 -532 49015 -246 217 -510 49025 -246 217 -510 49019 -244 217 -548 49009 -208 215 -558 49001 -238 217 -530 49039 -198 211 -564 49019 -202 211 -564 49009 -238 219 -528 49009 -228 223 -528 49017 -228 215 -560 49013 -238 217 -530 48999 -236 201 -568 49021 -194 217 -560 49013 -238 219 -528 49001 -236 201 -572 49019 -196 215 -560 49021 -202 255 -518 49005 -236 199 -570 49019 -194 217 -560 49013 -238 215 -530 49027 -206 237 -540 49021 -194 217 -560 215 -530 49031 -204 203 -572 49009 -202 255 -528 49021 -206 205 -574 49019 -196 215 -560 49013 -238 219 -516 49013 -244 207 -550 49023 -194 217 -560 49013 -238 217 -514 49047 -216 217 -536 49027 -194 217 -560 49015 -238 215 -530 49003 -236 201 -570 49009 -238 217 -530 49001 -236 201 -570 49001 -238 215 -516 49045 -212 209 -554 48997 -226 221 -538 49039 -204 217 -564 49013 -198 227 -562 49019 -194 215 -562 49013 -238 217 -516 49013 -244 209 -550 48999 -228 219 -540 49019 -240 217 -528 49013 -228 221 -526 49017 -228 215 -560 49013 -202 253 -530 49023 -206 203 -572 49019 -194 215 -560 49019 -202 253 -530 49025 -204 203 -572 49019 -194 217 -560 49017 -238 217 -530 49021 -206 239 -542 48987 -228 221 -538 49039 -204 217 -562 48997 -228 223 -528 49017 -226 215 -562 49015 -202 253 -518 49015 -242 -RAW_Data: 205 -546 49021 -194 217 -560 49015 -238 217 -530 49023 -206 239 -540 48993 -228 215 -560 49013 -238 217 -530 49019 -206 237 -542 48993 -228 213 -562 49013 -240 217 -528 49027 -204 203 -570 49021 -196 215 -560 49013 -238 219 -528 49019 -206 237 -542 49021 -194 217 -560 49013 -238 215 -532 49029 -206 203 -572 49021 -196 215 -560 49013 -238 217 -566 48977 -242 205 -544 49021 -194 217 -560 49013 -238 217 -516 49035 -214 215 -540 49029 -226 189 -558 49015 -226 215 -560 49013 -204 253 -528 49021 -206 203 -572 49021 -194 221 -538 49039 -204 253 -530 49005 -226 189 -558 49017 -244 217 -544 49019 -204 217 -562 49009 -208 215 -556 48993 -244 209 -552 49021 -208 217 -554 48995 -238 217 -530 49029 -222 211 -534 49045 -212 211 -552 48999 -250 215 -542 49011 -214 217 -538 49035 -210 215 -556 49001 -246 217 -544 48987 -236 219 -528 49011 -238 217 -530 49045 -208 215 -556 49009 -212 211 -558 49017 -212 213 -558 49027 -202 217 -564 49017 -228 197 -568 48983 -240 217 -530 49011 -228 233 -530 49007 -238 217 -530 49019 -234 199 -568 49021 -194 221 -538 49039 -204 217 -564 49013 -198 227 -562 49019 -194 217 -560 49013 -238 215 -530 49017 -244 209 -548 48991 -238 215 -530 49019 -242 205 -546 48993 -228 221 -538 49019 -238 219 -528 49013 -228 233 -528 49009 -236 217 -530 49023 -234 197 -568 49019 -196 215 -560 49013 -238 215 -518 49011 -246 209 -550 49023 -194 217 -560 49015 -238 217 -516 49043 -212 209 -554 49021 -196 217 -558 49015 -238 215 -530 49031 -206 235 -540 48991 -228 221 -540 49017 -240 217 -530 49021 -228 195 -570 49015 -202 255 -526 49017 -198 227 -562 49019 -194 217 -560 49021 -202 255 -528 49011 -234 195 -564 48995 -240 217 -530 49021 -206 215 -566 49021 -200 225 -562 49009 -206 253 -522 49015 -226 193 -568 49009 -238 217 -528 49023 -198 229 -564 48987 -226 215 -562 49017 -202 253 -518 49029 -206 237 -542 49021 -194 215 -562 49013 -238 217 -518 49013 -244 207 -552 48995 -228 221 -536 49039 -204 217 -562 49013 -198 229 -562 49019 -196 215 -560 49013 -238 215 -530 49019 -206 239 -544 49023 -194 215 -562 49011 -240 217 -528 49019 -240 205 -542 49025 -196 221 -538 49019 -240 217 -530 49009 -230 221 -562 48983 -228 215 -560 49013 -238 217 -530 48999 -236 201 -570 49021 -194 215 -560 49013 -238 217 -530 49025 -206 237 -542 49021 -196 215 -562 49011 -240 217 -528 49021 -206 237 -544 48997 -226 221 -538 49019 -240 217 -528 49015 -228 221 -560 48991 -238 215 -532 49019 -242 205 -544 48993 -228 221 -538 49019 -238 217 -530 49015 -230 231 -532 49013 -238 217 -564 48995 -198 225 -560 48987 -228 215 -560 49013 -240 217 -528 49023 -206 -RAW_Data: 237 -540 49021 -194 215 -562 49013 -238 215 -532 49019 -206 239 -542 49021 -194 215 -560 49023 -240 217 -528 49003 -238 217 -564 49003 -202 217 -564 49011 -202 217 -564 48993 -238 217 -530 49043 -204 217 -562 49011 -196 215 -562 49019 -238 217 -518 49025 -242 205 -542 48993 -228 221 -538 49027 -240 219 -526 49039 -200 227 -562 48989 -240 217 -516 49017 -242 207 -548 49019 -194 217 -560 49027 -204 217 -564 48997 -236 199 -568 48999 -238 215 -546 48993 -244 209 -550 49019 -208 215 -546 49017 -234 197 -568 49005 -238 217 -518 49023 -242 205 -546 48999 -226 221 -536 49041 -204 217 -564 48983 -230 235 -530 49019 -238 217 -524 49021 -234 197 -564 49021 -196 215 -560 49013 -238 215 -530 49017 -242 203 -544 49021 -194 217 -560 49013 -240 215 -516 49043 -212 211 -554 49021 -194 217 -560 49013 -238 215 -530 49027 -206 237 -542 49023 -194 215 -560 49013 -238 217 -516 49035 -214 215 -542 49027 -226 189 -558 49015 -228 213 -560 49011 -240 217 -528 49019 -204 239 -542 49019 -194 217 -560 49013 -238 215 -532 49017 -244 203 -544 49021 -194 223 -538 49017 -238 253 -526 48983 -230 223 -562 48989 -228 213 -562 49015 -202 253 -528 49011 -234 195 -564 49005 -238 217 -530 49005 -234 199 -570 49013 -208 215 -556 48997 -246 215 -550 49015 -214 215 -538 49033 -244 217 -526 48995 -212 251 -542 49013 -214 217 -534 49023 -206 253 -522 49023 -194 217 -560 49015 -238 215 -548 49003 -212 251 -508 49029 -226 195 -570 49015 -202 255 -524 49013 -234 195 -566 49019 -194 215 -560 49013 -238 217 -528 49015 -242 205 -546 49025 -194 221 -538 49039 -204 217 -560 49013 -200 229 -564 49019 -194 215 -560 49013 -238 217 -528 49027 -206 237 -540 49021 -194 217 -560 49019 -208 251 -524 48995 -246 215 -536 49003 -246 217 -548 48999 -238 219 -526 49015 -220 211 -570 49015 -198 227 -564 48985 -246 215 -550 49001 -240 217 -564 48983 -212 213 -556 49033 -210 215 -552 49019 -208 217 -554 49015 -208 215 -544 49033 -214 191 -582 48993 -244 217 -544 48993 -236 219 -562 48987 -244 217 -544 49013 -212 217 -538 49031 -246 217 -544 48989 -212 211 -554 49025 -208 217 -554 49013 -212 215 -544 49025 -246 213 -526 49027 -212 209 -556 49017 -214 215 -540 49013 -238 217 -528 49009 -236 219 -554 49011 -238 219 -524 49007 -244 217 -546 49003 -242 217 -524 48999 -244 209 -552 48997 -244 217 -546 49011 -210 213 -556 49009 -246 213 -528 49009 -244 217 -544 49015 -204 211 -568 48985 -226 217 -560 49017 -248 175 -560 49019 -240 181 -568 49017 -204 203 -574 49015 -206 217 -556 49019 -206 217 -558 49009 -246 217 -542 49003 -212 211 -560 49013 -212 211 -560 49043 -214 217 -536 48993 -244 -RAW_Data: 217 -548 49001 -228 195 -568 49017 -204 253 -528 49003 -236 219 -524 49021 -238 217 -516 49031 -206 239 -544 49003 -238 215 -532 49021 -242 205 -544 49001 -228 213 -560 49017 -212 209 -556 48993 -244 209 -554 48993 -238 217 -562 49005 -240 217 -528 49005 -230 211 -534 49013 -230 225 -562 48995 -240 217 -526 49017 -238 217 -528 49005 -248 193 -546 49027 -240 217 -526 48997 -244 215 -550 49007 -238 217 -524 49031 -214 215 -540 49017 -234 197 -570 49003 -234 197 -566 49005 -248 175 -560 49005 -234 199 -570 49009 -242 205 -552 48979 -238 201 -574 49011 -212 215 -574 48991 -240 219 -522 48997 -246 193 -582 48995 -240 217 -526 49005 -242 215 -550 48991 -244 217 -548 49005 -240 217 -526 49003 -244 217 -548 48991 -238 217 -564 49005 -206 217 -554 48995 -236 217 -564 49005 -240 181 -558 49015 -240 217 -524 48995 -236 219 -560 48989 -236 217 -564 48983 -236 219 -562 49007 -238 181 -564 48995 -242 217 -546 48991 -248 213 -536 49025 -210 215 -544 49017 -218 213 -570 49005 -234 197 -568 48995 -240 217 -528 49031 -206 215 -558 48993 -244 209 -552 48997 -244 213 -576 48989 -212 217 -540 49015 -246 213 -530 49027 -210 211 -554 49019 -248 175 -560 49009 -244 217 -542 48987 -238 217 -530 49009 -246 215 -536 49019 -240 217 -526 49027 -212 209 -556 49027 -214 215 -538 49011 -248 213 -530 49017 -212 253 -540 48991 -240 219 -526 49021 -202 253 -530 49023 -198 225 -562 49011 -204 217 -554 49013 -242 205 -544 49023 -194 217 -560 49015 -238 217 -528 49019 -242 205 -544 49023 -194 221 -538 49041 -202 217 -564 49017 -198 225 -562 48991 -224 211 -564 48997 -230 223 -562 48987 -244 207 -550 48995 -248 217 -540 49007 -248 213 -526 49031 -214 217 -536 49021 -212 217 -540 49025 -210 253 -506 49017 -246 215 -550 49013 -212 211 -556 48999 -248 213 -532 49013 -246 213 -530 49015 -212 215 -542 49039 -206 215 -558 49005 -246 215 -544 48995 -238 181 -566 49017 -246 211 -528 49013 -244 217 -542 48991 -240 217 -530 49003 -244 209 -554 49015 -212 215 -574 48991 -248 211 -526 49029 -212 215 -540 49033 -214 215 -538 49013 -246 213 -530 48999 -242 215 -552 49001 -246 211 -532 48997 -242 215 -554 48991 -242 217 -552 48999 -246 213 -532 49015 -246 217 -548 48985 -244 217 -544 48989 -246 215 -546 48987 -246 215 -534 49025 -206 215 -558 49021 -240 181 -560 49007 -240 217 -526 49007 -244 215 -550 48987 -236 217 -564 48991 -244 217 -546 48981 -248 183 -568 49009 -238 217 -562 48975 -248 215 -534 49029 -212 215 -542 49031 -210 211 -556 49021 -212 215 -540 49027 -240 217 -526 49011 -248 215 -542 48989 -248 213 -532 49011 -240 217 -526 49013 -236 217 -556 49001 -206 -RAW_Data: 253 -522 49015 -248 185 -558 49021 -208 215 -576 48981 -226 221 -568 48989 -228 197 -570 48993 -242 207 -552 49017 -238 217 -564 48953 -244 209 -554 49015 -240 217 -522 49007 -238 217 -562 48989 -238 217 -530 49007 -244 215 -548 49011 -212 217 -574 48989 -244 217 -542 48985 -248 213 -534 49003 -246 215 -534 49021 -248 179 -578 48971 -242 217 -552 49013 -244 179 -576 48975 -258 187 -562 48993 -246 213 -572 48977 -244 215 -548 48995 -244 213 -532 49019 -246 213 -528 48997 -242 209 -554 49005 -246 215 -544 48997 -246 215 -544 48995 -246 215 -542 48979 -244 209 -556 49009 -242 203 -548 49005 -248 211 -528 48995 -246 215 -538 49003 -244 215 -552 49019 -212 215 -576 48965 -248 191 -582 48993 -248 211 -530 49021 -206 215 -570 48993 -236 199 -570 48985 -248 191 -580 48985 -246 193 -578 48979 -244 215 -550 49003 -238 217 -524 49019 -238 217 -528 49019 -240 217 -526 49011 -240 217 -530 49013 -238 217 -530 49039 -202 219 -554 49021 -210 215 -554 49007 -210 253 -540 49001 -212 215 -542 49031 -204 253 -528 49015 -214 215 -540 49013 -246 215 -530 49019 -240 217 -526 49023 -206 215 -570 48983 -228 211 -564 49027 -210 211 -554 49027 -202 217 -562 48991 -244 215 -548 49001 -244 217 -544 48981 -238 211 -566 48985 -230 235 -528 49017 -242 207 -548 49007 -246 217 -540 48997 -238 217 -524 49025 -238 219 -526 49009 -238 217 -528 49005 -244 215 -550 49001 -246 185 -560 48997 -236 217 -556 49005 -238 217 -524 49009 -246 215 -548 48989 -246 193 -580 48981 -246 215 -548 48985 -242 187 -570 49023 -240 181 -560 49003 -248 213 -532 49025 -246 215 -546 48981 -246 211 -528 49009 -246 215 -546 48999 -246 217 -540 48997 -238 219 -524 49025 -212 215 -574 49003 -206 215 -558 49021 -206 215 -556 48993 -238 217 -562 48995 -236 217 -524 49023 -238 217 -528 49037 -204 217 -554 48993 -236 217 -564 49003 -202 255 -524 49013 -240 217 -528 49007 -246 215 -544 49019 -208 215 -554 49009 -214 251 -546 48991 -212 217 -540 49019 -240 217 -528 49013 -240 217 -528 49001 -236 217 -562 48999 -244 215 -544 48991 -244 215 -546 48985 -242 215 -552 48993 -236 219 -562 48981 -242 217 -550 49017 -246 215 -546 48981 -248 213 -526 49009 -240 217 -528 49039 -194 215 -560 49011 -212 251 -526 49013 -208 251 -528 49017 -212 213 -558 49003 -246 217 -544 48991 -240 217 -530 49011 -236 217 -556 49011 -194 217 -558 49019 -214 251 -506 49045 -210 215 -552 49015 -202 255 -526 49015 -214 191 -584 48987 -236 217 -556 49021 -204 217 -564 48991 -228 223 -562 48991 -238 217 -548 48981 -238 203 -572 49023 -204 217 -564 49001 -240 217 -528 49003 -226 219 -540 49021 -234 197 -566 49001 -240 -RAW_Data: 217 -526 49021 -240 217 -524 49003 -248 215 -534 49017 -238 217 -562 48969 -244 217 -548 49019 -208 215 -554 48989 -244 217 -550 49013 -208 215 -558 49011 -248 179 -544 49007 -246 213 -572 48975 -244 215 -550 48993 -244 185 -564 49003 -236 217 -556 49013 -238 179 -564 48999 -236 217 -562 48981 -236 219 -554 49013 -202 211 -566 48995 -244 209 -554 49013 -212 215 -576 48971 -240 217 -554 48989 -252 181 -568 49011 -228 221 -540 48999 -230 227 -564 48987 -248 211 -534 49011 -244 217 -544 48991 -244 215 -548 49001 -240 217 -524 48999 -228 223 -574 49001 -240 181 -558 49021 -242 179 -572 48991 -262 191 -568 48969 -248 213 -536 49003 -246 215 -536 49031 -208 215 -556 49001 -246 215 -546 48985 -244 215 -550 48985 -242 185 -572 49027 -238 181 -554 49013 -238 217 -528 49019 -238 219 -528 49023 -212 211 -560 49007 -242 205 -550 49019 -212 209 -554 49013 -246 213 -524 49023 -242 169 -576 48989 -238 201 -574 49007 -240 205 -544 48991 -244 207 -552 49017 -232 195 -566 48983 -244 209 -554 49011 -234 195 -568 48993 -246 213 -532 49005 -246 215 -546 48985 -244 215 -552 48999 -246 213 -530 49003 -242 217 -550 49005 -246 181 -576 48989 -236 219 -564 48969 -236 219 -562 48995 -224 211 -568 48989 -228 215 -562 49013 -246 175 -560 49011 -242 205 -546 49009 -218 213 -574 48985 -236 181 -566 49029 -234 195 -568 48979 -250 181 -568 49019 -240 217 -524 49025 -212 215 -574 48989 -240 217 -526 49019 -238 217 -526 49003 -246 215 -536 49013 -220 211 -572 49003 -240 203 -548 49015 -206 215 -558 49023 -204 217 -564 49003 -218 211 -544 49041 -202 217 -562 49017 -206 217 -554 49007 -224 211 -566 48989 -236 201 -572 48993 -238 217 -562 48987 -244 217 -544 48999 -218 211 -576 48993 -240 217 -562 48973 -244 205 -550 49021 -214 215 -570 48989 -246 179 -578 48991 -246 215 -544 48999 -246 217 -540 48995 -248 215 -542 48993 -248 211 -528 49007 -242 207 -550 49015 -212 209 -558 49015 -246 179 -578 48977 -238 203 -574 48999 -246 213 -528 49001 -246 193 -580 49007 -202 217 -562 48997 -238 217 -530 49029 -238 217 -524 48997 -244 185 -570 49007 -236 219 -560 48979 -238 217 -562 48981 -244 217 -550 49009 -238 217 -528 49019 -238 217 -528 49023 -206 215 -558 49001 -240 217 -530 49003 -246 215 -536 49029 -212 215 -540 49049 -212 191 -586 48975 -242 207 -550 49017 -206 237 -542 49017 -206 205 -574 49013 -198 229 -564 48991 -236 199 -570 48987 -238 201 -572 49001 -242 205 -548 49005 -236 219 -524 49035 -202 219 -562 49017 -198 211 -564 49025 -212 191 -582 49001 -238 217 -524 49021 -238 219 -526 49007 -238 217 -562 48985 -248 193 diff --git a/assets/resources/subghz/Jamming/Jam_433.92.sub b/assets/resources/subghz/Jamming/Jam_433.92.sub deleted file mode 100644 index 65589d4e4..000000000 --- a/assets/resources/subghz/Jamming/Jam_433.92.sub +++ /dev/null @@ -1,16 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 433920000 -Preset: FuriHalSubGhzPresetOok650Async -Protocol: RAW -RAW_Data: -614 2689 -200 1805 -200 21705 -298 191 -636 48887 -278 215 -618 48867 -310 213 -612 48873 -300 191 -638 48871 -312 183 -634 48869 -284 217 -596 48903 -272 221 -604 48901 -306 185 -626 48879 -300 207 -598 48889 -280 249 -584 48883 -302 187 -624 48909 -268 217 -594 48899 -278 251 -596 48881 -280 215 -598 48917 -252 215 -624 48905 -278 217 -588 48941 -244 215 -598 48937 -254 215 -594 48943 -232 229 -610 48907 -278 213 -600 48917 -242 255 -598 48899 -278 173 -632 48921 -244 251 -576 48927 -274 211 -598 275 -362 231 -436 131 -1192 131 -534 231 -336 65 -100 1957 -68 42797 -242 251 -584 48937 -242 213 -606 48927 -238 243 -596 48929 -242 217 -620 48891 -280 217 -598 48899 -280 215 -622 48891 -252 243 -594 48905 -276 213 -606 48931 -242 219 -626 48893 -252 217 -628 48885 -278 217 -626 48881 -278 215 -630 48893 -266 193 -634 48895 -254 221 -636 48901 -272 211 -598 48895 -274 251 -574 48917 -278 211 -600 48913 -278 215 -598 48891 -264 231 -612 48913 -274 209 -600 48925 -240 243 -592 48931 -238 243 -588 48899 -278 215 -586 48949 -238 243 -590 48917 -242 243 -596 48925 -222 259 -596 48923 -232 231 -610 48923 -244 251 -588 48919 -240 243 -590 48909 -278 213 -598 48941 -242 213 -602 48913 -242 253 -596 48909 -274 211 -600 48919 -240 245 -596 48905 -254 245 -594 48913 -274 211 -600 48903 -260 229 -612 48901 -274 249 -570 48915 -252 219 -624 48909 -244 251 -582 48901 -268 229 -610 48907 -280 215 -600 48911 -276 215 -580 48929 -276 215 -580 48921 -278 215 -600 48919 -232 231 -614 48899 -268 221 -604 48899 -284 229 -596 48923 -234 223 -602 48915 -278 211 -610 48899 -268 223 -602 48919 -258 225 -606 48905 -274 213 -602 48909 -276 213 -600 48911 -268 239 -586 48917 -242 251 -582 48905 -276 213 -604 48909 -274 213 -606 48905 -278 213 -612 48899 -278 215 -604 48919 -236 223 -602 48921 -276 215 -606 48887 -302 209 -596 48899 -272 255 -594 48887 -274 213 -608 48883 -312 213 -582 48891 -286 229 -596 48905 -268 219 -626 48891 -278 211 -602 48909 -274 211 -600 48903 -272 249 -572 48923 -268 201 -618 48897 -274 217 -596 48931 -274 185 -628 48887 -274 255 -594 48887 -272 247 -570 48919 -266 225 -602 48891 -274 253 -560 48901 -288 225 -602 48909 -270 211 -602 48893 -284 217 -594 48903 -284 231 -596 48895 -286 221 -600 48901 -278 211 -614 48887 -268 241 -594 48891 -304 183 -628 48903 -272 211 -602 48919 -270 211 -600 48903 -274 251 -586 48905 -274 217 -596 48889 -292 199 -614 48911 -270 211 -604 48909 -266 227 -604 48913 -274 217 -596 48917 -236 223 -602 48937 -236 223 -632 48879 -272 253 -592 48887 -274 253 -558 48909 -270 223 -600 48911 -RAW_Data: -274 215 -602 48907 -276 249 -562 48925 -274 215 -604 48901 -270 251 -568 48923 -252 215 -626 48901 -272 211 -602 48901 -270 249 -574 48913 -272 215 -622 48881 -270 223 -602 48891 -304 215 -616 48869 -286 225 -606 48885 -270 223 -630 48863 -286 217 -626 48895 -262 239 -594 48895 -270 221 -630 48885 -270 227 -608 48887 -270 217 -628 48879 -302 187 -628 48883 -270 219 -628 48883 -304 213 -610 48877 -292 197 -616 48899 -270 227 -606 48897 -270 231 -596 48915 -268 217 -592 48901 -302 215 -578 48927 -266 231 -596 48881 -286 223 -604 48879 -304 217 -596 48885 -288 223 -606 48895 -272 217 -628 48891 -272 219 -596 48907 -266 229 -608 48871 -290 225 -608 48879 -310 217 -594 48909 -266 215 -594 48909 -272 215 -628 48867 -312 217 -594 48909 -266 223 -604 48897 -264 237 -592 48913 -264 223 -608 48887 -290 219 -602 48905 -264 235 -588 48911 -262 217 -628 48879 -264 221 -634 48877 -278 251 -590 48895 -270 211 -600 48919 -270 211 -600 48915 -280 217 -596 48893 -264 221 -634 48909 -246 253 -590 48883 -270 211 -628 48889 -278 251 -590 48909 -262 215 -592 48925 -256 215 -626 48899 -254 213 -628 48907 -248 253 -592 48881 -280 217 -626 48889 -270 211 -596 48933 -262 223 -602 48917 -272 181 -630 48913 -274 217 -582 48931 -272 209 -596 48919 -276 217 -598 48901 -266 237 -584 48897 -268 241 -592 48909 -274 215 -616 48891 -280 217 -582 48909 -262 229 -612 48901 -260 217 -628 48907 -262 223 -602 48895 -270 211 -628 48915 -242 211 -632 48891 -280 219 -596 48895 -278 217 -598 48915 -256 215 -624 48897 -278 211 -600 48923 -280 219 -596 48883 -286 213 -628 48887 -276 213 -600 48923 -272 181 -630 48885 -308 181 -632 48907 -280 217 -594 48907 -264 223 -604 48873 -294 235 -588 48883 -290 225 -606 48903 -264 237 -594 48893 -300 205 -596 48905 -264 227 -608 48893 -300 205 -596 48915 -264 223 -606 48899 -276 213 -602 48903 -266 241 -592 48911 -276 217 -580 48923 -264 225 -606 48901 -280 217 -596 48907 -270 211 -598 48935 -262 221 -602 48899 -274 217 -612 48915 -246 249 -572 48911 -260 217 -630 48903 -274 215 -580 48933 -282 217 -594 48915 -260 189 -632 48923 -230 213 -626 48903 -260 217 -628 48913 -260 225 -596 48909 -280 219 -594 48905 -260 227 -596 48899 -280 217 -596 48917 -274 215 -612 48895 -280 217 -584 48921 -264 225 -608 48903 -262 227 -604 48925 -266 199 -612 48901 -264 227 -606 48907 -262 225 -606 48925 -258 189 -630 48909 -262 223 -602 48915 -262 221 -602 48919 -260 219 -602 48911 -260 223 -604 48899 -262 229 -608 48909 -262 223 -604 48899 -272 215 -610 48929 -244 211 -598 48921 -280 217 -596 48905 -256 213 -624 48921 -276 219 -588 48907 -RAW_Data: -260 215 -628 48891 -274 215 -614 48887 -280 215 -610 48917 -280 217 -576 48927 -254 215 -594 48915 -268 213 -628 48915 -276 215 -584 48907 -266 239 -590 48917 -258 219 -596 48957 -240 217 -588 48931 -268 203 -614 48919 -274 215 -580 48941 -244 215 -586 48947 -230 225 -596 48949 -230 223 -604 48963 -240 213 -600 48923 -244 251 -572 48953 -230 231 -598 48927 -238 219 -596 48933 -264 193 -630 48915 -266 185 -628 48925 -242 217 -628 48899 -268 201 -618 48933 -234 213 -630 48901 -276 217 -596 48907 -264 231 -596 48917 -276 217 -594 48901 -266 193 -636 48917 -230 225 -634 48903 -274 217 -594 48929 -234 213 -630 48925 -234 211 -630 48907 -276 217 -594 48899 -262 227 -606 48923 -264 183 -630 48907 -264 215 -596 48947 -240 215 -598 48935 -232 217 -626 48921 -240 253 -594 48913 -234 213 -628 48947 -242 217 -596 48921 -258 229 -598 48921 -244 215 -624 48935 -238 203 -616 48927 -230 223 -594 48953 -238 217 -622 48929 -232 229 -602 48945 -240 215 -598 48927 -234 233 -608 48919 -230 217 -626 48933 -240 217 -596 48939 -232 223 -628 48925 -230 221 -606 48951 -240 217 -596 48937 -234 231 -606 48939 -228 231 -596 48931 -230 215 -626 48935 -238 213 -614 48921 -232 211 -628 48949 -228 217 -594 48947 -228 233 -596 48961 -198 227 -598 48947 -244 207 -622 48931 -244 207 -618 48951 -210 247 -590 48939 -246 213 -598 48931 -244 209 -620 48957 -210 211 -622 48941 -244 205 -612 48939 -246 213 -592 48963 -210 211 -622 48955 -210 211 -622 48935 -242 207 -616 48937 -242 207 -612 48927 -246 207 -618 48959 -212 209 -620 48937 -242 207 -614 48945 -212 247 -590 48935 -244 207 -618 48935 -246 213 -598 48937 -246 215 -598 48939 -246 215 -602 48941 -248 213 -594 48965 -212 209 -622 48935 -248 213 -596 48955 -212 211 -622 48951 -210 247 -592 48937 -242 207 -618 48955 -204 203 -638 48943 -240 205 -608 48931 -244 217 -580 48973 -212 245 -588 48959 -210 211 -622 48933 -246 215 -600 48933 -244 209 -620 48951 -206 237 -608 48945 -206 237 -608 48945 -212 247 -592 48957 -210 211 -622 48955 -210 211 -624 48945 -212 247 -592 48955 -210 211 -624 48939 -244 207 -614 48931 -248 213 -598 48945 -248 213 -596 48931 -246 215 -602 48937 -242 207 -620 48953 -210 211 -622 48947 -242 203 -612 48943 -242 205 -610 48951 -212 215 -608 48957 -212 247 -590 48955 -210 211 -624 48951 -212 211 -626 48961 -212 209 -618 48927 -246 207 -618 48943 -246 213 -594 48933 -246 207 -618 48957 -214 217 -602 48961 -210 211 -626 48929 -244 209 -618 48929 -244 207 -618 48933 -244 207 -616 48947 -210 247 -592 48959 -210 209 -622 48931 -244 207 -618 48939 -242 205 -616 48949 -210 211 -624 48941 -RAW_Data: -246 213 -596 48957 -212 211 -622 48957 -210 211 -622 48937 -244 207 -616 48947 -212 211 -622 48941 -246 215 -598 48931 -244 209 -618 48955 -212 209 -620 48953 -212 209 -624 48937 -242 207 -618 48937 -242 205 -614 48955 -212 209 -622 48941 -242 207 -612 48937 -246 213 -596 48955 -210 211 -624 48955 -212 211 -622 48945 -248 211 -594 48943 -242 207 -612 48945 -212 247 -592 48939 -244 205 -614 48941 -246 213 -594 48963 -214 215 -602 48967 -210 209 -622 48951 -212 209 -624 48937 -244 207 -584 48989 -212 209 -618 48935 -244 207 -616 48941 -248 211 -592 48963 -214 215 -604 48965 -214 215 -606 48935 -244 209 -618 48957 -212 211 -618 48955 -212 211 -622 48933 -244 207 -616 48929 -244 209 -616 48957 -212 209 -622 48953 -212 211 -622 48945 -242 205 -610 48933 -236 199 -634 48949 -210 211 -622 48943 -242 205 -612 48951 -212 209 -622 48945 -242 205 -612 48953 -212 209 -622 48933 -248 215 -598 48943 -242 207 -614 48925 -244 209 -618 48947 -212 247 -590 48955 -210 213 -626 48959 -210 209 -618 48961 -212 217 -604 48953 -212 247 -592 48937 -244 207 -614 48945 -242 205 -578 48967 -242 207 -614 48933 -244 207 -584 48977 -208 237 -576 48989 -214 217 -602 48953 -248 211 -592 48945 -212 249 -592 48963 -212 209 -616 48949 -212 247 -590 48951 -206 237 -578 48963 -244 207 -620 48953 -212 209 -620 48937 -244 207 -614 48941 -242 205 -610 48939 -242 205 -614 48955 -212 211 -622 48951 -212 209 -624 48939 -242 207 -612 48929 -244 207 -618 48929 -248 215 -600 48945 -242 205 -614 48945 -240 205 -612 48951 -198 227 -596 48967 -242 203 -612 48941 -212 249 -590 48949 -206 239 -612 48945 -242 203 -610 48947 -206 239 -610 48945 -210 249 -588 48941 -242 207 -614 48953 -212 211 -624 48947 -212 247 -590 48937 -246 215 -580 48959 -244 217 -578 48951 -242 217 -584 48983 -212 191 -616 48959 -238 217 -596 48939 -242 215 -620 48927 -244 207 -616 48941 -244 217 -576 48961 -242 205 -616 48923 -238 203 -606 48967 -246 215 -578 48947 -244 209 -618 48957 -212 209 -622 48943 -212 251 -574 48951 -244 215 -614 48949 -214 215 -604 48947 -246 213 -598 48941 -246 213 -598 48945 -248 211 -596 48959 -212 209 -622 48945 -210 251 -574 48977 -212 215 -606 48937 -244 209 -618 48955 -212 209 -622 48947 -234 197 -602 48949 -244 207 -618 48947 -242 203 -610 48939 -234 199 -602 48971 -234 195 -600 48953 -238 201 -636 48949 -206 203 -640 48939 -246 211 -592 48933 -242 209 -620 48945 -246 211 -592 48955 -212 209 -626 48957 -212 215 -606 48943 -246 213 -602 48959 -210 211 -624 48955 -206 237 -608 48931 -242 207 -616 48933 -246 213 -600 48929 -244 209 -620 48941 -246 215 -578 48965 -RAW_Data: -246 215 -576 48975 -210 209 -622 48933 -236 201 -604 48963 -242 207 -616 48931 -242 207 -618 48941 -240 205 -614 48923 -238 203 -638 48947 -204 239 -544 48995 -246 213 -532 49029 -214 215 -538 49025 -212 211 -560 49001 -248 213 -532 49009 -244 217 -544 48995 -238 217 -528 49027 -206 251 -524 49001 -246 215 -534 49027 -212 217 -538 49031 -210 211 -556 49007 -244 217 -544 48997 -238 219 -526 49001 -244 215 -552 48989 -246 215 -534 49035 -214 191 -582 48995 -238 219 -526 49005 -242 217 -548 49007 -212 251 -508 49011 -244 215 -552 48997 -246 185 -562 49013 -240 217 -526 49029 -208 217 -554 48989 -244 215 -552 49011 -210 221 -556 48997 -238 217 -528 49017 -246 215 -530 49035 -208 215 -552 49017 -212 215 -540 49013 -236 219 -560 48979 -238 217 -564 48993 -238 219 -592 48937 -244 215 -600 48937 -246 215 -602 48965 -210 209 -622 48953 -212 211 -622 48939 -242 205 -616 48933 -244 205 -616 48941 -244 217 -576 48951 -248 215 -600 48947 -246 215 -576 48973 -212 215 -608 48965 -206 217 -622 48937 -246 213 -598 48935 -248 215 -600 48959 -210 211 -622 48951 -242 203 -610 48941 -248 211 -592 48933 -246 215 -600 48951 -246 213 -596 48937 -244 215 -582 48953 -244 215 -584 48963 -248 213 -596 48947 -246 211 -594 48951 -246 211 -594 48953 -242 203 -610 48941 -242 203 -610 48951 -212 209 -622 48943 -242 205 -614 48953 -212 209 -620 48959 -206 203 -606 48983 -212 215 -606 48955 -212 251 -572 48975 -212 191 -614 48957 -242 185 -636 48943 -246 215 -612 48941 -210 215 -608 48951 -246 215 -578 48955 -244 217 -614 48921 -244 215 -618 48929 -246 215 -612 48925 -246 215 -596 48947 -246 215 -576 48951 -244 207 -620 48949 -210 211 -624 48949 -210 253 -572 48945 -242 215 -620 48955 -202 217 -628 48947 -202 219 -630 48925 -244 215 -614 48939 -248 215 -576 48971 -206 215 -624 48943 -246 213 -592 48931 -248 215 -602 48937 -244 215 -616 48929 -246 213 -598 253 -572 48965 -212 211 -628 48959 -212 217 -602 48945 -246 215 -598 48951 -210 247 -592 48959 -212 209 -624 48935 -248 213 -596 48937 -242 209 -616 48953 -212 217 -606 48945 -248 213 -600 48963 -214 217 -602 48965 -212 215 -606 48965 -214 215 -604 48957 -210 247 -592 48955 -212 211 -622 48943 -246 213 -596 48953 -212 215 -608 48959 -212 251 -572 48971 -210 211 -624 48931 -246 215 -602 48949 -246 213 -594 48939 -246 215 -598 48955 -206 253 -590 48955 -214 215 -604 48949 -244 205 -614 48945 -246 211 -592 48939 -246 213 -598 48941 -244 205 -616 48939 -246 213 -596 48937 -246 215 -612 48937 -240 217 -590 48937 -246 215 -600 48959 -210 211 -622 48955 -212 215 -606 48949 -246 215 -614 48929 -246 213 -RAW_Data: -596 48959 -210 211 -620 48957 -210 211 -622 48929 -246 215 -602 48935 -244 207 -622 48957 -214 215 -604 48953 -210 247 -592 48959 -212 215 -606 48967 -214 215 -606 48947 -242 205 -616 48947 -246 175 -628 48933 -246 193 -612 48973 -206 215 -622 48939 -246 215 -578 48961 -242 205 -614 48949 -212 211 -622 48957 -206 203 -640 48935 -242 205 -614 48955 -206 203 -638 48923 -246 213 -602 48951 -246 211 -598 48953 -210 211 -626 48961 -212 215 -604 48945 -246 213 -598 48937 -238 201 -604 48975 -206 239 -610 48945 -240 203 -610 48935 -242 205 -616 48951 -206 205 -640 48943 -210 211 -626 48935 -248 213 -598 48935 -244 215 -586 48979 -212 211 -622 48929 -244 209 -620 48947 -212 215 -608 48953 -246 215 -580 48957 -238 217 -596 48963 -206 251 -590 48947 -210 253 -572 48939 -242 215 -624 48947 -206 253 -588 48933 -246 215 -614 48925 -244 213 -602 48933 -242 207 -622 48941 -240 203 -616 48923 -232 223 -630 48915 -230 225 -630 48919 -236 199 -638 48941 -240 201 -614 48941 -246 211 -596 48925 -242 209 -626 48929 -242 209 -620 48929 -246 213 -604 48947 -246 211 -598 48925 -238 235 -610 48921 -244 207 -622 48937 -240 205 -620 48933 -242 205 -618 48931 -242 207 -618 48921 -244 215 -608 48953 -244 213 -596 48929 -244 209 -620 48939 -244 213 -600 48949 -246 211 -594 48941 -240 207 -618 48939 -240 207 -614 48927 -244 207 -620 48939 -242 205 -616 48941 -240 205 -614 48943 -242 203 -612 48931 -242 209 -618 48951 -212 209 -622 48937 -246 213 -598 48955 -240 203 -612 48917 -238 235 -608 48949 -210 211 -624 48951 -210 211 -624 48959 -212 209 -622 48935 -244 207 -616 48931 -244 207 -616 48949 -212 215 -606 48971 -212 215 -606 48963 -212 217 -606 48969 -210 211 -622 48943 -248 211 -592 48959 -212 215 -606 48963 -212 211 -622 48935 -244 207 -616 48925 -244 209 -620 48951 -234 195 -596 48963 -246 213 -594 48945 -246 213 -594 48949 -246 213 -594 48961 -212 215 -602 48939 -242 217 -618 48933 -242 207 -616 48953 -210 209 -620 48945 -246 211 -592 48955 -212 215 -608 48949 -242 207 -616 48945 -248 211 -592 48933 -246 215 -602 48939 -246 215 -600 48937 -246 215 -598 48949 -248 215 -576 48969 -212 211 -622 48961 -212 209 -622 48935 -246 213 -596 48939 -244 207 -616 48957 -206 203 -606 48985 -212 209 -620 48939 -244 205 -612 48955 -212 217 -602 48943 -246 215 -580 48955 -246 215 -600 48957 -212 215 -606 48973 -212 209 -620 48933 -244 217 -582 48953 -248 215 -600 48943 -246 215 -598 48951 -240 203 -612 48933 -236 199 -632 48937 -242 205 -614 48927 -244 217 -582 48947 -242 211 -622 48945 -246 217 -574 48947 -242 217 -616 48933 -246 215 -578 48965 -248 215 -RAW_Data: -574 48957 -246 215 -580 48963 -246 211 -592 48939 -246 215 -582 48973 -210 211 -626 48931 -246 213 -602 48941 -242 207 -620 48939 -246 213 -594 48957 -210 211 -624 48949 -240 205 -610 48927 -242 209 -618 48953 -212 215 -606 48947 -242 209 -616 48941 -244 203 -610 48951 -212 209 -622 48953 -212 215 -608 48961 -212 247 -590 48947 -212 221 -624 48931 -236 201 -602 48981 -202 253 -562 48967 -242 205 -614 48935 -238 211 -600 48957 -234 197 -598 48983 -212 211 -620 48937 -248 213 -594 48949 -248 213 -590 48939 -244 207 -616 48941 -242 205 -610 48939 -238 217 -596 48961 -198 227 -596 48981 -202 219 -596 48969 -210 253 -572 48955 -246 215 -580 48959 -248 213 -596 48945 -248 211 -596 48939 -244 207 -614 48957 -212 209 -620 48929 -248 215 -600 48957 -206 237 -610 48945 -206 237 -608 48949 -206 237 -576 48957 -246 207 -618 48959 -206 203 -604 48971 -212 247 -592 48955 -214 217 -604 48947 -236 217 -588 48969 -200 231 -596 48957 -238 217 -594 48963 -206 253 -592 48937 -238 217 -596 48961 -206 215 -600 48979 -212 247 -590 48953 -212 215 -606 48969 -206 215 -622 48933 -248 215 -598 48939 -246 215 -580 48977 -212 217 -606 48963 -212 215 -606 48955 -212 249 -594 48967 -208 217 -584 48967 -240 217 -594 48953 -208 239 -576 48975 -242 205 -576 48989 -206 217 -588 48979 -212 217 -606 48957 -238 219 -594 48941 -236 219 -596 48959 -202 253 -596 48939 -240 217 -596 48961 -214 215 -606 48959 -206 251 -592 48963 -202 217 -598 48981 -194 217 -626 48961 -216 217 -602 48961 -202 211 -600 48979 -208 215 -602 48985 -214 217 -602 48945 -240 217 -594 48945 -238 215 -600 48939 -238 201 -604 48963 -248 215 -596 48949 -212 249 -592 48951 -214 215 -608 48969 -204 217 -596 48987 -202 219 -594 48969 -212 249 -588 48933 -246 207 -616 48937 -250 213 -594 48963 -214 217 -602 48945 -244 217 -580 48981 -202 219 -596 48959 -242 207 -614 48935 -244 217 -578 48977 -212 191 -650 48933 -244 217 -576 48965 -212 247 -592 48951 -240 205 -610 48947 -210 211 -626 48941 -244 205 -616 48951 -212 209 -622 48939 -242 205 -616 48929 -244 207 -618 48923 -238 203 -638 48947 -210 211 -622 48931 -238 203 -636 48939 -242 203 -612 48945 -232 197 -600 48943 -238 235 -610 48931 -246 213 -598 48927 -244 217 -606 48951 -246 213 -596 48933 -244 215 -620 48925 -246 213 -602 48947 -246 211 -594 48935 -244 207 -620 48947 -248 175 -628 48957 -210 209 -622 48929 -230 225 -596 48971 -206 239 -610 48945 -212 211 -624 48933 -246 215 -600 48937 -246 215 -600 48955 -212 215 -610 48945 -246 215 -600 48933 -244 209 -620 48929 -236 203 -638 48951 -212 209 -620 48935 -246 215 -598 48959 -212 209 -RAW_Data: -622 48957 -206 205 -640 48931 -236 199 -634 48941 -242 203 -612 48953 -204 203 -638 48945 -212 209 -626 48959 -186 211 -634 48961 -228 181 -628 48953 -242 205 -612 48927 -244 209 -620 48941 -242 205 -612 48935 -244 205 -614 48925 -248 213 -604 48949 -246 217 -576 48947 -238 201 -636 48925 -244 209 -618 48935 -246 213 -598 48935 -242 217 -584 48961 -248 213 -598 48939 -244 207 -614 48955 -206 235 -576 48971 -246 213 -594 48959 -212 209 -622 48947 -210 253 -572 48975 -212 211 -620 48955 -210 209 -622 48939 -244 205 -616 48953 -212 209 -622 48947 -210 247 -590 48947 -248 213 -592 48945 -242 205 -614 48943 -246 211 -592 48951 -242 203 -612 48939 -248 211 -592 48949 -210 249 -590 48965 -212 209 -618 48951 -212 213 -622 48939 -246 215 -594 48937 -248 215 -600 48943 -242 207 -614 48951 -212 211 -624 48945 -244 203 -610 48937 -244 205 -610 48945 -242 205 -610 48947 -206 237 -608 48935 -244 205 -614 48951 -212 211 -622 48957 -212 211 -622 48951 -212 211 -622 48937 -248 213 -596 48961 -212 211 -622 48939 -248 213 -596 48935 -244 207 -616 48945 -212 247 -594 48939 -244 205 -612 48959 -210 211 -618 48937 -244 207 -582 48971 -246 213 -596 48947 -242 205 -612 48927 -244 209 -618 48937 -242 205 -614 48931 -244 207 -616 48941 -242 205 -612 48955 -212 211 -556 48997 -244 207 -550 49019 -212 211 -556 49001 -244 207 -548 48997 -244 209 -550 49013 -212 213 -558 49011 -242 205 -544 49021 -212 209 -556 49011 -242 205 -544 48999 -244 207 -548 49001 -242 207 -548 49025 -212 209 -552 49001 -248 215 -530 49005 -244 207 -548 49023 -212 211 -552 49009 -246 213 -528 49013 -248 211 -528 49019 -212 211 -558 49013 -212 251 -508 49013 -248 215 -600 48935 -246 207 -618 48955 -212 211 -622 48941 -242 205 -546 48995 -244 207 -550 49019 -212 211 -556 49007 -248 213 -596 48931 -244 209 -586 48961 -246 207 -550 49001 -248 215 -596 48949 -246 213 -594 48939 -248 193 -610 48939 -248 213 -600 48941 -244 209 -616 48939 -242 205 -616 48947 -206 237 -610 48935 -244 205 -546 48993 -246 209 -552 49019 -212 209 -622 48955 -212 209 -622 48953 -210 213 -624 48957 -212 211 -622 48937 -242 207 -612 48951 -212 211 -624 48945 -244 203 -610 48935 -242 207 -614 48939 -248 213 -594 48957 -212 211 -622 48959 -214 215 -604 48959 -212 215 -606 48943 -246 193 -612 48967 -204 253 -592 48941 -244 217 -578 48971 -212 211 -624 48931 -246 207 -618 48953 -214 215 -606 48969 -212 209 -620 48933 -242 209 -616 48927 -246 209 -618 48939 -244 205 -610 48957 -212 209 -620 48941 -242 205 -580 48975 -246 213 -592 48939 -242 207 -584 48969 -244 207 -612 48957 -212 209 -618 48941 -244 205 -RAW_Data: -614 48951 -210 211 -624 48937 -242 207 -612 48953 -212 211 -622 48941 -242 207 -614 48929 -246 207 -616 48953 -212 211 -622 48957 -212 209 -618 48953 -212 211 -622 48933 -248 191 -612 48957 -240 217 -596 48947 -244 217 -576 48955 -248 213 -598 48967 -214 215 -604 48953 -212 247 -588 48935 -244 217 -614 48929 -246 215 -580 48971 -210 221 -624 48953 -204 217 -594 48977 -202 253 -594 48935 -246 193 -610 48967 -210 215 -608 48963 -210 213 -624 48961 -210 211 -620 48959 -212 209 -620 48947 -212 211 -628 48951 -212 211 -624 48935 -248 213 -598 48965 -214 193 -612 48975 -206 215 -626 48941 -246 213 -594 48939 -242 207 -616 48939 -246 215 -578 48955 -246 215 -596 48965 -212 211 -620 48935 -246 215 -596 48939 -244 207 -616 48929 -244 209 -616 48957 -212 209 -622 48935 -246 215 -598 48941 -248 213 -594 48955 -242 203 -610 48927 -244 207 -616 48957 -212 209 -622 48929 -246 217 -602 48959 -212 211 -622 48959 -212 211 -618 48951 -212 211 -622 48941 -242 207 -614 48953 -212 209 -624 48957 -212 209 -620 48931 -246 193 -610 48979 -214 215 -602 48961 -212 211 -556 49005 -246 215 -528 49021 -212 211 -556 49001 -248 215 -534 49011 -248 213 -528 49015 -248 213 -526 49021 -212 211 -558 49011 -212 249 -522 49007 -244 207 -548 49007 -212 249 -524 49021 -212 211 -558 49021 -212 211 -558 48999 -248 215 -530 49025 -214 215 -538 49013 -248 213 -534 49003 -244 207 -550 49015 -212 211 -558 49027 -214 193 -580 49011 -202 217 -564 48989 -236 217 -556 49011 -194 219 -558 49029 -208 217 -556 48999 -238 217 -530 49035 -208 215 -556 48999 -246 215 -546 49009 -208 215 -556 49015 -238 217 -524 49007 -236 217 -562 48983 -236 219 -562 49007 -206 217 -554 49021 -212 191 -582 49009 -214 215 -540 49007 -248 215 -534 49017 -246 217 -542 48987 -248 213 -532 49019 -212 215 -542 49017 -246 215 -548 48999 -246 217 -508 49013 -246 193 -546 49043 -208 217 -554 48993 -244 217 -548 48995 -246 215 -546 49015 -214 191 -582 48989 -238 217 -530 49013 -244 215 -548 49011 -212 191 -582 49011 -206 251 -524 49019 -210 217 -574 48987 -246 215 -544 48985 -248 191 -578 48979 -244 215 -552 49011 -212 191 -586 49009 -208 251 -522 49017 -210 215 -578 48981 -244 185 -566 49029 -208 215 -554 49011 -212 211 -560 48997 -246 193 -578 49001 -212 215 -576 48997 -212 211 -558 49027 -204 217 -562 48993 -246 215 -546 49015 -212 217 -538 49027 -212 217 -540 49019 -244 217 -542 48983 -248 215 -534 49013 -244 217 -546 48999 -240 217 -524 49005 -244 217 -548 49003 -240 217 -526 49015 -242 217 -522 49031 -208 215 -556 48989 -236 217 -564 48993 -238 217 -528 49005 -242 217 -552 49021 -208 215 -RAW_Data: -554 49021 -208 215 -554 49007 -240 217 -526 49005 -244 217 -546 49011 -212 215 -542 49015 -244 217 -578 48967 -242 205 -612 48935 -236 197 -634 48933 -244 205 -616 48921 -238 203 -638 48925 -244 207 -618 48947 -242 203 -612 48937 -234 197 -634 48947 -204 205 -640 48937 -242 203 -614 48933 -234 201 -636 48923 -238 201 -636 48919 -238 203 -640 48943 -242 201 -610 48945 -240 203 -544 48987 -246 207 -554 49003 -244 205 -616 48927 -238 203 -606 48953 -236 203 -636 48925 -238 201 -638 48943 -206 237 -542 49017 -212 209 -558 49017 -212 211 -560 48995 -244 209 -618 48925 -238 201 -640 48927 -246 213 -600 48933 -242 209 -620 48955 -210 209 -624 48949 -240 205 -610 48931 -246 213 -598 48949 -246 213 -594 48947 -246 211 -594 48959 -212 215 -608 48959 -210 211 -626 48945 -242 205 -614 48949 -206 237 -610 48949 -210 209 -622 48931 -244 207 -622 48947 -242 203 -612 48937 -242 203 -614 48933 -242 207 -616 48945 -246 175 -626 48955 -246 175 -626 48941 -246 211 -596 48939 -244 207 -618 48935 -242 207 -616 48953 -210 211 -620 48929 -244 207 -620 48955 -212 217 -604 48953 -248 211 -594 48937 -244 207 -620 48923 -244 209 -618 48929 -244 209 -620 48925 -244 209 -620 48953 -210 211 -624 48951 -210 211 -626 48937 -246 213 -598 48963 -208 215 -620 48923 -242 215 -606 48933 -272 179 -632 48943 -236 219 -594 48933 -242 217 -584 48957 -248 213 -602 48949 -248 211 -594 48961 -214 191 -614 48959 -246 215 -578 48951 -246 193 -612 48975 -208 215 -622 48927 -244 215 -618 48947 -210 211 -620 48933 -246 215 -602 48935 -244 207 -620 48949 -246 177 -626 48951 -212 211 -626 48933 -244 217 -616 48917 -246 215 -604 48961 -210 211 -624 48951 -212 209 -626 48925 -246 215 -602 48963 -246 175 -626 48925 -244 217 -604 48961 -246 175 -624 48927 -244 215 -606 48939 -248 191 -612 48979 -202 217 -598 48961 -246 215 -578 48969 -212 211 -628 48927 -246 215 -604 48953 -248 175 -626 48931 -244 209 -620 48933 -246 213 -600 48967 -214 215 -602 48935 -246 207 -620 48955 -212 209 -622 48937 -246 215 -580 48963 -242 205 -582 48979 -212 215 -608 48949 -246 215 -598 48943 -248 215 -594 48969 -216 215 -602 48941 -244 207 -578 48983 -214 213 -588 48987 -198 227 -594 48969 -206 253 -592 48939 -240 217 -596 48957 -212 249 -590 48959 -214 217 -602 48949 -238 217 -588 48959 -238 217 -590 48945 -244 217 -580 48961 -240 217 -596 48955 -214 247 -590 48959 -204 217 -632 48923 -238 217 -588 48957 -236 217 -588 48963 -226 221 -600 48957 -234 197 -600 48975 -210 209 -626 48943 -246 213 -594 48957 -206 239 -608 48925 -236 203 -604 48977 -210 211 -624 48929 -248 213 -602 48943 -244 215 -RAW_Data: -582 48963 -248 213 -594 48963 -210 211 diff --git a/assets/resources/subghz/Jamming/Jam_438.90.sub b/assets/resources/subghz/Jamming/Jam_438.90.sub deleted file mode 100644 index e9d04dbc5..000000000 --- a/assets/resources/subghz/Jamming/Jam_438.90.sub +++ /dev/null @@ -1,16 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 438900000 -Preset: FuriHalSubGhzPresetOok650Async -Protocol: RAW -RAW_Data: 49165 -230 189 -400 1566 -3756 12839 -308 143 -612 48965 -242 207 -552 49019 -214 213 -538 49015 -246 215 -548 49009 -212 215 -540 49015 -246 213 -530 49003 -246 193 -580 48997 -240 219 -522 49023 -206 215 -556 49007 -244 217 -544 49009 -212 211 -556 48995 -244 209 -554 49005 -246 213 -528 49025 -206 205 -574 49011 -212 211 -560 49021 -212 209 -556 48999 -220 211 -568 49021 -232 193 -566 48983 -226 211 -564 49023 -210 211 -558 49019 -214 215 -540 49011 -248 213 -532 49005 -246 213 -534 49009 -218 213 -568 48999 -228 221 -538 49027 -240 203 -544 48991 -242 253 -520 49011 -216 211 -572 48981 -236 219 -562 48995 -242 181 -558 48995 -244 215 -552 49007 -224 211 -566 48979 -232 225 -564 48995 -244 215 -554 48999 -212 215 -540 49029 -202 217 -562 48995 -238 217 -562 49009 -224 181 -564 49021 -234 195 -568 48997 -218 213 -576 48995 -224 211 -566 48985 -244 207 -552 48991 -248 213 -536 49029 -212 215 -540 49023 -248 179 -578 48993 -246 213 -524 49019 -240 217 -526 49023 -218 211 -540 49029 -208 215 -558 49013 -246 177 -560 49021 -212 215 -540 49011 -246 215 -548 49007 -246 175 -560 49005 -224 211 -566 49013 -234 195 -564 49001 -248 175 -562 48997 -248 215 -534 49007 -246 215 -550 49007 -222 181 -600 48987 -234 229 -538 48989 -238 217 -564 48975 -246 215 -538 49027 -212 217 -538 49027 -212 211 -558 49005 -246 215 -546 48987 -246 215 -534 48999 -246 193 -580 48993 -224 211 -566 48989 -228 221 -538 49013 -228 221 -540 49009 -228 215 -562 48999 -236 199 -570 48989 -242 209 -554 48991 -246 209 -552 48997 -246 215 -548 48985 -244 217 -548 48991 -220 243 -566 48985 -234 199 -566 49007 -212 215 -540 49031 -248 213 -534 49003 -212 211 -562 48999 -220 211 -568 49003 -228 219 -540 49015 -242 207 -546 49005 -218 213 -544 49025 -222 211 -566 48995 -244 207 -550 49021 -214 217 -536 49017 -238 219 -528 48999 -220 213 -566 49013 -228 191 -594 48969 -252 181 -566 49027 -234 195 -566 48987 -246 215 -546 48991 -218 213 -568 48999 -230 223 -562 48981 -248 215 -534 49031 -194 211 -564 49019 -242 205 -544 48999 -232 211 -564 49001 -240 205 -544 48993 -248 215 -536 49009 -240 217 -530 49017 -222 211 -566 48995 -248 215 -528 49007 -248 215 -544 49015 -192 211 -564 49031 -206 203 -572 49003 -212 251 -508 49029 -212 253 -506 49009 -242 217 -552 49019 -208 253 -556 48979 -216 211 -540 49025 -240 219 -522 49001 -226 211 -566 49023 -210 209 -556 49003 -244 215 -548 48987 -244 217 -548 49007 -212 211 -558 48999 -244 217 -548 48993 -238 217 -530 49019 -240 181 -564 49031 -198 227 -566 49009 -212 209 -554 49013 -246 217 -540 49007 -212 209 -556 49019 -234 -RAW_Data: 193 -566 48989 -242 207 -552 49011 -212 213 -558 49005 -246 193 -578 48993 -238 217 -524 49025 -202 253 -528 48999 -228 213 -562 49017 -206 203 -574 49005 -216 213 -578 48987 -240 217 -528 49005 -244 215 -550 48987 -246 215 -536 49033 -208 215 -554 49013 -206 251 -524 49015 -240 217 -524 49019 -238 217 -528 49017 -206 253 -522 49009 -248 213 -526 49027 -214 215 -538 49021 -210 253 -540 49007 -214 215 -540 49019 -224 211 -568 48989 -228 223 -528 49033 -216 211 -544 49029 -204 253 -528 49015 -206 253 -524 49005 -246 217 -510 49017 -238 217 -530 49039 -202 217 -556 49017 -202 253 -526 49023 -204 253 -526 49017 -208 215 -556 49021 -214 217 -538 49031 -212 217 -540 49021 -204 253 -526 49003 -244 217 -548 48987 -248 215 -532 49001 -248 215 -534 49031 -214 215 -538 49023 -216 213 -542 49025 -218 211 -544 49035 -194 211 -564 49021 -242 205 -546 49003 -246 217 -540 48985 -220 211 -568 49029 -196 225 -564 48997 -242 205 -548 49015 -206 217 -558 49027 -210 215 -552 49001 -240 217 -528 49007 -240 217 -530 49017 -238 219 -528 49005 -226 211 -564 49021 -214 215 -540 49009 -232 211 -564 48997 -248 215 -528 49009 -232 211 -532 49033 -212 247 -526 48999 -238 217 -530 49033 -196 223 -570 48995 -240 217 -528 49025 -228 187 -560 49025 -238 217 -528 49029 -198 225 -530 49025 -238 215 -564 48993 -206 237 -542 49003 -236 219 -528 49009 -238 253 -516 48995 -240 217 -530 49027 -204 253 -528 49011 -222 211 -566 48993 -228 221 -560 49019 -246 217 -542 48987 -214 215 -534 49015 -246 217 -544 48993 -248 213 -528 49015 -212 247 -526 49023 -214 217 -538 49017 -248 213 -528 49021 -216 211 -542 49027 -208 251 -524 49015 -218 211 -542 49017 -228 213 -560 48989 -226 211 -562 49031 -212 209 -552 48999 -244 241 -520 49005 -246 217 -540 49007 -214 217 -538 49031 -212 211 -554 49011 -216 213 -546 49013 -224 211 -564 49023 -198 225 -564 49005 -212 213 -558 48995 -220 213 -566 49003 -230 223 -528 49039 -208 251 -522 49027 -214 215 -534 49005 -246 215 -534 49023 -238 217 -528 49017 -246 177 -558 49001 -246 215 -534 49015 -246 211 -528 49025 -212 211 -556 49007 -244 217 -542 49011 -208 217 -554 48997 -244 217 -548 48991 -248 213 -532 49005 -238 217 -562 49001 -242 217 -530 48991 -238 217 -564 48997 -222 211 -536 49039 -206 203 -572 49015 -212 193 -582 48997 -238 217 -524 49031 -224 181 -564 49011 -244 209 -550 48995 -238 217 -564 48981 -238 217 -556 48985 -226 211 -564 49007 -242 205 -548 49003 -242 207 -550 49011 -208 251 -522 49027 -208 215 -556 48995 -220 211 -568 48999 -228 223 -538 49007 -228 223 -536 49015 -230 235 -528 49003 -244 207 -554 48995 -246 -RAW_Data: 215 -538 49001 -248 213 -534 49015 -246 215 -544 49005 -212 215 -542 49013 -246 215 -532 49011 -246 213 -530 49001 -244 209 -552 49015 -210 211 -558 49023 -214 215 -540 49003 -244 209 -552 49023 -210 209 -556 49021 -212 211 -554 49011 -246 213 -528 49027 -214 215 -538 49015 -246 215 -544 48981 -228 211 -562 49019 -212 215 -576 48991 -224 211 -564 49001 -242 205 -548 48987 -246 209 -554 49005 -224 211 -566 48987 -226 217 -560 48999 -244 207 -550 48993 -248 191 -578 49013 -188 213 -564 49029 -198 227 -566 48999 -218 211 -546 49013 -224 211 -564 49025 -206 203 -572 49011 -212 211 -558 49007 -242 205 -550 49019 -190 211 -566 49019 -238 215 -516 49039 -204 217 -564 49009 -238 217 -516 49019 -236 219 -528 49013 -224 211 -566 49013 -232 195 -566 48989 -246 215 -548 49011 -194 211 -564 49001 -232 225 -530 49043 -214 217 -536 49021 -222 211 -566 48993 -228 221 -562 49009 -210 211 -552 49021 -214 215 -540 49031 -212 217 -538 49037 -208 217 -554 48987 -238 217 -562 48987 -246 215 -548 48989 -244 215 -550 49015 -212 253 -544 48983 -212 211 -562 49011 -222 211 -566 49011 -206 205 -572 48991 -246 215 -548 48991 -220 211 -568 48997 -230 225 -564 49003 -212 217 -540 49015 -248 213 -530 49029 -214 191 -582 49005 -222 211 -534 49037 -198 227 -566 49011 -208 215 -554 49011 -212 215 -542 49023 -218 213 -546 49011 -244 215 -550 49005 -238 217 -528 49001 -246 215 -536 49011 -248 213 -528 49029 -214 215 -538 49029 -212 211 -556 49023 -214 215 -538 49017 -246 217 -544 48981 -244 217 -548 49005 -246 187 -566 48995 -242 205 -548 48999 -246 215 -546 48987 -244 217 -548 49019 -208 217 -554 48995 -246 215 -548 49007 -218 211 -542 49027 -238 219 -526 48999 -238 217 -562 48979 -244 215 -550 48997 -224 211 -564 49007 -228 189 -558 49021 -246 213 -530 49015 -212 251 -508 49025 -246 217 -542 48991 -248 213 -528 49021 -212 215 -540 49011 -220 213 -566 49029 -204 203 -572 49013 -214 215 -540 49015 -246 215 -546 49011 -214 217 -538 49021 -248 175 -562 48995 -246 217 -536 49007 -226 211 -564 49029 -248 179 -576 48977 -246 177 -560 49001 -238 217 -562 48999 -238 217 -528 49013 -238 217 -528 49031 -202 217 -564 48995 -236 215 -564 48985 -236 217 -562 48989 -246 217 -540 48997 -212 251 -540 48983 -242 207 -552 49013 -240 205 -546 49001 -234 199 -570 49009 -232 195 -566 49009 -204 203 -574 48995 -246 213 -534 48999 -244 217 -550 49001 -242 207 -552 49013 -210 211 -554 49011 -246 213 -528 49011 -242 205 -550 49005 -240 217 -528 49013 -246 213 -528 49007 -246 215 -548 48981 -236 219 -560 49003 -224 211 -566 48981 -244 207 -552 49025 -208 215 -554 49019 -202 -RAW_Data: 217 -564 48991 -238 217 -564 48977 -238 217 -564 49001 -238 217 -524 49029 -202 219 -564 49005 -226 179 -566 49015 -236 201 -570 48999 -238 217 -528 49003 -236 217 -556 49007 -238 217 -528 49009 -246 215 -544 48989 -274 217 -524 48983 -246 215 -534 49001 -246 207 -554 49005 -246 213 -528 49003 -246 215 -534 49025 -212 209 -556 48999 -244 207 -552 49001 -248 213 -528 49013 -246 215 -546 48987 -244 217 -548 48997 -240 217 -528 49031 -208 217 -554 49011 -210 215 -576 49005 -202 219 -562 49019 -202 253 -562 48977 -224 181 -564 49021 -246 211 -526 49013 -240 217 -528 49021 -210 215 -578 48995 -248 175 -562 49007 -246 213 -530 49009 -236 199 -570 49009 -210 211 -554 49007 -242 207 -552 49007 -248 175 -562 49007 -248 211 -530 49017 -242 205 -546 49019 -212 209 -554 49009 -234 199 -568 49013 -204 203 -574 48999 -236 199 -570 48983 -244 207 -554 49001 -244 207 -550 48991 -244 209 -554 49007 -236 197 -568 49005 -234 195 -566 49003 -240 205 -544 48993 -238 201 -572 49007 -242 203 -544 49013 -212 211 -556 48997 -244 209 -552 49015 -240 203 -544 48991 -244 243 -520 49005 -244 203 -548 48999 -242 205 -550 49019 -212 209 -556 49017 -210 211 -560 49007 -244 185 -562 49019 -238 215 -530 49019 -232 211 -566 48973 -246 193 -546 49015 -226 211 -564 48995 -246 193 -578 49007 -208 215 -554 49023 -204 217 -562 48999 -240 217 -528 49007 -246 215 -548 48985 -244 215 -550 49019 -208 215 -554 49007 -242 217 -526 49009 -240 217 -530 49011 -246 215 -546 49001 -240 217 -524 49013 -240 217 -528 49019 -240 217 -526 49027 -208 215 -554 49005 -246 215 -544 49011 -208 215 -556 48995 -226 211 -564 49007 -242 205 -548 49005 -240 217 -528 49033 -208 217 -552 49005 -240 217 -526 49007 -244 217 -546 49015 -208 217 -554 49005 -226 211 -568 48999 -212 213 -560 49019 -212 191 -584 49003 -236 219 -524 49033 -204 217 -554 49021 -202 253 -526 49011 -240 217 -526 49017 -240 219 -524 49027 -204 217 -562 48983 -226 211 -564 49033 -204 203 -572 49001 -240 217 -528 49029 -206 215 -570 48997 -238 215 -528 49003 -230 225 -562 48991 -246 215 -546 48991 -246 215 -552 48985 -244 217 -546 48993 -244 185 -564 49027 -208 215 -554 49017 -212 211 -556 48999 -244 207 -552 49011 -242 203 -546 49005 -248 211 -526 49027 -214 217 -536 49023 -240 217 -526 49011 -248 211 -530 49015 -240 217 -526 49017 -240 219 -522 49019 -224 181 -598 48997 -234 195 -566 48985 -246 191 -580 48983 -236 217 -564 48985 -244 217 -546 49003 -246 217 -540 48993 -248 215 -542 48983 -246 193 -578 48981 -244 217 -550 48989 -248 215 -532 49003 -248 213 -534 49029 -212 209 -556 49015 -248 175 -560 49017 -212 -RAW_Data: 215 -542 49009 -248 213 -536 49017 -248 215 -542 48995 -248 215 -542 49003 -222 211 -534 49035 -196 225 -536 49043 -206 203 -572 49019 -202 217 -564 49001 -212 251 -542 48999 -212 217 -542 49029 -212 211 -558 49017 -240 203 -546 49009 -248 213 -524 49011 -248 215 -508 49039 -212 217 -540 49007 -248 213 -534 49007 -244 215 -556 49003 -212 217 -540 49007 -248 215 -534 49021 -212 211 -560 49019 -214 191 -584 48989 -242 217 -552 48999 -246 217 -544 48989 -246 213 -532 49025 -208 215 -558 49021 -208 217 -554 49003 -246 217 -542 48999 -212 251 -540 48983 -248 213 -534 49011 -248 213 -528 49021 -212 215 -542 49035 -214 217 -538 49033 -214 215 -536 49033 -208 215 -556 48993 -244 215 -552 48993 -246 215 -550 49005 -208 215 -558 49001 -244 217 -548 49001 -246 217 -550 48995 -212 217 -538 49011 -246 215 -550 49009 -214 215 -540 49011 -248 213 -530 49007 -244 187 -564 49025 -208 217 -556 48995 -246 215 -550 49003 -210 215 -544 49035 -202 255 -526 48995 -244 217 -548 48991 -238 217 -530 49035 -212 215 -542 49021 -248 215 -508 49031 -212 215 -544 49011 -242 217 -550 49013 -208 215 -558 49023 -202 217 -562 49015 -202 217 -564 49003 -236 219 -528 49029 -240 181 -554 49017 -226 211 -562 48985 -242 209 -552 49013 -214 215 -542 49011 -226 211 -566 49001 -242 207 -548 49003 -246 215 -548 48991 -238 217 -530 49015 -226 213 -564 48997 -246 213 -528 48999 -248 213 -536 49011 -240 217 -530 49021 -224 211 -566 49007 -212 251 -544 48997 -204 217 -562 49009 -206 215 -570 49003 -228 195 -572 48993 -246 213 -532 49031 -208 215 -542 49007 -236 211 -566 48985 -244 207 -550 48995 -242 185 -572 49007 -238 211 -534 49007 -240 203 -572 48991 -246 193 -546 49039 -210 211 -556 49005 -244 205 -548 49011 -234 195 -566 48987 -238 201 -570 48987 -244 207 -552 48995 -244 209 -552 49015 -212 215 -576 217 -564 48989 -238 217 -530 49015 -240 217 -528 49011 -240 179 -568 49021 -234 197 -566 48981 -242 217 -552 49021 -204 217 -562 48989 -238 217 -564 48997 -242 217 -524 48995 -246 215 -536 49007 -246 215 -548 48983 -244 215 -554 49007 -248 177 -560 48995 -244 209 -552 49021 -214 215 -540 49017 -248 211 -528 49005 -246 215 -548 49005 -212 217 -542 49035 -206 215 -558 49017 -214 215 -540 49021 -240 217 -526 49013 -238 219 -528 49001 -242 217 -550 49003 -238 217 -528 49027 -200 255 -524 48999 -238 217 -528 49013 -244 217 -550 49001 -244 217 -544 49009 -214 215 -540 49005 -246 215 -534 49015 -246 211 -530 49015 -248 179 -578 48999 -246 181 -576 48983 -248 213 -532 49003 -244 215 -550 49009 -214 215 -540 49035 -214 191 -582 48991 -230 221 -560 48989 -244 207 -550 -RAW_Data: 49007 -212 249 -522 49025 -214 215 -540 49021 -212 253 -506 49047 -208 217 -552 49007 -212 217 -542 49029 -206 253 -524 49027 -210 215 -554 49007 -206 251 -528 48999 -238 217 -530 49041 -214 217 -538 49029 -214 217 -536 49013 -240 217 -530 49015 -210 253 -510 49041 -210 215 -554 49005 -224 211 -532 49043 -206 237 -542 48991 -248 217 -532 49019 -208 251 -526 49003 -246 215 -546 48997 -246 217 -510 49031 -212 249 -524 49025 -212 211 -554 49003 -244 207 -546 49013 -212 251 -508 49017 -238 219 -528 49015 -250 213 -530 49003 -248 213 -532 49033 -212 209 -552 49007 -212 249 -534 49019 -212 209 -554 49003 -246 217 -544 49017 -216 217 -534 49013 -212 249 -528 49005 -242 207 -548 48999 -244 217 -548 49011 -216 211 -540 49027 -204 211 -564 49027 -214 217 -536 49019 -240 217 -528 49023 -208 217 -558 48997 -238 217 -530 49011 -238 217 -530 49039 -208 215 -556 49003 -238 217 -530 49017 -246 217 -510 49031 -212 249 -524 48999 -248 215 -534 49017 -212 251 -508 49033 -196 211 -562 49013 -236 219 -554 49003 -228 187 -560 49027 -202 253 -526 49029 -198 225 -562 48999 -238 219 -516 49023 -236 197 -566 49003 -228 211 -530 49019 -232 211 -562 49021 -204 217 -530 49023 -230 223 -528 49029 -212 253 -506 49015 -236 219 -530 49021 -246 217 -544 49001 -208 251 -524 49015 -238 219 -528 49021 -202 255 -518 49009 -234 199 -566 48991 -236 217 -564 49013 -202 219 -562 49005 -202 255 -526 49023 -214 193 -578 49001 -228 189 -558 49035 -202 211 -566 49017 -208 215 -568 48985 -246 207 -552 49005 -240 181 -566 49003 -248 193 -546 49025 -226 191 -556 49035 -202 253 -528 49019 -200 225 -562 48987 -244 209 -552 49003 -242 207 -546 49007 -246 185 -560 49023 -194 217 -558 49031 -202 217 -554 49025 -206 203 -572 48991 -228 215 -560 49029 -238 215 -550 48987 -206 237 -540 48999 -228 219 -538 49025 -240 219 -526 49023 -194 223 -538 49031 -206 251 -528 49001 -228 221 -540 49037 -208 215 -544 49023 -232 197 -564 49007 -238 217 -518 49005 -238 201 -574 49001 -226 213 -562 48993 -232 211 -568 48987 -240 181 -564 49011 -244 217 -548 49013 -202 217 -554 49009 -238 217 -528 49017 -240 217 -528 49025 -212 211 -558 48997 -244 209 -550 49043 -210 215 -554 48989 -212 251 -508 49025 -212 251 -508 49039 -208 215 -558 49021 -214 217 -536 49029 -212 211 -556 49009 -212 249 -526 49009 -248 215 -526 49003 -246 215 -548 49013 -216 215 -538 49017 -248 185 -558 49025 -202 217 -564 48991 -244 217 -548 48993 -240 181 -564 49007 -236 201 -572 49011 -206 253 -524 49017 -206 215 -570 49009 -194 219 -560 49029 -208 215 -556 48993 -226 211 -564 48999 -248 215 -534 49025 -208 251 -522 -RAW_Data: 49019 -212 211 -554 49015 -212 247 -524 49007 -246 217 -544 49001 -242 217 -526 49031 -210 253 -522 48999 -212 217 -540 49015 -248 193 -544 49043 -202 219 -562 48983 -238 217 -564 48989 -238 217 -524 49015 -236 217 -556 48993 -230 211 -564 49015 -208 215 -558 48999 -228 213 -562 49017 -202 219 -562 49005 -226 195 -570 48997 -238 217 -530 49023 -226 195 -568 49025 -202 217 -562 48997 -230 231 -534 48997 -238 217 -530 49037 -194 223 -568 49013 -202 255 -524 48993 -230 225 -528 49043 -204 217 -564 49015 -198 241 -562 48983 -246 187 -560 49005 -228 211 -562 48993 -244 207 -550 49021 -214 217 -536 49017 -212 253 -506 49023 -238 219 -530 49009 -248 215 -532 49009 -246 217 -510 49049 -208 217 -540 49031 -204 217 -564 48985 -238 211 -568 48991 -236 197 -568 49017 -208 217 -554 48995 -236 219 -560 48991 -236 255 -528 48989 -238 219 -528 49009 -238 217 -528 49031 -210 215 -554 49023 -214 215 -536 49003 -246 215 -534 49007 -244 217 -548 49017 -210 215 -554 49011 -208 251 -524 49021 -210 215 -554 49007 -240 181 -566 49021 -196 225 -570 48987 -244 209 -550 48997 -244 217 -548 49011 -214 215 -540 49021 -248 217 -506 49045 -204 219 -562 49001 -212 253 -506 49013 -248 215 -532 49029 -214 217 -536 49009 -248 215 -530 49015 -240 217 -528 49021 -226 193 -568 48991 -238 217 -530 49019 -230 233 -528 49011 -236 219 -528 49031 -200 227 -564 48989 -226 213 -562 49005 -238 217 -530 49005 -238 217 -564 48999 -212 217 -540 49039 -214 217 -536 49031 -216 215 -538 49005 -246 215 -548 49007 -212 253 -506 49037 -214 217 -536 49035 -214 209 -550 48999 -244 217 -548 49001 -214 251 -508 49027 -206 251 -528 49011 -214 249 -524 49015 -206 253 -526 49027 -208 253 -526 49007 -204 253 -528 49021 -210 215 -554 49015 -208 217 -556 49021 -216 215 -538 49011 -248 213 -530 49011 -212 249 -528 49003 -248 215 -514 49033 -206 253 -526 49019 -206 253 -522 49013 -214 251 -508 49023 -212 253 -508 49033 -208 251 -524 49017 -212 217 -540 49021 -210 253 -510 49023 -248 215 -528 49023 -212 213 -556 48999 -244 207 -548 49015 -214 217 -540 49013 -244 217 -546 49019 -210 217 -552 48995 -244 217 -546 49017 -216 215 -534 49035 -216 217 -534 49015 -206 251 -528 49029 -208 215 -556 49021 -214 193 -578 48999 -212 253 -506 49017 -248 215 -548 48999 -212 251 -508 49041 -210 215 -556 48999 -248 215 -526 49019 -214 251 -506 49019 -248 215 -528 49005 -244 217 -548 49009 -216 215 -538 49031 -214 211 -554 49005 -248 215 -540 48987 -248 215 -534 49019 -212 221 -556 49001 -228 221 -528 49017 -238 217 -530 49023 -246 217 -508 49047 -216 215 -536 49033 -210 215 -552 49013 -210 251 -522 -RAW_Data: 49019 -214 249 -528 48987 -248 217 -530 49021 -216 215 -540 49019 -212 251 -508 49019 -246 215 -548 48989 -236 219 -554 49003 -228 195 -568 49029 -212 253 -506 49013 -208 251 -522 49019 -212 217 -540 49021 -212 251 -542 49003 -212 215 -542 49031 -214 215 -540 49035 -216 215 -538 49017 -212 251 -548 49001 -214 217 -536 49009 -246 215 -532 49005 -246 215 -534 49033 -210 215 -552 49015 -202 253 -528 48999 -246 215 -528 49003 -244 215 -550 48989 -248 215 -534 49001 -248 215 -534 49033 -214 215 -538 49027 -216 215 -538 49005 -248 215 -534 49021 -212 213 -558 48999 -248 215 -534 49017 -212 247 -526 49003 -244 217 -548 49005 -212 215 -540 49031 -212 215 -542 49023 -246 217 -508 49041 -208 215 -558 49009 -212 253 -506 49019 -246 215 -530 49005 -248 215 -532 49029 -210 215 -554 48991 -248 215 -534 49003 -246 215 -536 49003 -248 193 -578 48993 -248 215 -540 48991 -248 215 -546 48983 -246 215 -548 48987 -248 215 -534 49017 -246 217 -540 48991 -248 215 -544 48999 -208 251 -526 49011 -248 213 -526 49023 -206 215 -558 49017 -212 215 -542 49029 -212 253 -544 48999 -212 211 -552 48995 -248 215 -534 49023 -212 215 -540 49011 -244 209 -552 49017 -212 217 -540 49025 -212 213 -558 49031 -208 217 -550 48993 -248 193 -544 49013 -246 215 -534 49025 -212 215 -540 49039 -214 215 -538 49023 -214 215 -540 49017 -246 215 -548 48999 -246 217 -508 49013 -244 215 -552 49001 -238 217 -530 49029 -208 251 -526 48993 -244 207 -548 49017 -212 217 -540 49025 -206 253 -524 49007 -246 213 -530 49019 -212 217 -542 49041 -210 215 -552 49007 -212 221 -556 49005 -238 219 -530 49033 -214 215 -536 49003 -244 217 -548 49001 -248 213 -526 49023 -214 191 -584 49003 -212 251 -540 49001 -212 217 -540 49037 -212 217 -540 49007 -244 217 -548 49003 -212 253 -506 49035 -214 211 -556 48993 -244 217 -550 49005 -248 211 -526 49027 -212 209 -556 49015 -214 215 -540 49025 -212 251 -540 48993 -248 215 -542 48991 -246 213 -530 49003 -246 215 -548 49001 -212 249 -524 49021 -212 217 -542 49035 -214 209 -554 48997 -246 193 -546 49033 -206 251 -524 49031 -208 217 -550 48995 -246 215 -548 49007 -212 217 -540 49013 -240 253 -530 48989 -206 253 -522 49017 -206 253 -524 49015 -210 253 -506 49045 -216 215 -538 49015 -248 213 -526 49023 -214 215 -538 49031 -212 211 -556 48995 -248 215 -534 49031 -212 209 -552 49007 -246 217 -544 48993 -238 217 -530 49017 -246 217 -540 49003 -214 215 -540 49013 -246 215 -534 49017 -210 253 -540 48981 -248 215 -532 49011 -248 213 -528 49023 -212 217 -540 49015 -248 213 -532 49027 -212 209 -556 49003 -246 215 -532 49027 -214 217 -536 49005 -246 215 -548 -RAW_Data: 49001 -248 215 -542 48983 -248 215 -534 48999 -244 209 -552 49045 -210 215 -578 48949 -248 193 -544 49021 -248 213 -530 49017 -212 217 -542 49023 -246 217 -508 49033 -206 251 -526 49003 -242 207 -552 49003 -248 215 -512 49039 -206 215 -544 49035 -204 217 -564 49003 -240 217 -526 49021 -208 251 -524 49019 -208 251 -522 49007 -248 215 -544 49011 -208 217 -554 48993 -246 215 -534 49003 -248 251 -544 48973 -212 211 -560 49027 -212 209 -552 49009 -212 247 -526 49011 -246 215 -530 49011 -248 211 -528 49027 -216 215 -538 49013 -248 249 -538 48981 -212 211 -554 49011 -212 249 -526 49011 -212 253 -506 49037 -202 211 -564 49021 -206 237 -542 49019 -214 217 -536 49007 -248 215 -534 49009 -248 215 -544 48985 -238 217 -528 49023 -228 221 -528 49019 -228 213 -562 49001 -248 249 -536 48957 -238 201 -572 48989 -246 215 -534 49017 -212 251 -508 49015 -248 215 -532 49005 -244 253 -528 48977 -228 213 -562 48999 -212 221 -560 49017 -214 215 -542 49029 -208 251 -524 49019 -214 215 -540 49023 -212 251 -542 48979 -238 253 -528 48997 -214 251 -546 48977 -240 253 -526 48983 -248 215 -552 48993 -212 253 -546 48995 -214 253 -540 48989 -216 251 -542 48969 -246 243 -518 49009 -212 253 -546 48997 -216 253 -506 49003 -248 215 -538 49011 -212 253 -546 48985 -212 251 -548 48987 -212 249 -530 49009 -212 251 -548 48979 -246 217 -552 48983 -244 217 -556 49001 -214 251 -510 49025 -208 215 -566 49005 -214 221 -562 48993 -238 217 -564 48969 -236 255 -524 48989 -240 253 -528 48985 -248 215 -548 48987 -248 213 -534 48993 -248 251 -504 49019 -214 253 -542 48967 -246 243 -520 48991 -246 251 -538 48967 -248 215 -570 48985 -214 253 -544 48977 -212 251 -550 48987 -248 213 -534 49019 -214 243 -524 49017 -214 253 -540 48999 -210 251 -524 49013 -208 253 -522 49001 -212 247 -532 49009 -212 249 -530 49015 -212 245 -526 49017 -212 253 -542 48989 -212 247 -528 49019 -212 245 -522 49001 -246 217 -552 48977 -246 215 -538 49019 -210 247 -528 49007 -248 211 -534 49011 -246 215 -570 48949 -248 215 -540 49023 -216 251 -508 49023 -214 253 -540 48965 -246 253 -502 49011 -248 213 -532 49001 -246 215 -536 49017 -212 253 -542 48993 -212 253 -540 48973 -246 253 -528 48987 -242 205 -548 48993 -244 217 -552 49003 -214 251 -542 48991 -212 253 -542 48987 -248 213 -530 49017 -208 251 -524 48995 -246 215 -552 48993 -248 215 -550 49007 -204 255 -526 48991 -226 219 -570 48997 -212 253 -542 48991 -226 211 -562 48999 -202 255 -522 49007 -230 221 -560 49015 -204 211 -564 49001 -212 249 -530 49019 -196 243 -562 48983 -238 217 -554 49005 -194 261 -530 48999 -238 219 -528 49027 -230 233 -562 -RAW_Data: 48967 -214 251 -544 48983 -238 217 -554 49001 -200 229 -566 48999 -238 215 -546 48993 -244 241 -558 48979 -196 241 -530 49023 -202 241 -532 49031 -210 215 -570 48975 -248 223 -552 48981 -228 257 -530 48989 -248 213 -534 49023 -196 241 -562 48985 -230 211 -564 48985 -238 211 -564 48983 -244 215 -544 49017 -200 227 -564 49009 -202 255 -530 49009 -234 195 -564 49005 -240 217 -530 48997 -236 233 -538 48991 -238 253 -528 49003 -200 227 -564 49005 -228 219 -566 48989 -208 251 -526 49015 -194 261 -532 48999 -240 211 -536 49013 -212 249 -530 49011 -196 243 -560 49001 -238 217 -530 49001 -230 223 -562 48995 -240 217 -546 49005 -206 239 -544 48989 -236 253 -530 48989 -238 217 -564 48985 -232 211 -564 48991 -240 211 -534 49019 -212 223 -560 48997 -238 215 -568 48985 -232 195 -566 49013 -202 255 -528 49019 -202 255 -528 49013 -204 253 -528 48997 -246 217 -546 49005 -216 215 -542 49023 -248 215 -536 49003 -212 245 -522 48999 -248 215 -534 49005 -248 215 -532 49007 -248 213 -532 49021 -214 243 -520 48997 -244 217 -554 48983 -238 253 -524 48995 -248 215 -550 48989 -212 253 -548 48983 -246 217 -550 48991 -212 221 -564 48995 -246 215 -568 48979 -214 221 -562 49013 -210 251 -524 48987 -248 215 -572 48979 -212 247 -532 49019 -212 245 -522 49011 -212 253 -544 48977 -244 217 -554 49003 -208 251 -528 49001 -240 215 -568 48991 -198 225 -562 48987 -244 253 -520 49001 -212 251 -546 48987 -246 211 -530 49003 -246 211 -570 48981 -246 211 -532 49007 -248 213 -530 49003 -240 217 -562 48987 -212 247 -532 49025 -204 253 -528 48985 -238 253 -528 48973 -242 253 -522 48979 -246 251 -540 48987 -246 211 -530 49009 -246 217 -546 49003 -210 245 -524 48993 -244 217 -554 49007 -212 245 -526 49015 -210 247 -528 48999 -246 215 -552 48981 -244 215 -556 49017 -246 215 -552 48951 -244 209 -588 48963 -242 207 -588 48955 -246 215 -576 48977 -246 213 -566 48979 -232 197 -566 49007 -206 253 -526 48995 -238 253 -528 48989 -228 221 -560 49005 -204 253 -524 49019 -208 251 -526 48997 -248 215 -536 49005 -208 241 -548 49011 -214 247 -526 49001 -236 229 -534 49023 -212 243 -520 49001 -238 219 -562 48983 -228 231 -528 49021 -198 229 -564 48993 -244 217 -552 49003 -208 251 -526 49005 -212 253 -544 48993 -212 251 -546 48999 -214 251 -540 48995 -210 251 -522 48989 -246 215 -556 49007 -212 245 -522 49025 -208 253 -524 49011 -204 253 -528 48993 -228 221 -562 48993 -238 215 -546 49045 -208 251 -528 48965 -236 217 -566 48993 -196 241 -560 48983 -244 243 -518 49011 -212 253 -546 48995 -212 247 -522 48999 -248 215 -536 49007 -214 251 -548 48973 -248 215 -538 48997 -248 215 -540 -RAW_Data: 49009 -212 249 -532 49021 -212 243 -524 49013 -214 245 -528 49013 -214 251 -544 48987 -212 247 -530 48995 -248 215 -538 48997 -228 243 -528 49013 -212 251 diff --git a/assets/resources/subghz/Jamming/Jam_868.35.sub b/assets/resources/subghz/Jamming/Jam_868.35.sub deleted file mode 100644 index 9dee7722b..000000000 --- a/assets/resources/subghz/Jamming/Jam_868.35.sub +++ /dev/null @@ -1,16 +0,0 @@ -Filetype: Flipper SubGhz RAW File -Version: 1 -Frequency: 868350000 -Preset: FuriHalSubGhzPresetOok650Async -Protocol: RAW -RAW_Data: 10447 -306 135 -454 49115 -244 209 -394 49169 -236 217 -396 49147 -226 211 -402 49177 -208 251 -358 49185 -196 219 -398 49185 -212 213 -392 49181 -200 229 -368 49185 -238 235 -348 49205 -204 235 -346 49211 -198 225 -368 49187 -244 207 -352 49197 -230 233 -340 49199 -236 197 -372 49183 -244 217 -384 49153 -230 235 -370 49177 -242 205 -350 49195 -238 217 -396 49149 -244 241 -354 49157 -236 217 -398 49149 -244 207 -354 49219 -202 255 -360 49167 -234 197 -372 49209 -214 217 -372 49181 -212 247 -362 49185 -202 255 -362 49171 -234 197 -374 49191 -238 217 -362 49189 -206 239 -382 49183 -204 217 -396 49169 -242 203 -382 49181 -198 211 -400 49173 -240 211 -370 49191 -200 229 -370 49193 -234 197 -374 49211 -212 209 -390 49175 -208 251 -360 49187 -194 211 -402 49181 -230 189 -398 49193 -212 209 -394 49165 -244 205 -386 49167 -228 197 -408 49175 -238 217 -360 49165 -244 215 -386 49179 -206 205 -380 49197 -242 205 -382 49181 -198 227 -370 49193 -244 203 -382 49173 -228 195 -380 49201 -200 227 -370 49177 -232 235 -430 49117 -236 197 -434 49143 -212 211 -454 49103 -248 213 -430 49101 -248 213 -440 49111 -244 203 -416 49137 -246 213 -430 49105 -218 213 -438 49121 -228 211 -400 49191 -196 217 -400 49177 -198 229 -372 49193 -242 203 -352 49193 -244 205 -386 49181 -206 237 -380 49165 -242 205 -384 49161 -246 215 -368 49189 -212 211 -394 49185 -212 211 -394 49173 -242 203 -382 49159 -244 207 -388 49171 -242 205 -382 49169 -242 205 -382 49169 -236 197 -372 49191 -242 207 -384 49189 -214 193 -380 49209 -204 217 -398 49165 -212 251 -342 49205 -212 211 -390 49171 -212 251 -378 49173 -204 217 -398 49167 -234 199 -372 49209 -204 217 -396 49181 -212 209 -390 49185 -202 253 -360 49187 -212 211 -390 49183 -202 255 -360 49181 -212 211 -394 49185 -196 211 -402 49197 -204 209 -372 49213 -208 187 -404 49171 -244 207 -356 49215 -204 217 -396 49183 -212 209 -390 49183 -202 253 -360 49185 -212 211 -392 49183 -196 211 -400 49197 -204 211 -402 49185 -210 215 -374 49171 -244 207 -386 49181 -202 253 -360 49181 -212 213 -394 49179 -238 217 -360 49193 -206 205 -378 49195 -242 205 -384 49169 -242 205 -384 49181 -206 203 -380 49203 -206 237 -380 49155 -246 207 -388 49189 -206 203 -378 49211 -206 203 -378 49191 -236 197 -376 49191 -244 205 -384 49171 -242 203 -384 49157 -244 207 -388 49159 -222 211 -404 49169 -228 235 -342 49185 -232 225 -368 49201 -204 237 -348 49209 -212 211 -390 49163 -238 201 -378 49203 -208 237 -346 49191 -242 207 -356 49199 -234 199 -374 49197 -242 205 -350 49187 -244 209 -358 49191 -236 201 -374 49183 -244 209 -358 49193 -244 205 -388 -RAW_Data: 49173 -228 195 -380 49201 -232 197 -372 49197 -228 195 -378 49197 -234 195 -406 49167 -238 181 -398 49153 -272 169 -414 49143 -272 181 -396 49179 -242 169 -414 49163 -242 203 -386 49165 -238 217 -396 49141 -236 201 -410 49145 -244 215 -374 49163 -256 181 -402 49183 -244 179 -414 49165 -222 211 -372 49203 -204 211 -402 49167 -238 213 -394 49143 -236 219 -396 49175 -214 215 -374 49169 -232 235 -370 49173 -236 215 -394 49145 -228 215 -370 49181 -230 227 -370 49185 -248 185 -394 49171 -244 205 -354 49205 -214 251 -340 49197 -206 239 -350 49199 -200 231 -370 49203 -214 213 -362 49199 -226 211 -370 49193 -242 205 -354 49213 -202 217 -396 49183 -212 211 -360 49215 -202 253 -360 49183 -212 211 -362 49211 -196 211 -400 49201 -204 211 -404 49149 -244 185 -404 49171 -244 207 -386 49185 -202 217 -396 49183 -212 211 -390 49181 -204 253 -360 49183 -212 211 -394 49185 -208 217 -388 49181 -212 217 -376 49199 -212 211 -390 49167 -236 199 -374 49193 -242 207 -384 49165 -248 213 -366 49179 -238 219 -360 49193 -206 203 -378 49213 -202 219 -394 49183 -212 211 -390 49187 -202 217 -396 49155 -244 209 -388 49161 -236 217 -396 49155 -244 205 -354 49215 -196 211 -400 49179 -212 251 -342 49207 -208 217 -388 49157 -220 213 -400 49175 -230 191 -400 49195 -206 203 -380 49191 -244 217 -380 49177 -210 211 -392 49181 -232 195 -374 49193 -240 205 -382 49155 -236 219 -398 49157 -236 197 -376 49175 -234 219 -396 49153 -244 207 -390 49169 -244 215 -380 49155 -246 213 -368 49193 -210 209 -394 49177 -246 179 -412 49157 -246 211 -364 49163 -246 191 -420 49159 -244 217 -378 49159 -244 217 -378 49151 -220 213 -404 49183 -226 193 -380 49187 -234 197 -376 49199 -246 175 -396 49177 -242 203 -384 49167 -246 211 -364 49165 -246 213 -372 49173 -246 215 -380 49149 -246 215 -372 49175 -244 215 -382 49179 -222 179 -402 49185 -236 197 -376 49183 -246 213 -366 49191 -210 209 -394 49179 -246 175 -396 49185 -246 175 -396 49165 -242 207 -388 49171 -242 205 -384 49169 -246 177 -398 49175 -246 215 -378 49165 -240 217 -358 49175 -226 211 -404 49157 -242 207 -386 49181 -212 215 -376 49167 -270 179 -396 49169 -242 205 -386 49175 -246 175 -394 49169 -246 215 -368 49185 -212 211 -396 49181 -218 211 -408 49155 -226 211 -370 49185 -244 217 -380 49153 -238 217 -400 49157 -212 251 -376 49163 -238 217 -360 49185 -214 211 -396 49163 -226 211 -402 49169 -228 221 -366 49177 -236 217 -396 49149 -244 209 -354 49189 -236 219 -396 49173 -194 211 -402 49179 -240 217 -362 49197 -198 225 -368 49185 -240 217 -362 49179 -236 217 -396 49151 -242 207 -354 49217 -202 217 -396 49157 -244 209 -356 -RAW_Data: 49221 -198 211 -402 49161 -240 211 -370 49179 -244 217 -380 49181 -204 217 -396 49161 -236 217 -362 49191 -224 213 -370 49203 -206 235 -346 49215 -212 209 -358 49191 -244 209 -356 49207 -206 239 -380 49185 -212 211 -388 49181 -198 229 -370 49209 -212 209 -390 49163 -244 207 -386 49165 -242 207 -384 49159 -244 207 -388 49187 -204 203 -378 49185 -244 209 -390 49159 -244 209 -388 49175 -212 215 -378 49185 -248 213 -364 49171 -242 207 -386 49161 -244 207 -386 49167 -250 211 -364 49187 -212 211 -396 49173 -238 217 -362 49185 -206 239 -350 49217 -204 217 -396 49155 -244 207 -386 49177 -212 211 -394 49167 -244 207 -384 49171 -248 213 -362 49177 -248 211 -364 49167 -244 207 -356 49207 -206 239 -348 49193 -244 207 -354 49189 -244 209 -356 49209 -208 237 -346 49201 -242 205 -350 49203 -242 205 -350 49205 -212 213 -396 49191 -214 215 -370 49199 -188 211 -402 49187 -234 195 -372 49195 -232 197 -374 49211 -210 209 -390 49189 -212 209 -390 49177 -208 237 -380 49161 -244 205 -384 49167 -244 205 -384 49175 -206 239 -380 49157 -246 207 -388 49169 -242 205 -384 49159 -244 209 -386 49171 -242 205 -382 49167 -244 205 -382 49175 -242 203 -352 49187 -236 201 -376 49201 -212 245 -362 49167 -242 207 -388 49187 -204 203 -380 49189 -234 199 -376 49209 -212 211 -392 49173 -244 205 -350 49201 -208 239 -350 49185 -244 209 -390 49165 -234 201 -376 49207 -204 237 -346 49197 -212 251 -344 49199 -208 215 -370 49207 -240 217 -360 49177 -238 217 -362 49193 -202 217 -400 49185 -210 215 -386 49157 -246 207 -356 49219 -204 203 -380 49187 -244 217 -382 49165 -210 249 -362 49193 -212 211 -388 49185 -214 209 -392 49189 -212 207 -390 49165 -242 207 -386 49165 -244 205 -384 49167 -242 205 -386 49173 -242 205 -382 49175 -212 211 -394 49167 -244 205 -386 49157 -244 209 -388 49175 -246 213 -360 49173 -242 205 -384 49161 -244 207 -388 49169 -236 197 -374 49177 -246 207 -390 49167 -248 213 -366 49193 -204 203 -380 49197 -212 247 -362 49191 -212 209 -390 49165 -244 207 -386 49175 -242 203 -380 49173 -228 195 -380 49193 -238 215 -360 49203 -208 217 -386 49177 -210 211 -396 49183 -206 239 -348 49215 -206 203 -380 49197 -242 203 -352 49195 -228 197 -408 49175 -238 217 -360 49191 -202 211 -404 49171 -228 195 -380 49187 -236 199 -376 49201 -226 195 -410 49177 -204 217 -396 49175 -202 255 -362 49181 -206 217 -390 49175 -238 217 -396 49135 -228 215 -400 49165 -236 199 -376 49201 -212 215 -376 49191 -240 219 -358 49193 -208 217 -388 49179 -212 215 -376 49185 -242 205 -386 49167 -248 211 -364 49187 -212 211 -394 49173 -248 213 -362 49191 -198 227 -368 49199 -206 239 -348 -RAW_Data: 49209 -198 229 -370 49195 -236 195 -374 49207 -206 201 -380 49195 -234 197 -374 49201 -206 239 -348 49199 -242 205 -352 49195 -244 207 -354 49205 -212 211 -396 49163 -244 209 -356 49209 -212 211 -394 49169 -242 207 -356 49185 -246 209 -356 49209 -212 211 -394 49181 -212 211 -394 49163 -244 209 -358 49185 -244 209 -388 49189 -212 209 -390 49185 -210 211 -394 49169 -234 199 -374 49199 -242 203 -382 49171 -248 175 -398 49171 -246 213 -364 49163 -222 211 -402 49195 -198 227 -368 49183 -248 213 -368 49183 -206 253 -358 49175 -240 217 -396 49147 -238 181 -402 49171 -226 215 -398 49175 -206 237 -380 49153 -244 215 -386 49181 -214 191 -418 49169 -204 253 -358 49167 -244 215 -384 49179 -212 215 -376 49187 -246 211 -364 49161 -244 209 -390 49165 -244 205 -386 49175 -210 211 -396 49179 -212 247 -360 49163 -246 215 -372 49163 -246 209 -390 49187 -214 191 -418 49165 -238 217 -362 49177 -222 211 -372 49205 -206 237 -348 49189 -244 205 -388 49181 -206 237 -346 49193 -236 199 -374 49205 -212 215 -378 49181 -248 185 -396 49165 -226 215 -400 49161 -248 213 -366 49175 -238 217 -396 49151 -244 205 -382 49175 -206 253 -358 49189 -202 217 -396 49183 -206 235 -346 49213 -204 217 -396 49181 -212 211 -390 49185 -202 253 -360 49185 -212 209 -392 49181 -196 211 -402 49199 -202 211 -404 49183 -210 215 -374 49173 -244 207 -386 49179 -202 255 -358 49181 -214 211 -394 49181 -204 253 -360 49183 -212 211 -394 49167 -236 219 -396 49151 -234 199 -374 49213 -204 217 -396 49183 -212 209 -388 49189 -202 217 -396 49183 -212 209 -388 49183 -198 211 -400 49199 -202 211 -370 49215 -208 215 -376 49173 -244 207 -354 49211 -202 255 -360 49181 -212 213 -394 49189 -202 217 -398 49171 -196 219 -398 49179 -210 253 -344 49199 -206 215 -402 49171 -242 205 -382 49181 -208 217 -390 49163 -236 217 -396 49157 -238 215 -394 49161 -204 211 -402 49177 -234 197 -372 49209 -206 203 -378 49197 -210 253 -376 49173 -216 215 -374 49169 -244 209 -386 49165 -244 207 -384 49177 -212 211 -396 49181 -206 239 -348 49197 -242 205 -382 49171 -242 205 -382 49167 -248 213 -364 49195 -206 201 -378 49203 -206 239 -348 49217 -214 191 -382 49189 -238 219 -364 49199 -208 217 -388 49183 -214 215 -374 49171 -244 209 -386 49185 -206 237 -346 49209 -212 211 -392 49161 -248 193 -380 49193 -212 251 -342 49193 -206 251 -360 49171 -230 221 -368 49175 -236 217 -396 49151 -244 209 -356 49215 -202 255 -360 49181 -214 209 -390 49183 -202 253 -360 49183 -212 211 -394 49181 -196 211 -400 49205 -202 211 -404 49151 -246 185 -400 49171 -244 207 -384 49179 -204 253 -360 49181 -212 211 -396 49181 -202 253 -360 -RAW_Data: 49183 -212 213 -392 49181 -202 255 -360 49183 -212 211 -394 49179 -196 243 -368 49201 -204 211 -402 49185 -208 215 -378 49169 -246 207 -388 49179 -202 255 -358 49181 -214 211 -394 49181 -202 255 -358 49185 -212 211 -394 49189 -202 217 -396 49157 -244 209 -386 49179 -202 211 -402 49163 -246 207 -388 49189 -216 193 -380 49183 -228 221 -380 49181 -212 253 -342 49199 -214 215 -376 49185 -212 249 -362 49185 -214 217 -374 49177 -244 205 -386 49183 -212 211 -392 49185 -198 229 -370 49191 -242 205 -382 49169 -228 195 -410 49179 -202 217 -396 49171 -246 185 -396 49159 -238 217 -400 49149 -244 215 -382 49151 -244 209 -388 49165 -236 199 -408 49175 -200 227 -370 49199 -196 219 -398 49191 -206 203 -412 49161 -242 207 -384 49163 -242 207 -386 49167 -242 205 -384 49173 -240 203 -384 49181 -210 209 -394 49183 -246 173 -396 49173 -246 211 -364 49175 -244 213 -366 49163 -246 215 -372 49179 -246 213 -364 49171 -246 195 -382 49177 -238 217 -398 49147 -238 217 -398 49159 -212 215 -378 49195 -234 195 -372 49183 -230 233 -372 49175 -238 215 -358 49171 -236 217 -400 49175 -208 217 -388 49185 -214 213 -374 49187 -246 211 -362 49183 -240 203 -382 49163 -244 205 -386 49175 -240 203 -382 49173 -242 203 -382 49165 -242 205 -386 49177 -206 205 -412 49173 -240 203 -382 49167 -240 205 -384 49181 -232 181 -404 49155 -242 185 -438 49141 -242 207 -388 49177 -228 183 -400 49167 -236 217 -398 49155 -230 199 -406 49157 -228 211 -402 49163 -242 217 -382 49169 -238 213 -394 49143 -236 201 -410 49151 -242 207 -390 49161 -244 205 -388 49173 -242 203 -384 49179 -206 237 -378 49173 -234 197 -374 49179 -236 201 -378 49197 -242 203 -382 49171 -234 197 -374 49179 -236 203 -380 49187 -246 211 -368 49179 -228 183 -400 49199 -202 217 -400 49155 -236 203 -380 49175 -236 217 -396 209 -392 49181 -238 213 -360 49187 -246 175 -396 49181 -238 215 -360 49185 -246 175 -396 49181 -228 183 -400 49167 -236 211 -404 49155 -244 185 -432 49135 -238 201 -412 49171 -238 181 -398 49157 -238 201 -412 49145 -234 217 -396 49151 -244 209 -392 49179 -236 215 -394 49153 -246 175 -396 49179 -236 213 -394 49163 -210 211 -394 49177 -228 183 -400 49201 -202 211 -402 49153 -240 185 -438 49141 -244 207 -388 49177 -238 215 -394 49149 -246 175 -398 49177 -238 213 -394 49149 -246 213 -366 49191 -238 179 -396 49153 -244 209 -392 49181 -238 215 -360 49183 -246 175 -398 49177 -238 213 -394 49153 -244 211 -366 49177 -228 183 -400 49201 -238 181 -398 49155 -238 203 -380 49177 -272 181 -396 49151 -244 207 -392 49181 -238 179 -396 49187 -246 175 -394 49181 -238 179 -430 49153 -246 175 -396 49177 -226 -RAW_Data: 183 -402 49167 -236 217 -398 49155 -236 201 -410 49147 -236 219 -396 49149 -244 207 -390 49179 -238 215 -394 49153 -246 175 -394 49179 -228 183 -400 49167 -236 211 -402 49151 -242 185 -438 49141 -242 207 -388 49179 -236 215 -394 49151 -246 175 -398 49177 -238 213 -394 49153 -246 211 -364 49177 -238 213 -394 49163 -246 175 -394 49185 -226 181 -402 49165 -236 211 -402 49151 -244 185 -402 49175 -242 207 -388 49179 -226 181 -402 49165 -236 217 -398 49157 -236 199 -378 49175 -236 217 -396 49151 -244 207 -392 49179 -238 179 -396 49187 -246 175 -394 49181 -238 213 -360 49187 -246 175 -396 49181 -228 183 -400 49199 -202 211 -402 49151 -240 215 -410 49141 -242 207 -388 49177 -228 183 -400 49167 -236 219 -398 49155 -236 199 -408 49145 -272 181 -396 49151 -242 209 -392 49179 -238 213 -394 49155 -246 175 -396 49181 -228 183 -400 49177 -238 181 -434 49151 -244 185 -396 49175 -242 203 -384 49179 -228 181 -402 49171 -238 217 -396 49167 -232 193 -374 49183 -236 217 -396 49149 -234 201 -408 49151 -236 219 -398 49169 -228 191 -382 49177 -242 207 -388 49169 -246 215 -378 49153 -244 215 -384 49179 -206 215 -390 49173 -244 217 -378 49159 -244 211 -366 49175 -242 205 -386 49171 -240 205 -384 49153 -244 207 -390 49173 -242 205 -384 49165 -242 207 -384 49159 -244 207 -388 49171 -240 205 -384 49161 -236 201 -378 49179 -238 201 -412 49147 -238 203 -410 49157 -242 207 -388 49177 -210 211 -394 49161 -244 209 -390 49153 -238 203 -410 49155 -236 201 -406 49155 -236 201 -410 49157 -242 207 -384 49169 -242 205 -386 49161 -242 205 -388 49163 -242 205 -390 49169 -244 205 -382 49183 -204 205 -412 49159 -246 213 -368 49175 -246 213 -364 49175 -246 215 -380 49167 -210 211 -396 49187 -240 203 -350 49201 -234 197 -372 49193 -242 205 -384 49177 -206 237 -348 49195 -236 197 -376 49179 -244 209 -390 49175 -240 203 -382 49157 -236 201 -378 49195 -234 199 -374 49189 -236 197 -376 49193 -234 199 -374 49177 -246 207 -388 49177 -240 203 -382 49171 -248 211 -362 49185 -214 215 -376 49189 -212 211 -398 49171 -246 213 -366 49171 -242 207 -386 49169 -242 205 -386 49171 -248 175 -398 49191 -210 209 -392 49183 -212 215 -376 49175 -244 207 -388 49181 -212 215 -376 49179 -244 205 -386 49163 -248 211 -368 49163 -244 209 -390 49161 -244 207 -388 49163 -236 199 -376 49193 -230 195 -408 49161 -228 235 -370 49171 -236 215 -394 49153 -240 181 -400 49175 -236 217 -396 49147 -236 219 -396 49159 -238 217 -360 49185 -232 181 -402 49173 -228 221 -394 49179 -196 223 -380 49191 -232 197 -372 49197 -226 195 -380 49203 -238 181 -396 49173 -246 217 -376 49155 -246 213 -366 49171 -246 -RAW_Data: 213 -368 49179 -242 205 -384 49179 -232 195 -372 49175 -238 203 -378 49179 -238 203 -378 49201 -242 203 -350 49209 -206 205 -412 49179 -206 203 -412 49165 -248 211 -362 49165 -244 209 -388 49179 -212 209 -396 49181 -210 211 -396 49183 -206 237 -380 49153 -238 201 -410 49165 -242 203 -384 49157 -236 201 -380 49189 -236 199 -378 49189 -242 205 -386 49155 -236 203 -380 49197 -242 203 -382 49173 -240 203 -382 49151 -238 203 -410 49175 -206 237 -380 49177 -210 211 -394 49171 -242 207 -384 49183 -210 209 -392 49167 -242 207 -386 49181 -206 237 -378 49167 -246 213 -364 49169 -246 215 -382 49167 -248 175 -396 49177 -242 205 -382 49161 -236 199 -378 49181 -232 233 -370 49169 -228 221 -380 49181 -238 215 -360 49201 -208 215 -388 49161 -236 201 -378 49193 -230 197 -378 49187 -236 199 -378 49195 -228 189 -398 49167 -228 223 -380 49167 -232 225 -368 49201 -194 225 -380 49175 -230 237 -368 49177 -234 197 -374 49195 -230 195 -410 49181 -202 219 -396 49153 -242 187 -402 49189 -212 215 -378 49193 -232 197 -370 49193 -228 195 -410 49161 -228 213 -370 49187 -236 199 -376 49199 -228 193 -380 49177 -236 217 -396 49155 -244 185 -402 49189 -212 191 -418 49159 -246 193 -382 49183 -242 205 -386 49169 -228 197 -378 49195 -236 197 -374 49191 -230 189 -398 49169 -228 221 -380 49171 -236 217 -396 49175 -212 215 -376 49171 -238 201 -380 49185 -228 223 -370 49175 -244 207 -388 49161 -244 207 -386 49183 -198 229 -370 49199 -206 237 -350 49203 -242 203 -350 49197 -246 211 -366 49165 -246 215 -368 49177 -248 213 -366 49185 -210 217 -410 49143 -246 215 -368 49175 -242 207 -388 49161 -236 199 -408 49159 -242 205 -386 49169 -242 205 -384 49157 -246 215 -384 49179 -212 209 -392 49161 -238 201 -378 49183 -238 201 -378 49201 -232 197 -370 49207 -212 209 -390 49169 -234 201 -374 49191 -242 205 -384 49169 -228 197 -408 49181 -196 219 -398 49179 -242 203 -380 49183 -204 203 -380 49207 -212 209 -394 49175 -242 205 -382 49169 -230 195 -380 49183 -228 215 -400 49161 -244 207 -354 49199 -242 205 -384 49167 -242 205 -386 49167 -230 189 -398 49187 -206 237 -380 49185 -212 209 -392 49159 -238 201 -378 49205 -206 237 -348 49187 -238 199 -378 49201 -212 215 -376 49183 -246 193 -380 49193 -206 251 -358 49181 -212 221 -390 49175 -230 181 -402 49177 -230 223 -368 49197 -206 235 -378 49161 -244 205 -386 49171 -242 205 -382 49179 -212 217 -374 49181 -238 217 -398 49145 -244 217 -380 49167 -212 221 -394 49155 -236 219 -398 49177 -214 215 -370 49191 -206 237 -380 49185 -206 203 -378 49181 -238 203 -378 49197 -242 205 -382 49171 -228 195 -378 49203 -200 227 -372 49193 -228 -RAW_Data: 197 -378 49197 -234 197 -374 49189 -244 205 -384 49159 -236 201 -376 49203 -210 211 -396 49157 -244 209 -390 49185 -210 209 -392 49165 -242 207 -390 49163 -244 215 -368 49169 -246 213 -370 49171 -244 215 -384 49153 -244 207 -388 49161 -242 207 -390 49157 -242 209 -390 49167 -236 199 -406 49171 -210 211 -396 49171 -236 197 -406 49159 -242 205 -386 49183 -210 211 -392 49161 -244 207 -388 49173 -240 205 -384 49163 -242 205 -388 49175 -212 209 -396 49183 -240 203 -384 49155 -238 199 -408 49163 -242 205 -386 49167 -242 203 -384 49155 -238 203 -380 49209 -206 203 -410 49171 -240 205 -382 49165 -246 213 -364 49191 -210 209 -392 49157 -244 209 -390 49165 -242 207 -388 49183 -206 203 -380 49185 -236 201 -380 49181 -238 201 -380 49189 -236 199 -376 49197 -234 195 -372 49179 -236 203 -378 49203 -240 203 -352 49205 -240 203 -352 49205 -240 203 -350 49181 -238 201 -380 49195 -236 197 -374 49199 -232 197 -372 49205 -198 227 -370 49201 -232 195 -372 49193 -234 197 -374 49203 -204 237 -380 49169 -232 197 -374 49189 -234 199 -406 49175 -200 227 -370 49185 -230 233 -370 49177 -228 189 -398 49177 -236 197 -374 49191 -236 197 -374 49189 -236 199 -378 49179 -236 201 -410 49155 -238 199 -378 49197 -212 211 -398 49173 -246 211 -364 49169 -246 215 -368 49193 -212 215 -376 49193 -212 209 -394 49165 -236 201 -378 49193 -236 197 -374 49199 -206 239 -380 49155 -238 201 -378 49181 -238 203 -378 49201 -226 195 -378 49203 -202 219 -396 49171 -248 215 -376 49159 -234 199 -374 49177 -232 235 -368 49183 -238 215 -360 49173 -244 215 -384 49159 -236 199 -376 49191 -230 189 -398 49199 -196 223 -380 49199 -200 227 -370 49197 -228 195 -378 49175 -236 219 -396 49171 -212 215 -410 49143 -244 207 -388 49173 -242 205 -382 49171 -230 195 -378 49187 -236 199 -376 49193 -244 203 -384 49157 -244 209 -388 49165 -236 199 -376 49195 -228 195 -380 49207 -194 211 -400 49185 -228 181 -400 49183 -238 213 -394 49173 -208 215 -388 49157 -244 209 -390 49173 -230 195 -378 49203 -232 195 -372 49197 -228 193 -380 49209 -202 217 -396 49175 -212 215 -376 49197 -200 227 -372 49191 -228 191 -396 49197 -196 225 -380 49197 -200 225 -370 49199 -226 195 -378 49203 -204 217 -396 49171 -248 215 -378 49163 -236 195 -372 49179 -232 225 -368 49193 -240 205 -350 49193 -230 197 -406 49181 -202 217 -396 49167 -238 217 -398 49139 -246 215 -370 49197 -198 237 -370 49181 -238 215 -392 49141 -244 215 -384 49163 -242 205 -384 49167 -228 199 -406 49177 -228 189 -398 49163 -238 203 -378 49201 -206 237 -382 49179 -206 205 -410 49171 -242 203 -380 49155 -236 203 -408 49179 -206 203 -410 49169 -242 -RAW_Data: 205 -384 49167 -246 213 -364 49187 -212 211 -392 49173 -242 205 -382 49177 -232 195 -372 49183 -244 207 -386 49173 -228 197 -378 49199 -234 197 -372 49179 -246 207 -390 49165 -248 211 -364 49173 -242 207 -386 49173 -242 203 -382 49159 -244 207 -388 49179 -206 237 -350 49197 -246 213 -362 49183 -206 239 -350 49213 -206 203 -380 49185 -244 207 -388 49171 -242 205 -352 49205 -248 175 -398 49157 -238 203 -378 49195 -244 203 -382 49175 -242 203 -380 49181 -206 205 -410 49167 -242 205 -382 49171 -242 205 -384 49153 -238 201 -378 49195 -234 199 -374 49183 -236 201 -378 49187 -236 199 -376 49199 -242 203 -380 49167 -230 189 -398 49195 -194 225 -378 49205 -202 217 -396 49185 -206 217 -388 49163 -248 213 -370 49163 -238 203 -378 49181 -238 203 -378 49181 -246 193 -382 49181 -238 211 -370 49189 -228 213 -370 49195 -234 195 -372 49191 -242 205 -382 49171 -248 213 -362 49175 -246 213 -364 49193 -212 209 -390 49157 -248 213 -372 49179 -220 211 -412 49157 -232 181 -402 49189 -234 195 -374 49199 -212 209 -396 49181 -212 209 -396 49183 -206 251 -358 49167 -246 193 -380 49205 -212 215 -374 49175 -246 213 -368 49173 -246 193 -380 49191 -212 215 -410 49145 -244 215 -384 49181 -212 217 -374 49177 -246 213 -366 49187 -210 211 -396 49175 -244 217 -378 49163 -212 247 -362 49169 -242 207 -388 49167 -236 197 -376 49177 -236 203 -408 49175 -206 237 -380 49179 -212 211 -390 49187 -210 209 -392 49175 -242 207 -384 49161 -236 199 -376 49199 -206 239 -380 49159 -236 201 -376 49193 -242 205 -384 49187 -204 203 -380 49201 -240 203 -382 49153 -244 209 -390 49173 -242 205 -382 49155 -238 203 -378 49183 -238 201 -378 49187 -244 205 -384 49175 -242 203 -380 49155 -244 209 -390 49185 -212 209 -392 49159 -244 207 -388 49189 -212 215 -372 49201 -214 215 -370 49193 -208 215 -390 49169 -246 215 -382 49149 -244 209 -388 49159 -244 207 -388 49189 -212 209 -388 49187 -210 209 -392 49189 -204 205 -410 49157 -244 207 -386 49179 -212 211 -392 49163 -244 207 -388 49159 -244 209 -388 49169 -242 205 -384 49173 -246 211 -362 49193 -212 215 -374 49183 -246 211 -364 49167 -248 213 -370 49183 -210 247 -360 49187 -212 215 -376 49191 -242 203 -380 49163 -242 207 -386 49175 -212 211 -394 49173 -246 213 -366 49173 -218 213 -404 49175 -234 195 -372 49201 -210 211 -394 49167 -246 213 -368 49193 -208 215 -390 49159 -244 185 -402 49187 -202 253 -362 49173 -240 217 -362 49167 -244 209 -390 49177 -210 253 -340 49189 -248 211 -364 49163 -230 237 -368 49177 -244 205 -352 49203 -234 199 -372 49177 -244 209 -388 49187 -212 209 -390 49167 -248 213 -366 49193 -214 215 -374 49167 -244 -RAW_Data: 215 -386 49169 -212 251 -376 49151 -244 217 -380 49153 -242 217 -386 49171 -212 251 -374 49167 -240 203 -350 49201 -242 203 -382 49167 -242 205 -384 49165 -242 207 -384 49157 -246 207 -388 49183 -214 215 -376 49189 -210 213 -396 49185 -206 215 -392 49163 -244 217 -382 49159 -244 207 -386 49157 -238 201 -378 49199 -242 203 -352 49197 -242 205 -384 49167 -230 195 -380 49209 -202 217 -396 49173 -246 217 -376 49163 -234 197 -372 49197 -228 195 -380 49195 -234 197 -372 49193 -242 205 -352 49199 -230 189 -398 49197 -194 223 -380 49199 -198 227 -370 49179 -242 209 -390 49165 -228 223 -370 49167 -230 221 -380 49177 -230 211 -404 49171 -196 211 -402 49183 -228 181 -402 49185 -228 213 -370 49185 -234 199 -376 49195 -242 205 -382 49163 -230 197 -408 49177 -238 217 -358 49165 -244 185 -404 49189 -212 215 -376 49199 -198 227 -372 49191 -230 195 -378 49207 -202 217 -396 49169 -246 215 -380 49159 -236 197 -374 49199 -240 203 -384 49165 -228 197 -408 49177 -202 217 -396 49169 -246 215 -380 49161 -234 199 -374 49197 -228 195 -380 49197 -234 197 -374 49197 -228 195 -378 49197 -234 197 -372 49203 -200 225 -372 49195 -228 195 -380 49205 -196 211 -402 49161 -226 223 -380 49201 -202 217 -396 49169 -240 217 -362 49171 -244 215 -382 49165 -246 185 -396 49167 -234 201 -408 49159 -236 197 -406 49161 -242 203 -384 49165 -242 205 -388 49169 -240 205 -386 49153 -244 209 -390 49163 -246 213 -368 49161 -244 209 -392 49161 -244 207 -388 49161 -242 209 -390 49181 -206 237 -350 49213 -212 209 -390 49179 -196 211 -400 49201 -202 211 -404 49159 -248 213 -366 49183 -242 203 -380 49169 -242 205 -384 49157 -238 199 -378 49207 -204 205 -380 49185 -244 213 -372 49165 -242 215 -386 49171 -228 195 -408 49163 -236 219 -398 49161 -232 195 -374 49169 -272 181 -400 49173 -240 181 -392 49163 -236 217 -398 49173 -238 181 -400 49155 -236 217 -398 49155 -236 217 -396 49151 -236 199 -380 49175 -236 217 -396 49151 -244 207 -390 49157 -246 215 -372 49167 -238 201 -412 49163 -246 215 -378 49171 -228 193 -380 49193 -240 217 -392 49127 -236 211 -404 49167 -246 185 -394 49187 -202 211 -404 49179 -232 195 -370 49183 -242 207 -388 49159 -232 233 -370 49175 -238 213 -394 49139 -236 217 -398 49149 -244 207 -390 49173 -234 197 -374 49207 -204 203 -412 49145 -238 203 -412 49171 -240 205 -382 49151 -244 215 -374 49163 -246 213 -374 49191 -246 175 -398 49181 -242 203 -380 49155 -244 209 -390 49177 -210 211 -396 49179 -246 181 -376 49179 -244 207 -390 49167 -242 205 -384 49167 -242 207 -386 49165 -242 205 -384 49165 -236 199 -376 49199 -210 209 -396 49185 -210 211 -394 49185 -246 -RAW_Data: 175 -396 49171 -242 207 -386 49151 -232 227 -370 49175 -242 207 -390 49157 -246 215 -372 49173 -246 213 -366 49163 -238 203 -412 49169 -240 203 -384 49151 -244 209 -390 49175 -246 175 -396 49163 -242 215 -386 49157 -240 217 -386 49179 -246 175 -394 49185 -246 181 -408 49151 -238 217 -396 49161 -236 179 -396 49181 -228 189 -400 49173 -234 201 -378 49197 -246 175 -398 49183 -248 175 -396 49161 -244 207 -388 49165 -242 207 -388 diff --git a/assets/resources/subghz/Misc/Pager_Bruteforce.sub b/assets/resources/subghz/Misc/Pager_Bruteforce.sub new file mode 100644 index 000000000..27e8a5430 --- /dev/null +++ b/assets/resources/subghz/Misc/Pager_Bruteforce.sub @@ -0,0 +1,108 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 467750000 +Preset: FuriHalSubGhzPresetCustom +Custom_preset_module: CC1101 +Custom_preset_data: 02 0D 07 04 08 32 0B 06 10 64 11 93 12 0C 13 02 14 00 15 15 18 18 19 16 1B 07 1C 00 1D 91 20 FB 21 56 22 10 00 00 C0 00 00 00 00 00 00 00 +Protocol: RAW +RAW_Data: 2950 -8252 551 -184 549 -7528 1285 -554 369 -187658 219 -138090 28885 -1206 4003 -2610 3601 -3004 3401 -3002 3401 -3002 3403 -2994 3401 -3002 3393 -3004 3401 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1791 -3000 1801 -1400 1801 -1400 1801 -1402 3393 -3002 3401 -1398 1791 -3000 3401 -3002 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 3389 -3002 1801 -1400 3401 -3008 3397 -2994 3401 -1398 1791 -4422 621 -2182 1689 -2756 3511 -3098 3253 -3022 3413 -3010 3403 -3002 3407 -3004 3399 -3006 3393 -2994 3401 -3002 3395 -3002 3393 -3002 3395 -3002 3405 -1400 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3407 -3004 3393 -1398 1791 -3000 3401 -3002 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 3397 -3006 1805 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 3401 -2998 1805 -1396 3391 -3002 3393 -1402 1799 -3002 1797 -1398 3801 -2190 219 -1768 1767 -2596 3795 -2728 3493 -2872 3443 -3022 3417 -3002 3407 -3006 3393 -3002 3401 -2996 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3403 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -2994 1799 -1402 1795 -1398 1801 -1400 3407 -3006 3393 -1398 1791 -2998 3403 -3002 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 3389 -3002 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 +RAW_Data: 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 3395 -3002 1795 -1398 3401 -3002 3403 -1396 1791 -3000 3401 -7590 1961 -2458 3749 -2762 3575 -2990 3395 -2998 3393 -2994 3407 -2998 3393 -2994 3407 -2998 3397 -2998 3393 -3002 3395 -3002 3407 -2996 3395 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3393 -1402 1799 -3002 3395 -3002 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 3393 -1402 1799 -3002 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 3403 -2994 1799 -1402 3407 -2996 3395 -1400 1795 -1394 1797 -3002 3603 -200 1143 -188 1487 -1226 1827 -2996 3419 -3010 3401 -3002 3401 -3004 3401 -2994 3401 -3002 3399 -3006 3393 -2994 3401 -2996 3401 -3002 3399 -2996 3395 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1799 -1402 3401 -3002 3395 -1400 1795 -2992 3401 -3002 1801 -1402 1799 -1402 1801 -1396 1791 -1398 3403 -3002 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 3407 -2996 1797 -1394 3397 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -6446 2633 -2932 3363 -3180 +RAW_Data: 3189 -3190 3395 -2994 3393 -3002 3393 -3004 3393 -3002 3393 -3002 3403 -3002 3393 -3002 3395 -3002 3405 -2998 3393 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1394 1795 -1402 1801 -1400 3401 -2996 3401 -1400 1801 -3002 3393 -3004 1799 -1398 1791 -1398 1801 -1400 1801 -1400 3403 -3002 3399 -3004 1795 -1396 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 3401 -2996 1799 -1402 3401 -1398 1791 -2998 1801 -1402 1799 -1402 1799 -1402 4405 -2974 1981 -3218 3193 -3160 3241 -3164 3313 -3118 3309 -3084 3243 -3026 3413 -3002 3407 -3010 3409 -3002 3399 -2996 3391 -2994 3401 -2994 3403 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1396 1797 -3002 1801 -1400 1801 -1396 1791 -1400 3401 -3002 3401 -1402 1799 -2996 3401 -3002 1795 -1394 1797 -1400 1801 -1402 1799 -1402 3401 -1402 1795 -2990 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 3407 -2998 1795 -1394 3389 -1402 1801 -3002 1799 -1402 1801 -1400 3401 -3596 385 -560 373 -2330 8379 -2512 3729 -2750 3565 -2984 3385 -2990 3395 -3002 3393 -3002 3393 -3004 3401 -2998 3405 -2994 3395 -2994 3401 -3002 3403 -1400 1795 -1394 1793 -1398 1799 -1402 1799 -1402 1801 -3002 1799 -1402 1801 -1396 1791 -1398 3407 -3006 3393 -1402 1795 -2998 3403 -2994 1801 -1400 1801 -1396 1797 -1400 1801 -1402 3401 -1396 1793 -1398 1799 -3002 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 +RAW_Data: 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -3002 1799 -1402 3407 -1400 1789 -2990 1799 -1402 3401 -3002 3609 -3274 2973 -2884 3537 -2960 3375 -2986 3389 -2996 3393 -2994 3393 -3002 3403 -3002 3401 -2994 3407 -2998 3393 -2994 3401 -3004 3393 -3002 3393 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -2990 1801 -1402 1799 -1402 1799 -1402 3393 -3002 3403 -1400 1795 -2992 3401 -3002 1801 -1402 1795 -1398 1801 -1400 3401 -3002 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 3401 -3002 1797 -1398 3401 -1396 1797 -3002 1801 -1400 3403 -1396 1791 -3800 205 -3344 203 -612 2395 -2560 3555 -2896 3655 -2830 3419 -3014 3407 -3004 3393 -3004 3401 -2994 3401 -2994 3395 -3002 3401 -3002 3395 -3002 3401 -2998 3397 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -3004 1799 -1402 1799 -1398 1791 -1398 3403 -3002 3401 -1400 1801 -3002 3395 -3002 1799 -1398 1791 -1398 1801 -1400 3407 -3006 1795 -1394 3389 -3002 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 3407 -2998 1795 -1394 3397 -1402 1799 -3002 3395 -3002 1795 -1398 4003 -4020 1655 -3022 3323 -3148 3163 -3176 3385 -2990 3393 -2996 3401 -3002 3401 -2994 +RAW_Data: 3395 -3002 3401 -3002 3395 -3002 3401 -2994 3393 -3004 3401 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1402 3401 -2994 3401 -1402 1799 -3004 3397 -3006 1795 -1394 1791 -1400 1799 -1402 3401 -3002 3401 -2996 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1398 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 3401 -3002 1801 -1400 3407 -1400 1789 -2990 3407 -3004 3395 -8162 1623 -2776 3591 -2998 3389 -3000 3397 -2994 3393 -3002 3395 -3002 3401 -3002 3395 -3002 3393 -3002 3401 -2996 3401 -2994 3401 -3002 3395 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -3002 1799 -1398 1797 -1400 1801 -1400 3395 -3002 3401 -1398 1791 -3000 3401 -3002 1801 -1400 1795 -1394 1797 -1402 3405 -3006 3393 -1402 1799 -2996 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 3403 -3002 1799 -1398 3389 -1402 1801 -3002 3401 -1396 1793 -2998 3403 -1030 647 -3066 1817 -2644 3739 -2768 3575 -2986 3389 -2994 3395 -3002 3393 -3002 3399 -3006 3393 -2994 3401 -3004 3393 -3002 3393 -3002 3395 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3407 -3004 3399 -1404 1793 -2986 3401 -3002 1797 -1394 1795 -1402 1801 -1400 3407 -1404 1795 -2992 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 +RAW_Data: 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 3407 -3004 1795 -1394 3391 -1404 1801 -2994 3403 -1400 1795 -1394 1797 -6646 2743 -2920 3547 -2968 3181 -3190 3391 -2994 3393 -3002 3403 -2994 3401 -3002 3393 -3004 3393 -3002 3393 -3002 3403 -2994 3401 -3002 3393 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -3006 1799 -1394 1791 -1398 1801 -1400 3403 -3002 3401 -1398 1791 -2998 3403 -3002 1795 -1398 1801 -1400 1801 -1400 3407 -1400 1791 -2996 3405 -2994 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 3391 -3002 1799 -1402 3401 -1402 1799 -1398 1791 -3000 1799 -1402 1801 -1400 3595 -1062 1325 -884 2861 -2628 3677 -2784 3481 -2744 3683 -2912 3513 -2916 3333 -3156 3175 -3182 3191 -3190 3393 -2994 3403 -2994 3401 -3002 3393 -3004 3393 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -2992 1801 -1400 1801 -1400 1801 -1402 3405 -2998 3393 -1402 1795 -2992 3401 -3002 1801 -1400 1795 -1398 1801 -1402 3401 -1396 1793 -1398 1799 -3004 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1398 3401 -3002 1801 -1396 3389 -1402 1801 -1400 1801 -3002 1801 -1396 3391 -6068 219 -1318 1767 -2830 3479 -2936 3489 -2910 3509 -2922 3341 -3162 3175 -3186 3391 -2994 3393 -2998 3407 -2994 3393 -3002 3393 -3004 3401 -3002 3401 -1398 1791 -1394 +RAW_Data: 1797 -1400 1801 -1400 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1801 -1400 3401 -3002 3407 -1400 1789 -2990 3401 -3004 1799 -1402 1799 -1402 1795 -1394 3397 -1402 1801 -1400 1801 -1400 1801 -2994 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 3401 -3002 1797 -1398 3401 -1396 1797 -1402 1799 -3002 3403 -2994 4221 -2588 2113 -3134 3299 -3086 3259 -3026 3409 -3002 3407 -3006 3397 -3006 3393 -3002 3395 -3002 3393 -3002 3407 -2998 3393 -3002 3393 -3004 3401 -1396 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1801 -1400 1801 -1396 1793 -1398 3401 -3002 3401 -1402 1795 -2992 3401 -3002 1801 -1396 1797 -1402 3401 -3002 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 3401 -3006 1795 -1394 3391 -1400 1801 -1400 1801 -3002 3393 -1402 1801 -3802 207 -2344 219 -1326 1669 -2836 3513 -3130 3147 -3176 3181 -3186 3391 -2994 3393 -3002 3395 -3002 3401 -2994 3401 -3004 3393 -3002 3399 -3004 3395 -2994 3401 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -3002 1795 -1396 1795 -1402 1799 -1402 3401 -3002 3403 -1396 1791 -3000 3407 -3004 1797 -1394 1791 -1398 3401 -3002 1801 -1400 1797 -1394 3397 -3002 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 +RAW_Data: 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 3401 -2998 1805 -1396 3391 -1400 1801 -1402 1799 -1398 1791 -3000 1799 -1402 3607 -4140 2069 -2820 3359 -2938 3533 -2914 3513 -2916 3337 -3160 3173 -3184 3393 -2998 3389 -2996 3393 -3002 3393 -3002 3403 -2994 3401 -3002 3395 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -3002 1799 -1398 1797 -1400 1801 -1400 3395 -3002 3401 -1398 1791 -2998 3403 -3002 1799 -1402 1801 -1396 3391 -3002 1799 -1402 3401 -3002 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 3399 -3002 1799 -1402 3401 -1402 1795 -1394 1797 -1400 1801 -3002 3401 -7030 2161 -3078 3391 -2994 3389 -2996 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3401 -2996 3401 -2994 3401 -3002 3403 -2994 3393 -3002 3403 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -3006 1799 -1394 1791 -1398 1801 -1400 3403 -2994 3401 -1402 1799 -2994 3403 -3002 1799 -1398 1791 -1398 3403 -3002 1799 -1402 3401 -1398 1791 -2998 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1396 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -3002 1799 -1402 3393 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -3002 3795 -3692 2201 -2812 3459 -2876 3485 -3104 3309 -2934 3359 -3176 3181 -3190 3395 -2994 3393 -3006 3399 -2994 3401 -2994 3407 -3006 3389 -2994 3401 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -3002 1801 -1398 1791 -1398 +RAW_Data: 1801 -1400 3401 -3004 3393 -1400 1801 -3002 3399 -3006 1795 -1394 1797 -1400 3401 -2994 3403 -2994 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 3401 -3004 1799 -1402 3401 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -3394 399 -3496 2327 -2200 3995 -2554 3791 -2544 3685 -2710 3691 -2920 3333 -3156 3373 -2984 3391 -2996 3389 -2996 3401 -2994 3401 -2996 3405 -3002 3397 -1398 1791 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -3002 1801 -1398 1791 -1398 1801 -1400 3401 -3002 3395 -1400 1801 -3002 3401 -2996 1795 -1398 1799 -1402 3401 -2994 3403 -3002 3393 -3002 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 3401 -3002 3403 -3002 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 3593 -4356 1945 -2932 3435 -3014 3415 -3004 3401 -3004 3393 -3002 3401 -2994 3407 -3006 3393 -2994 3395 -3002 3401 -3002 3399 -3004 3395 -2994 3407 -1400 1789 -1392 1797 -1400 1801 -1400 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1801 -1400 3407 -3004 3395 -1396 1793 -2998 3401 -3004 1799 -1398 1791 -1398 3401 -3002 3403 -1396 1791 -3000 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 +RAW_Data: 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 3401 -3002 3407 -3006 1795 -1394 1791 -1398 1801 -1400 1801 -1402 3401 -4768 389 -390 193 -2086 1793 -2908 3435 -3014 3409 -3002 3407 -3006 3401 -3002 3393 -2996 3401 -3002 3407 -2996 3395 -3002 3393 -3002 3393 -3004 3393 -3002 3401 -1398 1797 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1801 -1400 3401 -3002 3395 -1400 1797 -2998 3401 -3004 1799 -1398 1791 -1398 3401 -3002 3403 -1396 1797 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -1402 3393 -3002 3403 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3593 -1506 4053 -3028 3495 -2918 3323 -3148 3167 -3182 3185 -3192 3389 -2994 3401 -3004 3393 -3002 3401 -2994 3395 -3002 3401 -3002 3395 -3002 3393 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -3002 1801 -1400 1801 -1402 1799 -1402 3393 -3002 3401 -1402 1795 -2992 3401 -3002 1801 -1400 1801 -1398 3389 -1400 1801 -3002 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 3397 -3002 3401 -3002 1801 -1398 1795 -1402 1801 -1400 3393 -1402 1801 -5898 771 -378 2029 -2840 3559 -2776 3585 -2986 3395 -2994 3393 -3002 3403 -3002 3393 -3002 3393 -3004 3393 -3002 3401 -2998 3407 -2994 3401 -2994 3395 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -3002 1799 -1402 1801 -1396 1791 -1398 3403 -3002 3401 -1398 1795 -3002 3403 -2994 1799 -1402 +RAW_Data: 1795 -1398 3401 -1402 1801 -3002 1795 -1394 3403 -3004 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 3403 -3002 3401 -2994 1801 -1400 1795 -1400 3405 -3006 1795 -1394 3591 -3806 2201 -2824 3453 -2878 3493 -2908 3521 -2926 3349 -3164 3177 -3190 3387 -2990 3393 -2996 3401 -3006 3397 -2994 3403 -2994 3401 -2994 3401 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1801 -3002 1795 -1398 1801 -1400 1795 -1398 3407 -3006 3393 -1398 1791 -2998 3403 -3002 1799 -1398 1791 -1398 3401 -1402 1801 -3002 3401 -2994 1801 -1400 1797 -1398 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 3401 -2996 3401 -3002 1795 -1394 1797 -1402 3401 -3002 3401 -5912 1929 -3004 3419 -3010 3411 -2996 3395 -2994 3401 -3002 3401 -2994 3407 -2998 3393 -2994 3403 -3002 3393 -3002 3401 -2996 3401 -2994 3401 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1801 -1400 3401 -3002 3403 -1396 1793 -2998 3401 -3002 1797 -1394 1795 -1402 3401 -1402 1799 -3004 3401 -1396 1793 -2998 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 +RAW_Data: 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 3401 -2994 3403 -2994 1801 -1400 1801 -1400 3395 -1400 1801 -2994 3401 -2922 1031 -1104 1767 -3090 3163 -3166 3183 -3186 3393 -2994 3395 -3002 3401 -2994 3403 -3002 3397 -3006 3393 -2996 3401 -2994 3401 -2994 3403 -3002 3399 -1404 1795 -1394 1791 -1398 1801 -1400 1801 -1400 1801 -3002 1795 -1400 1799 -1402 1799 -1402 3407 -2996 3395 -1400 1795 -2992 3401 -3002 1801 -1402 1799 -1398 3389 -1402 1799 -1402 1799 -3004 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 3401 -3002 3403 -2994 1799 -1398 1797 -1400 3407 -1400 1791 -1394 1797 -8408 1655 -3216 3289 -3110 3319 -3136 3159 -3176 3185 -3200 3197 -3194 3389 -2996 3393 -2994 3401 -3002 3403 -2994 3401 -2994 3403 -3002 3397 -1404 1797 -1394 1795 -1402 1795 -1398 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -3002 1795 -1398 1801 -1402 3401 -1396 1793 -1398 1799 -3004 3405 -3006 1795 -1394 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3393 -3002 3401 -2996 1799 -1402 3401 -3002 1795 -1394 1793 -1398 4403 -1594 579 -948 2021 -2944 3439 -3026 3417 -3002 3411 -3002 3401 -3002 3393 -3004 3401 -2994 3407 -2996 3399 -3006 3393 -2994 3395 -3002 3401 -2994 3401 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1394 1797 -1400 1801 -1400 3401 -3004 3393 -1400 1801 -3002 3395 -3002 1799 -1402 1795 -1394 3397 -1402 1801 -1400 1801 -1400 1801 -2994 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 +RAW_Data: 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 3401 -3004 3397 -3006 1795 -1394 3391 -3002 1799 -1402 3401 -7960 1797 -3000 3435 -3014 3415 -3004 3407 -3006 3393 -2994 3407 -3002 3397 -2994 3393 -3004 3393 -3002 3401 -2994 3403 -3002 3393 -3002 3393 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -3002 1799 -1402 1795 -1394 1797 -1400 3403 -3002 3405 -1400 1793 -2990 3403 -3002 1799 -1402 1795 -1398 3401 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -3002 1801 -1402 1795 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 3407 -3006 3393 -2994 1801 -1396 3391 -3006 3405 -2994 3803 -4598 1425 -3262 3367 -2984 3185 -3190 3391 -2994 3405 -3006 3393 -2996 3401 -2994 3393 -3002 3403 -2994 3401 -3002 3393 -3004 3401 -2994 3401 -1398 1797 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -3002 1801 -1402 1799 -1402 1795 -1394 3397 -3004 3401 -1400 1801 -2994 3401 -3004 1795 -1394 3397 -3002 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 +RAW_Data: 1791 -1398 1801 -1400 3401 -3002 3403 -2994 1799 -1402 3401 -2994 3407 -1400 1791 -4212 203 -2976 1877 -3038 3175 -3164 3353 -2932 3519 -3106 3309 -3122 3147 -3168 3183 -3182 3389 -2994 3395 -3002 3393 -3002 3395 -3006 3397 -2994 3401 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1394 1797 -1400 1801 -1400 3403 -2998 3405 -1396 1793 -2998 3403 -3002 1799 -1398 3397 -3002 1797 -1398 1799 -1402 1799 -1402 3407 -2996 1797 -1394 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -3002 3401 -3002 1795 -1394 3399 -1400 1801 -3002 1801 -1396 3397 -804 201 -2984 1719 -3010 3487 -2908 3515 -3134 3147 -3168 3183 -3186 3389 -2998 3399 -2994 3393 -3002 3407 -2998 3393 -2994 3401 -3004 3401 -2994 3393 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -2998 1805 -1398 1791 -1394 1797 -1400 3401 -3002 3403 -1400 1801 -2994 3401 -3002 1797 -1394 3397 -3002 1801 -1400 1801 -1402 3401 -2994 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 3393 -3002 3403 -2994 1799 -1402 3393 -1402 1799 -3004 3393 -3202 803 -3626 2215 -2456 3759 -2776 3585 -2990 3391 -2994 3393 -3002 3403 -2994 3401 -3002 3393 -3004 3393 -3006 3397 -2994 3403 -2994 3401 -3002 3395 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -3002 1799 -1402 1795 -1394 1797 -1400 3407 -3006 3393 -1398 1795 -3002 3403 -3002 1795 -1394 3397 -3002 1801 -1402 1799 -1398 3389 -1402 1799 -3002 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 +RAW_Data: 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 3403 -3002 3393 -3002 1801 -1400 3395 -1400 1801 -1396 1797 -3002 4211 -4018 1715 -2938 3433 -3018 3411 -3010 3401 -3002 3401 -3002 3407 -2998 3393 -3002 3395 -3002 3393 -3002 3393 -3004 3401 -3002 3393 -3002 3395 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -3002 1799 -1402 1795 -1394 1797 -1400 3403 -3002 3401 -1402 1795 -2992 3401 -3002 1801 -1400 3401 -2994 1801 -1402 3393 -3002 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 3403 -3002 3401 -3002 1795 -1394 3403 -1404 1795 -1394 1797 -1402 1799 -4574 383 -2458 2107 -3020 3263 -3042 3423 -3010 3405 -3006 3401 -3002 3407 -2998 3393 -2994 3403 -3002 3393 -3002 3393 -3004 3401 -2994 3401 -2994 3403 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -3006 1805 -1396 1791 -1398 1801 -1402 3401 -3002 3401 -1398 1791 -3000 3405 -3006 1795 -1394 3391 -3002 1799 -1402 3401 -3002 3401 -2996 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 3403 -2994 3401 -3002 3395 -3002 1799 -1398 1791 -1398 1801 -1400 3603 -838 437 -2646 1921 -2808 +RAW_Data: 3533 -2914 3495 -2868 3443 -3022 3417 -3002 3407 -3010 3401 -2998 3393 -2996 3393 -3002 3401 -2994 3403 -3006 3397 -2994 3407 -1400 1789 -1392 1797 -1402 1799 -1402 1799 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3393 -1402 1799 -3002 3395 -3002 1795 -1398 3401 -3002 1797 -1398 3401 -1400 1797 -2994 1805 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 3403 -2994 3401 -3002 3393 -3004 1795 -1398 1799 -1402 3393 -3804 421 -1492 221 -1726 1751 -3022 3331 -3148 3177 -3180 3185 -3194 3199 -3190 3393 -3002 3395 -3002 3393 -3002 3403 -2998 3405 -2998 3397 -2996 3393 -3002 3393 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -3002 1801 -1402 1795 -1394 1797 -1400 3401 -3002 3403 -1396 1793 -2998 3401 -3004 1799 -1402 3393 -3002 1801 -1396 3399 -1400 1801 -1400 1801 -2998 1805 -1396 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 3401 -3002 3395 -3006 3397 -2994 1801 -1402 3401 -2994 3801 -416 429 -2326 1741 -2894 3367 -2982 3385 -2992 3393 -3002 3401 -2994 3403 -2994 3401 -2994 3403 -3002 3405 -2998 3393 -2996 3401 -2994 3401 -3002 3395 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -3002 1799 -1402 1801 -1400 1801 -1400 3395 -3002 3401 -1398 1791 -2998 3403 -3002 1801 -1400 3401 -2994 3403 -2998 1799 -1394 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 +RAW_Data: 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 3403 -2994 3401 -3006 3397 -2996 1799 -1398 3389 -1402 1799 -7642 1653 -2952 3443 -3022 3413 -3014 3411 -3006 3393 -3002 3407 -2996 3395 -2994 3401 -3002 3395 -2994 3401 -3002 3401 -2996 3401 -2994 3407 -1400 1791 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -3006 1801 -1392 1789 -1398 1801 -1400 3401 -3008 3405 -1396 1793 -2990 3403 -3006 1803 -1398 3389 -3002 3403 -2994 1799 -1402 3393 -3002 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 3401 -3004 3393 -3002 3401 -2994 3403 -3002 1795 -1394 4397 -596 1899 -1104 1803 -2886 3411 -3002 3401 -3002 3401 -3002 3403 -3002 3393 -3002 3403 -2998 3405 -2994 3393 -3004 3393 -2994 3401 -3002 3403 -2994 3401 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -3002 1795 -1396 1795 -1402 1799 -1402 3401 -3002 3395 -1400 1801 -3002 3393 -3002 1801 -1398 3389 -3002 3401 -3002 3395 -3002 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 3393 -3002 3401 -3004 3393 -3002 3393 -3002 3403 -3394 2509 -408 609 -1044 209 -420 1601 -3178 3319 -3096 3253 -3022 3419 -3014 3405 -3010 3403 -2996 3395 -2994 3401 -3002 3395 -2998 3405 -2994 3401 -3000 3397 -2994 3401 -1398 1791 -1398 +RAW_Data: 1801 -1400 1801 -1402 1799 -1402 1795 -2992 1799 -1402 1799 -1402 1801 -1396 3397 -3004 3401 -1400 1801 -2994 3401 -3004 1795 -1394 3397 -3002 3403 -3002 3393 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 3397 -3002 3403 -2994 3401 -2994 3403 -1400 1795 -2992 4001 -212 211 -424 845 -2058 1877 -3244 3181 -3188 3389 -2994 3401 -2996 3401 -2994 3401 -2994 3403 -3002 3393 -3002 3395 -3002 3401 -2994 3401 -2994 3403 -3002 3393 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -2990 1801 -1402 1799 -1402 1799 -1402 3401 -2994 3407 -1400 1791 -2992 3401 -3002 1801 -1402 3401 -2994 3401 -1402 1799 -2996 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1394 3397 -3002 3403 -3006 3397 -2994 3401 -1402 1801 -1396 1791 -8006 2651 -1824 3861 -2834 3417 -3014 3407 -3002 3401 -3002 3401 -3002 3395 -3002 3393 -3002 3395 -3006 3405 -2994 3393 -3004 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -2994 1801 -1402 1799 -1398 1791 -1398 3401 -3004 3401 -1400 1801 -2998 3405 -2996 1795 -1394 3397 -3006 3405 -1398 1791 -3000 3401 -2994 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 +RAW_Data: 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 3407 -3004 3395 -3002 3393 -1402 1795 -2992 1799 -1402 1799 -1402 3401 -4546 1981 -2786 3481 -2908 3497 -2922 3337 -3160 3175 -3186 3389 -2994 3399 -2994 3393 -3002 3403 -3002 3393 -2994 3401 -2996 3401 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -2998 1801 -1402 1799 -1398 1797 -1400 3401 -3002 3403 -1400 1801 -2994 3401 -2994 1801 -1402 3401 -2994 3401 -1402 1795 -1394 1797 -3002 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 3401 -3002 3395 -3006 3405 -1398 1789 -2990 1799 -1402 3401 -4586 587 -746 551 -1102 2019 -2888 3497 -2864 3439 -3018 3413 -3002 3401 -3002 3403 -2994 3401 -2998 3407 -2994 3393 -3002 3393 -3004 3401 -2998 3397 -2998 3407 -1396 1791 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3002 3393 -1402 1799 -3004 3393 -3002 1795 -1398 3401 -3004 3405 -1400 1793 -1394 1791 -1398 1801 -3002 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 3403 -2994 3401 -3006 3399 -1396 1791 -2992 3401 -3002 3603 -400 201 -1420 877 -1100 1971 -3176 3319 -2904 3511 -3132 3147 -3168 3181 -3186 3395 -2994 3393 -3002 3393 -3004 3401 -3002 3393 -2994 3403 -3002 3393 -3002 3403 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -2994 1799 -1402 1801 -1396 1797 -1400 3403 -3002 3393 -1402 1795 -2998 3403 -3002 1795 -1394 +RAW_Data: 3397 -1402 1799 -3004 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 3395 -3002 3401 -3002 3393 -1402 1795 -2992 3401 -1400 1801 -5262 401 -2280 2005 -2706 3647 -2842 3423 -3010 3405 -3006 3401 -3002 3403 -2994 3401 -3002 3395 -3002 3401 -2994 3393 -3002 3403 -2998 3405 -2998 3399 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -3000 1801 -1400 1801 -1400 1801 -1396 3391 -3002 3401 -1402 1799 -3002 3395 -3006 1805 -1396 3389 -1402 1801 -3002 1795 -1394 1797 -1400 3401 -3004 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 3391 -3002 3401 -3002 3407 -1404 1793 -1392 1793 -2998 1801 -1400 3603 -2686 1231 -664 1505 -3148 3313 -3126 3149 -3166 3175 -3190 3193 -3192 3393 -2994 3401 -2996 3401 -3006 3397 -2998 3399 -2994 3401 -2994 3403 -3002 3401 -1396 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3006 3397 -1402 1795 -2996 3405 -2998 1805 -1396 3391 -1400 1801 -2994 1801 -1400 3403 -2994 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 +RAW_Data: 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 3401 -3002 3407 -3006 3393 -1396 1793 -1398 1799 -3002 3403 -3602 861 -1102 1545 -442 1983 -3002 3277 -3092 3513 -3124 3147 -3168 3173 -3194 3195 -3190 3393 -3002 3395 -3006 3397 -2994 3395 -3002 3401 -2998 3405 -3000 3397 -1396 1793 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -3002 1801 -1400 1801 -1400 1801 -1398 3401 -3006 3393 -1402 1795 -2992 3401 -3002 1801 -1400 3395 -1400 1801 -3002 1795 -1394 3399 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 3401 -3002 3401 -3002 3403 -1396 1793 -1398 1799 -1402 1799 -3004 3593 -610 3645 -2950 3285 -3122 3311 -3116 3323 -3138 3163 -3174 3187 -3194 3397 -2996 3393 -2994 3401 -2994 3403 -3002 3393 -3002 3401 -2996 3401 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -3002 1795 -1394 3399 -1400 1801 -3002 3401 -2994 1801 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 3401 -3002 3393 -2994 3403 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -4212 1599 -1486 1653 -3012 3347 -3168 3181 -3188 3389 -2994 3395 -2994 3401 -3002 3401 -2996 3393 -3002 3401 -3002 3395 -3002 3399 -3004 3393 -2996 3401 -1396 1797 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3399 -1404 1795 -2996 3405 -2994 1801 -1396 3391 -1400 1801 -3002 3401 -2996 3401 -3006 1799 -1392 1789 -1398 1801 -1402 1799 -1402 +RAW_Data: 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 3401 -2994 3401 -1402 1795 -2992 1801 -1400 1801 -1400 1801 -1400 1801 -1402 4617 -3624 1617 -3122 3183 -3190 3389 -2994 3403 -2998 3405 -2994 3393 -3004 3393 -3006 3397 -2994 3403 -2994 3401 -3002 3395 -3002 3401 -2994 3401 -1402 1795 -1398 1801 -1400 1797 -1394 1795 -1402 1799 -3004 1799 -1402 1799 -1398 1791 -1398 3403 -3002 3401 -1400 1801 -3002 3393 -3004 1795 -1394 3397 -1402 1799 -3002 3403 -1400 1795 -2992 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 3401 -3004 3401 -1400 1797 -2990 1801 -1400 1801 -1402 1799 -1402 3401 -3200 601 -3982 1955 -2718 3687 -2842 3425 -3016 3405 -3006 3401 -3002 3403 -2994 3401 -3002 3393 -2996 3401 -3006 3397 -2998 3407 -2994 3393 -3006 3399 -1396 1791 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -3002 1795 -1398 1801 -1400 1801 -1400 3403 -2998 3405 -1398 1791 -2992 3401 -3006 1799 -1394 3391 -1400 1801 -3002 3401 -1402 1799 -1398 1791 -3000 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 +RAW_Data: 1799 -1402 1801 -1400 1801 -1400 1795 -1394 3399 -3002 3401 -1402 1795 -2998 1801 -1402 1799 -1398 3389 -3002 3603 -608 209 -3446 2219 -2994 3443 -3026 3417 -3002 3407 -3008 3399 -2998 3405 -2994 3395 -2998 3405 -2994 3395 -3002 3405 -2998 3393 -3002 3395 -2994 3401 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -3002 1801 -1402 1799 -1402 1799 -1402 3393 -3002 3403 -1396 1797 -2994 3401 -3002 1801 -1398 3393 -1406 1799 -1402 1795 -3000 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 3389 -3002 3403 -1400 1801 -3002 1795 -1394 1797 -1400 3403 -1400 1801 -5432 663 -1710 1925 -2726 3617 -3010 3419 -3006 3401 -3002 3401 -2998 3407 -2994 3393 -3002 3403 -2994 3401 -3002 3393 -3004 3393 -2994 3401 -3002 3403 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1398 1797 -3002 1801 -1400 1795 -1398 1801 -1400 3403 -2994 3401 -1402 1795 -2992 3401 -3002 1801 -1400 3401 -1398 1791 -1398 1801 -3002 1801 -1400 3401 -3004 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 3391 -3002 3401 -1402 1799 -3002 1801 -1402 3393 -2994 1801 -1400 3603 -3858 2219 -3186 3253 -3036 3417 -3006 3405 -3002 3403 -2998 3405 -2994 3401 -2996 3401 -2998 3405 -2994 3395 -2994 3401 -3002 3395 -3002 3401 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -2998 1799 -1394 1797 -1402 1799 -1402 3401 -2998 3405 -1398 1791 -2992 3401 -3002 1801 -1400 3403 -1400 1795 -1396 1795 -3002 3403 -3002 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 +RAW_Data: 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 3405 -3002 3397 -1398 1791 -2992 1801 -1400 3401 -3002 3395 -6072 1197 -792 1865 -2724 3513 -2896 3455 -3034 3419 -3002 3401 -3002 3401 -3004 3401 -2994 3401 -2998 3407 -2994 3401 -2994 3403 -2994 3401 -3002 3393 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -2992 1799 -1402 1799 -1402 1801 -1400 3401 -3000 3405 -1396 1793 -2990 3407 -3006 1795 -1394 3397 -1402 1799 -1402 1801 -3002 3393 -1400 1797 -2998 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1398 1797 -1400 3401 -3004 3393 -1400 1801 -3002 1795 -1394 3399 -1400 1801 -3002 4189 -3552 1729 -2986 3429 -3022 3419 -3006 3393 -3002 3399 -3004 3395 -2994 3401 -3002 3395 -3002 3393 -3006 3397 -3000 3405 -2994 3401 -2994 3395 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -3002 1801 -1400 3395 -1400 1801 -1400 1795 -1394 1797 -3002 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 3395 -3002 3393 -1402 1799 -3002 1797 -1394 +RAW_Data: 3397 -1402 1799 -1402 1799 -7326 2401 -2060 4155 -2504 3723 -2690 3661 -2838 3421 -3010 3411 -3002 3401 -3002 3401 -3002 3403 -2994 3401 -3002 3401 -2996 3393 -2994 3401 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -3004 1799 -1398 1795 -1402 1801 -1400 3401 -3004 3393 -1400 1801 -2994 3401 -3004 1795 -1394 3397 -1402 1799 -1402 1799 -1398 1791 -3000 3401 -3002 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 3401 -3002 3403 -1396 1791 -3000 3401 -3004 1799 -1398 1791 -1398 3601 -4120 1733 -2886 3559 -2960 3351 -3094 3255 -3044 3421 -3010 3401 -3006 3407 -3002 3393 -3002 3393 -3004 3401 -3002 3393 -3002 3395 -3002 3401 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -2998 1801 -1400 1801 -1398 1791 -1398 3401 -3002 3403 -1400 1795 -2992 3401 -3002 1801 -1400 3403 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -2994 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3393 -1402 1801 -3002 3393 -3002 1801 -1396 3399 -5588 365 -1116 2145 -3134 3189 -3190 3395 -2994 3401 -3002 3395 -3002 3393 -3002 3401 -2996 3401 -3002 3393 -3002 3395 -3002 3401 -2998 3405 -2996 3393 -1400 1797 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -3002 1801 -1396 3391 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -2992 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 +RAW_Data: 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 3401 -3002 3393 -1402 1795 -3000 3401 -3002 3393 -3004 3593 -3932 2743 -2594 3595 -3002 3393 -3002 3395 -3002 3401 -2994 3401 -2996 3401 -3002 3401 -2994 3403 -2994 3401 -2994 3403 -2998 3405 -2994 3393 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -3000 1799 -1402 1799 -1402 1801 -1400 3401 -2996 3401 -1400 1797 -2990 3403 -3002 3401 -3002 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 3393 -3004 3401 -1396 1793 -2998 3401 -3004 3401 -1396 1793 -7038 2817 -3032 3167 -3182 3385 -2996 3393 -2994 3401 -3002 3399 -3006 3393 -2994 3403 -2994 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3407 -1404 1795 -1394 1793 -1398 1799 -1402 1799 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3395 -3002 3401 -1398 1795 -3002 3403 -2994 3401 -3002 1801 -1396 1793 -1398 1799 -1402 1801 -1400 3401 -3004 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -3002 3401 -1402 1795 -2990 3403 -1400 1801 -3002 1801 -1396 3591 -4298 1767 -2654 3559 -2912 3513 -2914 3491 -2868 3443 -3022 3417 -3002 3407 -3006 3393 -3002 +RAW_Data: 3393 -3002 3403 -2994 3407 -3004 3395 -2994 3399 -1404 1795 -1394 1797 -1400 1801 -1400 1801 -1396 1793 -2998 1801 -1400 1801 -1402 1795 -1398 3401 -3006 3399 -1400 1795 -2992 3401 -3002 3403 -2994 1799 -1402 1801 -1396 1791 -1398 3403 -3002 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3401 -3002 3395 -1396 1797 -3002 3407 -1404 1795 -2992 3401 -3400 1713 -1100 3677 -3172 3377 -2982 3187 -3190 3393 -2996 3401 -2994 3401 -3002 3395 -3002 3399 -3004 3393 -2996 3401 -3002 3393 -3002 3395 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -2998 1801 -1402 1799 -1398 1791 -1398 3401 -3002 3403 -1400 1795 -2992 3401 -3002 3403 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 3401 -3002 3403 -1396 1791 -3000 3401 -1402 1799 -1402 1795 -3000 3801 -1120 181 -920 553 -1654 1653 -3052 3481 -2942 3489 -2908 3299 -3120 3335 -3164 3175 -3182 3389 -2996 3393 -3002 3401 -2996 3393 -3002 3401 -2994 3403 -3002 3393 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -3002 1801 -1400 1797 -1394 1795 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -3002 3403 -3006 1599 -1592 1789 -1398 3401 -3004 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -1396 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 +RAW_Data: 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 3401 -3002 3401 -1398 1797 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -3402 1057 -3748 1469 -3298 3149 -3174 3175 -3190 3393 -2994 3395 -3002 3393 -3002 3403 -3002 3393 -3002 3399 -3004 3395 -2994 3401 -2994 3403 -2994 3401 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -3002 1801 -1400 1797 -1394 1795 -1402 3401 -3002 3395 -1400 1801 -3002 3401 -2994 3403 -2994 1799 -1402 1801 -1400 3393 -3004 3393 -3002 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3401 -3002 3393 -1402 1801 -1400 1795 -2992 1801 -1400 1801 -1400 1801 -1402 3601 -3262 435 -874 1833 -3302 3235 -3018 3405 -3002 3407 -2998 3393 -3002 3393 -3002 3399 -3006 3393 -2994 3403 -3002 3393 -3002 3393 -3008 3397 -3002 3393 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -3002 1801 -1402 1799 -1402 1801 -1396 3403 -3004 3395 -1396 1793 -2998 3401 -3004 3401 -2994 1801 -1400 1795 -1394 3399 -1400 1801 -3002 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1801 -1400 3401 -2994 3403 -1396 1797 -1400 1801 -3002 1795 -1396 1795 -1402 3401 -7588 1923 -3068 3393 -2994 3403 -2994 3407 -3004 3399 -2998 3393 -2994 3393 -3004 3401 -2994 3401 -3002 3403 -2994 3393 -3002 3403 -2998 3409 -1400 1789 -1394 1795 -1402 1801 -1400 +RAW_Data: 1801 -1400 1797 -2998 1801 -1400 1797 -1394 1795 -1402 3401 -3002 3403 -1400 1801 -2994 3407 -2996 3395 -3002 1795 -1394 1797 -1400 3401 -1402 1801 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 3401 -3002 3401 -1398 1791 -1398 1801 -3002 1801 -1400 3401 -2996 3607 -1728 833 -1396 2303 -2880 3581 -2986 3391 -2994 3393 -3002 3395 -3002 3401 -2998 3405 -2996 3393 -2994 3401 -3002 3403 -2994 3401 -3002 3395 -3002 3393 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3407 -1400 1791 -2992 3401 -3002 3407 -2998 1795 -1394 3389 -3002 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 3407 -2996 3395 -1400 1795 -1398 1801 -3002 1801 -1400 3395 -1400 1801 -7606 1737 -3220 3235 -3022 3417 -3002 3407 -3004 3403 -2994 3401 -2994 3407 -3006 3393 -2994 3393 -3004 3401 -2994 3393 -3002 3403 -3002 3393 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -3002 1801 -1400 1797 -1394 1795 -1402 3401 -3002 3407 -1400 1789 -2990 3401 -3002 3403 -3002 1799 -1398 3389 -3002 1801 -1402 3401 -3002 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 +RAW_Data: 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 3401 -3002 3401 -1402 1795 -1394 1797 -3002 3401 -3002 1801 -1398 4195 -1886 1105 -442 1765 -3046 3269 -3160 3341 -3122 3291 -3112 3319 -3140 3163 -3176 3185 -3190 3391 -2994 3393 -2998 3411 -2998 3393 -3002 3393 -3004 3393 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -2992 1801 -1400 1801 -1400 1801 -1402 3401 -2994 3401 -1402 1795 -2992 3401 -3002 3401 -3004 1795 -1394 3397 -3002 3401 -3004 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 3401 -3002 3407 -1400 1791 -1394 1797 -3002 3401 -3002 3395 -5516 1583 -3012 3489 -2910 3305 -3120 3337 -3164 3173 -3186 3191 -3190 3399 -3004 3395 -2994 3401 -2994 3403 -2994 3401 -2994 3401 -3004 3393 -1400 1801 -1402 1795 -1398 1799 -1402 1795 -1398 1801 -3002 1801 -1400 1795 -1394 1797 -1402 3405 -3006 3393 -1402 1795 -2992 3401 -3002 3401 -3002 1797 -1394 3397 -3002 3407 -1404 1795 -2992 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 3401 -3002 3401 -1398 1791 -1398 1801 -3002 3401 -1398 1795 -3002 3595 -3624 415 -206 2483 -2414 3585 -3002 3401 -2994 3401 -3004 3393 -2994 3401 -3002 3403 -2998 3411 -2996 3395 -2994 3393 -3002 3393 -3004 3401 -2994 3401 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 3407 -3004 3399 -1400 1789 -2990 3403 -3002 3401 -3002 1795 -1394 3403 -1404 1795 -2992 1801 -1400 1801 -1400 1801 -1402 1795 -1394 +RAW_Data: 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 3389 -3004 3401 -1400 1801 -1402 1799 -2994 3403 -1400 1795 -1398 1801 -8014 1843 -2840 3389 -2994 3403 -2994 3401 -3002 3393 -3002 3395 -3002 3401 -2994 3403 -2994 3401 -2994 3407 -3006 3393 -2994 3401 -2998 3399 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1402 3405 -3006 3393 -1398 1791 -3000 3405 -3006 3393 -2994 1801 -1398 3389 -1402 1799 -3002 3403 -3002 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 3401 -2994 3401 -1398 1795 -1402 1801 -1400 1801 -2994 1801 -1400 1801 -1400 3395 -4724 1853 -2864 3547 -2976 3181 -3186 3391 -2994 3393 -2994 3407 -3006 3399 -2996 3399 -2998 3393 -3002 3399 -3006 3393 -2994 3401 -2994 3403 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -3002 1795 -1398 1801 -1400 1801 -1396 3391 -3002 3401 -1402 1799 -3004 3393 -3002 3401 -2994 1801 -1402 3393 -1400 1797 -1398 1799 -3002 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 +RAW_Data: 1799 -1402 1799 -1402 1795 -1398 1801 -1400 3403 -2994 3401 -1402 1795 -1398 1801 -1400 1801 -3002 1795 -1394 3397 -5708 365 -1470 9113 -1824 3823 -2614 3609 -3002 3403 -3002 3401 -3002 3401 -2994 3403 -3002 3393 -3002 3399 -3006 3393 -2994 3401 -3004 3393 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3002 3393 -1402 1801 -3002 3393 -3006 3397 -2996 1799 -1398 3397 -1402 1799 -1402 1799 -1398 1791 -3000 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1795 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 3397 -3002 3407 -1404 1795 -1394 1791 -1398 1801 -3002 3401 -2996 3601 -1690 629 -2154 1905 -2832 3651 -2830 3423 -3006 3401 -3002 3401 -3002 3395 -3002 3401 -3002 3395 -3002 3405 -2998 3393 -2996 3401 -3002 3407 -2996 3395 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1396 1797 -3002 1801 -1400 1795 -1394 1797 -1402 3401 -3002 3401 -1402 1795 -2996 3409 -2998 3393 -2994 3403 -3002 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 3401 -3002 3393 -1402 1799 -1398 1791 -1398 1801 -3002 3401 -1402 1795 -3600 639 -3748 1839 -2644 3729 -2756 3567 -2982 3391 -2990 3393 -2994 3403 -3002 3401 -2994 3401 -2994 3403 -3002 3393 -3002 3403 -2994 3393 -3002 3401 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1394 1797 -1400 1801 -1400 3401 -3004 3397 -1404 1797 -2990 3403 -3002 3405 -2998 3393 -2996 1799 -1398 1795 -1402 3401 -3002 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 +RAW_Data: 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 3401 -2996 3401 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -3000 1801 -1400 3801 -4494 1987 -2568 3839 -2822 3413 -3002 3403 -3002 3401 -3002 3401 -3002 3407 -3010 3393 -2994 3395 -3002 3393 -3002 3401 -2996 3401 -2994 3401 -1398 1797 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1801 -1400 3401 -3002 3403 -1396 1793 -2998 3401 -3004 3393 -3002 3401 -3002 1797 -1394 3389 -3002 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 3401 -3002 3395 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -3002 3405 -8042 1841 -2856 3557 -2932 3531 -2910 3509 -2922 3345 -3160 3173 -3188 3395 -2996 3391 -2994 3401 -3002 3399 -2998 3393 -3002 3401 -2994 3395 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3002 3407 -1400 1791 -2992 3401 -3002 3401 -3002 3403 -2994 1795 -1398 3407 -1404 1795 -2992 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 3395 -3002 3393 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -2994 3603 -4452 +RAW_Data: 1771 -2854 3567 -2986 3389 -2992 3393 -3002 3393 -3004 3393 -3002 3401 -2994 3395 -3002 3401 -3002 3393 -3004 3393 -3002 3401 -2994 3403 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -3002 1795 -1398 1801 -1400 1795 -1400 3401 -3002 3393 -1402 1799 -3004 3393 -3002 3401 -2994 3403 -2994 3401 -3002 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -3002 3407 -1404 1795 -1394 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -7856 8207 -2522 3741 -2764 3573 -2988 3393 -2994 3393 -3004 3393 -3002 3393 -3002 3403 -2994 3401 -3006 3399 -2994 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -2992 1799 -1402 1799 -1402 1801 -1400 3401 -2996 3401 -1400 1797 -2990 3403 -3002 3401 -3002 3401 -2994 3395 -3002 3401 -2998 1805 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 3401 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 3601 -4768 1587 -3096 3397 -2990 3395 -2994 3401 -3002 3395 -3006 3397 -2994 3401 -2996 3401 -3002 3393 -3002 3395 -3002 3401 -2994 3403 -3002 3393 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3393 -1402 1801 -3002 3401 -2998 3399 -2994 3401 -2994 3401 -1402 1795 -3000 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 +RAW_Data: 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3401 -1402 1799 -2994 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 3403 -5196 383 -1652 1837 -3050 3375 -2986 3393 -2996 3393 -3002 3401 -2994 3403 -2998 3405 -2994 3395 -3002 3405 -2998 3393 -2996 3401 -3002 3393 -3006 3399 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -3000 1801 -1400 1801 -1400 1801 -1400 3395 -3002 3407 -1400 1791 -2992 3401 -3002 3401 -3002 3395 -3002 3393 -1402 1799 -1398 1795 -3004 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 3403 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1402 1799 -1402 3401 -2994 3603 -836 655 -2854 1731 -2816 3487 -2910 3517 -2910 3481 -2856 3443 -3016 3407 -3006 3401 -3006 3399 -2994 3393 -3006 3397 -2996 3393 -3002 3401 -3002 3395 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -3002 1795 -1398 1801 -1400 1801 -1400 3395 -3002 3401 -1398 1791 -3000 3401 -3002 3401 -2994 3407 -1404 1795 -2992 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 3403 -1400 1795 -2992 1801 -1400 1801 -1400 1801 -1402 1799 -1398 3389 -1402 1799 -7638 2209 -2584 3689 -2704 3511 -2934 3347 -3168 3179 -3186 3389 -2994 3395 -2994 3401 -3002 3393 -3004 3393 -3002 +RAW_Data: 3401 -2994 3403 -2994 3401 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -3002 1801 -1398 1791 -1398 1799 -1402 3401 -3002 3395 -1400 1801 -3002 3407 -3000 3399 -2994 3393 -1402 1795 -2992 1799 -1402 3401 -3002 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 3401 -1402 1799 -3004 1799 -1402 1795 -1394 1797 -1400 3401 -3004 1799 -1402 3601 -4312 1887 -2802 3527 -2906 3523 -3128 3147 -3164 3181 -3188 3389 -2994 3395 -2994 3401 -3002 3393 -3004 3393 -3002 3393 -3002 3403 -3002 3393 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3403 -1396 1797 -3002 3407 -2996 3395 -2994 3401 -1402 1795 -2998 3395 -3006 1803 -1398 1791 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3401 -1398 1791 -3000 1799 -1402 1799 -1402 1801 -1400 3401 -2996 3401 -7934 8393 -2332 3759 -2774 3583 -2990 3389 -2994 3403 -3002 3393 -3002 3393 -3004 3393 -3002 3401 -2994 3403 -3002 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -2994 1799 -1402 1795 -1394 1797 -1400 3403 -3002 3401 -1398 1791 -2998 3403 -3006 3405 -2998 3397 -1398 1791 -3000 3401 -1402 1799 -2994 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 +RAW_Data: 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1396 3391 -1400 1801 -3006 1805 -1396 1791 -1398 1801 -1402 3401 -1396 1797 -3002 3603 -4584 1767 -2612 3777 -2734 3539 -2912 3505 -2916 3331 -3156 3173 -3182 3187 -3190 3393 -2996 3401 -3002 3401 -2994 3395 -3002 3401 -2994 3407 -1400 1791 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -2994 1799 -1402 1801 -1396 1797 -1400 3403 -3002 3401 -1398 1791 -2990 3403 -3002 3401 -3002 3401 -1398 1791 -1398 1801 -3006 1805 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -1400 1801 -3002 1801 -1396 1797 -1400 1801 -1400 3395 -1400 1801 -1398 1795 -8110 2015 -2632 3843 -2818 3415 -3002 3407 -3004 3401 -2996 3401 -3002 3393 -3002 3395 -3002 3401 -2994 3403 -2998 3405 -2994 3393 -3004 3393 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -3002 1801 -1396 1797 -1400 1801 -1402 3401 -2994 3401 -1402 1801 -3002 3393 -2994 3401 -3002 3395 -1400 1801 -1402 1799 -2994 3407 -2998 1795 -1394 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 3397 -1400 1801 -3002 1801 -1396 1793 -1398 3401 -3002 1795 -1398 1801 -1400 3603 -4032 1885 -2658 3649 -2852 3473 -2950 3571 -2718 3513 -2898 3455 -3040 3421 -3010 3401 -3006 3411 -2998 3393 -3002 3395 -3002 3393 -3002 3393 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -3008 1799 -1394 1791 -1398 1801 -1400 3401 -3004 3401 -1396 +RAW_Data: 1793 -3002 3407 -2994 3401 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 3401 -1402 1801 -2998 1803 -1398 1791 -1394 3399 -3002 1799 -1402 3401 -8194 21409 -2410 3595 -3000 3401 -3002 3403 -3006 3405 -2994 3395 -3002 3401 -2994 3401 -3002 3395 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -2990 1801 -1402 1799 -1402 1799 -1402 3401 -2994 3407 -1404 1795 -2992 3401 -3002 3395 -3006 3397 -1398 1791 -1394 1797 -1400 1801 -1400 1801 -3002 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 3393 -1402 1795 -3000 1799 -1402 1799 -1398 3397 -3002 3403 -3002 3593 -4590 8471 -2416 3813 -2802 3403 -3002 3401 -3002 3401 -3004 3401 -3002 3393 -3002 3395 -3002 3401 -2994 3403 -3002 3401 -2994 3393 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1795 -3004 1795 -1398 1799 -1402 1795 -1398 3401 -3004 3401 -1396 1793 -2998 3401 -3004 3401 -1396 1793 -2998 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 +RAW_Data: 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 3397 -1402 1801 -3006 1803 -1398 1791 -1398 3401 -3004 3393 -1400 1801 -6470 1853 -2954 3275 -3044 3425 -3014 3405 -3004 3401 -3002 3401 -3002 3395 -3002 3393 -3002 3401 -2996 3401 -2998 3405 -2994 3395 -3006 3397 -1398 1791 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -3002 1801 -1398 1791 -1398 1801 -1400 3401 -3002 3403 -1396 1791 -3000 3401 -3002 3403 -1396 1793 -2998 1801 -1400 1801 -1402 1799 -1402 3401 -2994 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 3393 -1402 1799 -3000 1803 -1398 1791 -1398 3401 -1402 1799 -3004 1795 -1394 3797 -4442 2001 -2426 3829 -2818 3415 -3014 3401 -3002 3393 -3002 3395 -3002 3401 -3002 3393 -2996 3401 -2994 3401 -3002 3395 -3002 3401 -3002 3395 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -3002 1799 -1398 1791 -1398 1801 -1400 3403 -3002 3393 -1402 1799 -3006 3399 -2994 3401 -1398 1791 -2998 1801 -1402 1799 -1402 3393 -3002 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 3403 -1400 1801 -3002 1801 -1396 1791 -1398 3403 -1400 1801 -3002 3401 -8088 1813 -2902 3441 -3020 3417 -3010 3411 -3004 3399 -3002 3397 -2994 3395 -3002 3393 -3002 3393 -3004 3401 -2998 3405 -2994 3395 -3002 3393 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -3002 1795 -1396 1795 -1402 1799 -1402 3401 -3002 3403 -1400 1795 -2992 3401 -3002 3403 -1400 1795 -2992 1801 -1400 1801 -1400 3403 -1396 1791 -3000 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 +RAW_Data: 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3401 -1402 1799 -3002 1797 -1394 1795 -1402 3401 -1402 1799 -1402 1795 -2992 3601 -4130 1967 -2648 3605 -2874 3687 -2732 3527 -2902 3507 -2930 3349 -3168 3173 -3186 3395 -2998 3397 -2994 3395 -3002 3401 -2994 3401 -3000 3405 -1396 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -3002 3401 -1402 1795 -2992 1799 -1402 3401 -3002 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 3397 -1400 1801 -3002 1801 -1400 1797 -1398 3401 -1400 1801 -1402 1795 -1394 1797 -3402 1061 -2794 2197 -2242 4043 -2320 3991 -2722 3497 -2880 3643 -2830 3415 -3010 3401 -3002 3401 -3002 3403 -3002 3401 -3002 3399 -3006 3393 -2994 3393 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -2992 1799 -1402 1799 -1402 1801 -1400 3407 -2998 3393 -1396 1793 -3002 3407 -3002 3393 -1398 1795 -3002 1801 -1402 3401 -3002 3393 -3002 1797 -1394 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1398 +RAW_Data: 1799 -1398 1797 -1400 3401 -1402 1795 -2992 1801 -1400 3401 -3002 1801 -1402 1799 -1398 1791 -1398 3601 -2170 4255 -2912 3537 -2960 3375 -2986 3189 -3192 3393 -3002 3401 -2994 3403 -3002 3393 -3002 3393 -3004 3393 -3002 3401 -3002 3395 -3002 3393 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -3002 1795 -1396 1795 -1402 1799 -1402 3401 -3006 3399 -1396 1791 -3000 3401 -3002 3403 -1400 1795 -2992 1801 -1400 3401 -1402 1795 -3000 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 3401 -1402 1799 -3002 1797 -1398 3401 -3002 1801 -1396 1793 -1398 3401 -8220 2607 -1888 3817 -2618 3609 -3002 3403 -3002 3401 -3002 3401 -3006 3399 -2994 3401 -2994 3403 -2998 3405 -2994 3393 -3004 3401 -2998 3405 -1398 1791 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -2996 1799 -1402 1799 -1398 1797 -1400 3401 -2996 3401 -1400 1801 -2994 3401 -3004 3393 -1400 1801 -3002 1795 -1394 3399 -1400 1801 -1400 1801 -2994 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 3401 -1398 1791 -3004 1803 -1402 3393 -3002 1795 -1396 3397 -3002 3401 -4962 8235 -2580 3581 -2994 3403 -2994 3401 -2994 3401 -3004 3393 -3002 3393 -3002 3403 -3002 3393 -2994 3403 -3006 3397 -2998 3405 -1398 1791 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1394 1795 -1402 1801 -1400 3401 -2996 3401 -1400 1801 -3002 3395 -3002 3397 -1404 1797 -2990 3403 -3002 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 +RAW_Data: 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 3401 -1398 1791 -3000 1799 -1402 3401 -2998 1805 -1398 3389 -1400 1801 -8008 2567 -1896 3829 -2822 3413 -3014 3407 -3002 3401 -2994 3401 -3002 3395 -3002 3399 -3004 3395 -3002 3399 -3004 3393 -2996 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -3002 1801 -1402 1799 -1402 1795 -1394 3397 -3004 3401 -1400 1797 -2990 3401 -3004 3401 -1400 1801 -2998 3397 -3004 1795 -1394 3397 -3002 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 3403 -1404 1795 -2992 1799 -1402 3401 -2998 3407 -2998 1799 -1394 3791 -4154 1719 -2816 3391 -3170 3285 -3136 3323 -3106 3317 -3134 3147 -3164 3173 -3188 3389 -2994 3395 -3002 3393 -3002 3401 -3002 3395 -3002 3393 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -3006 1801 -1394 1791 -1398 1801 -1400 3401 -3002 3403 -1396 1791 -3000 3401 -3002 3403 -1396 1793 -2998 3401 -3008 3405 -2994 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 3401 -1402 1801 -3002 1799 -1402 3401 -2994 3403 -2994 3405 -8152 1939 -2656 3635 -2818 3409 -3014 3405 -3002 3403 -2994 3401 -2994 +RAW_Data: 3401 -3004 3393 -3002 3401 -2998 3211 -3198 3393 -2994 3395 -3002 3401 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -2990 1801 -1400 1801 -1402 1799 -1398 3397 -3002 3401 -1402 1795 -3000 3401 -2994 3403 -1400 1795 -2992 3401 -3006 3407 -1396 1791 -2996 1805 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3401 -1402 1799 -2994 1801 -1402 3401 -3002 3393 -1398 1797 -3002 3601 -4348 1837 -2790 3659 -2830 3417 -3016 3405 -3002 3401 -3002 3403 -3002 3393 -3002 3401 -2996 3401 -2994 3401 -3002 3395 -3002 3393 -3006 3205 -1598 1791 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -3000 1799 -1398 1797 -1400 1801 -1396 3399 -3002 3401 -1398 1795 -3002 3403 -3002 3393 -1402 1799 -3002 3395 -1400 1801 -2998 1805 -1396 1791 -1398 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 3399 -1400 1801 -2994 1801 -1400 3401 -3002 3395 -1400 1801 -1398 1791 -8144 1783 -2880 3443 -3018 3419 -3004 3403 -3002 3401 -3002 3401 -2996 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3403 -2994 3401 -3002 3393 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1795 -3000 1799 -1402 1799 -1402 1801 -1400 3393 -3004 3401 -1396 1793 -2998 3403 -3002 3401 -1400 1797 -2990 3407 -1404 1795 -2992 3401 -3002 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 +RAW_Data: 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 3397 -1402 1801 -3002 1799 -1398 3397 -1402 1799 -3004 1795 -1394 1797 -1400 4407 -3438 2423 -2508 3661 -2838 3421 -3020 3405 -3002 3401 -3002 3403 -3006 3397 -2994 3393 -3004 3401 -2994 3401 -3002 3403 -2994 3401 -3002 3399 -1400 1791 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3401 -1398 1791 -2998 3403 -3002 3401 -1398 1791 -2998 3403 -1400 1795 -1398 1801 -3002 1795 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 3407 -1400 1791 -2992 1801 -1400 3401 -1402 1801 -2994 1799 -1402 3401 -5710 183 -2022 2537 -1884 3815 -2610 3601 -3002 3401 -3002 3403 -3002 3393 -3002 3403 -2994 3405 -3006 3393 -2996 3393 -3002 3401 -2994 3403 -3002 3393 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3407 -1400 1791 -2996 3405 -2994 3403 -1396 1791 -3000 3401 -1402 1795 -1394 1797 -1400 1801 -3002 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 3397 -1402 1799 -3008 1803 -1398 3395 -1404 1795 -2990 3403 -3002 3593 -4580 1655 -3024 3321 -2950 3563 -2974 3385 -2992 3397 -2998 3393 -3000 3397 -3002 3393 -2996 3401 -3006 3397 -2994 3403 -3002 3399 -3004 3399 -1400 1789 -1392 1797 -1402 1799 -1402 1799 -1402 1801 -3002 +RAW_Data: 1795 -1394 1791 -1398 1801 -1400 3403 -3002 3401 -1402 1799 -2994 3403 -2994 3401 -1402 1799 -1402 1795 -2992 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -1400 1795 -3000 1801 -1400 3401 -1402 1801 -2994 3401 -1400 1797 -7502 3329 -1154 3985 -2602 3601 -3008 3397 -2994 3393 -3002 3407 -2998 3393 -2998 3407 -2994 3401 -2994 3401 -2996 3401 -2994 3401 -2994 3403 -1400 1801 -1396 1797 -1402 1799 -1398 1797 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1400 3403 -3002 3401 -1402 1795 -2992 3401 -3002 3401 -1398 1791 -1398 1801 -3002 1799 -1402 1801 -1396 3389 -3004 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 3403 -1400 1801 -3002 1795 -1394 3399 -1400 1801 -1400 1801 -2994 1801 -1400 4395 -3776 14743 -2408 3811 -2802 3401 -3002 3401 -3002 3403 -3002 3393 -3002 3401 -2996 3401 -3002 3401 -2994 3395 -3002 3393 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -2990 1801 -1400 1801 -1402 1799 -1398 3397 -3002 3407 -1404 1795 -2992 3407 -2996 3395 -1400 1795 -1398 1801 -3002 1801 -1396 3391 -3002 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 +RAW_Data: 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1799 -1398 3397 -1402 1799 -3002 1797 -1394 3397 -1402 1799 -1402 1799 -2996 3401 -3996 385 -3102 2063 -3036 3275 -3042 3425 -3020 3405 -3006 3411 -2996 3395 -3002 3393 -3002 3395 -3002 3393 -3002 3401 -3002 3395 -3002 3393 -3002 3403 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -3002 1799 -1402 1801 -1396 1791 -1398 3403 -3002 3407 -1404 1595 -3194 3407 -2994 3393 -1402 1795 -1394 1797 -3002 1799 -1402 3401 -1398 1795 -3004 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 3403 -1400 1801 -3002 1795 -1394 3391 -1400 1801 -1400 1801 -1400 1801 -3002 3603 -1478 645 -1724 2035 -3064 3173 -3182 3187 -3190 3393 -2996 3401 -3002 3393 -3002 3403 -2994 3401 -2994 3407 -2998 3393 -3002 3393 -3002 3403 -2994 3401 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -2998 1801 -1402 1799 -1402 1795 -1394 3397 -3002 3403 -1400 1795 -3000 3401 -3002 3395 -1400 1801 -1396 1797 -3002 3407 -2998 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 3407 -1400 1791 -2992 1799 -1402 3401 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -8088 1731 -3044 3437 -3028 3261 -3072 3287 -3118 3295 -3118 3323 -3148 3167 -3180 3185 -3190 3395 -2994 3399 -3004 3393 -2996 3401 -2994 3401 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -2996 1799 -1402 1799 -1402 1801 -1396 3397 -2996 3401 -1400 1801 -3006 3403 -2998 3397 -1400 +RAW_Data: 1793 -1394 1795 -3004 3401 -3002 3393 -2994 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 3393 -1402 1801 -3002 3393 -3002 1801 -1396 1797 -1402 1799 -1402 1795 -1398 3401 -4926 8515 -2468 3839 -2822 3413 -3010 3407 -3004 3403 -3002 3393 -3002 3393 -3004 3401 -2994 3393 -3002 3403 -3002 3401 -2994 3395 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -3002 1799 -1402 1795 -1398 1801 -1400 3403 -2994 3401 -1402 1799 -2994 3403 -3002 3393 -1402 1799 -1398 1795 -3004 3401 -1396 1793 -2998 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 3403 -1396 1791 -3000 3401 -3002 1801 -1400 1797 -1394 1795 -1402 3407 -8138 1617 -2850 3563 -2976 3385 -2990 3395 -2994 3401 -2994 3401 -2996 3401 -3002 3401 -2994 3403 -2994 3401 -2994 3407 -3006 3393 -2994 3407 -1400 1791 -1394 1797 -1400 1801 -1402 1799 -1398 1795 -3004 1799 -1402 1795 -1398 1801 -1400 3401 -2996 3401 -1400 1797 -2990 3403 -3002 3401 -1400 1801 -1398 1791 -2998 3403 -1400 1801 -1400 1801 -2994 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 +RAW_Data: 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 3401 -1402 1801 -3002 3397 -3006 1795 -1394 1793 -1398 3401 -3002 3601 -4378 1989 -2806 3493 -2902 3511 -2930 3349 -3166 3183 -3186 3389 -2994 3403 -2994 3407 -3004 3395 -2994 3393 -3002 3401 -3004 3393 -3002 3393 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -3002 1801 -1398 1795 -1402 1801 -1400 3393 -3002 3403 -1396 1793 -3002 3405 -2996 3405 -1400 1793 -1394 1795 -1402 1801 -3002 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 3401 -1402 1801 -3002 3401 -2994 1801 -1400 1801 -1402 3393 -1400 1801 -7422 9169 -1802 3795 -2600 3611 -3002 3401 -3006 3405 -2996 3393 -3002 3407 -2996 3395 -2994 3401 -3002 3403 -2994 3401 -2994 3401 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -2992 1799 -1402 1801 -1400 1801 -1400 3401 -2996 3401 -1396 1797 -3002 3403 -3002 3393 -1400 1801 -1398 1791 -1398 1801 -3002 1799 -1402 3401 -2994 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 3393 -1402 1795 -3000 3401 -3002 1795 -1394 3399 -3002 1799 -1402 3801 -1286 649 -2066 2205 -3008 3427 -3012 3407 -3006 3393 -2994 3393 -3002 3403 -2994 3401 -3002 3395 -3002 3393 -3002 3401 -2996 3401 -3002 3393 -3002 3395 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -3002 1799 -1402 1801 -1396 1797 -1400 3403 -2994 3401 -1402 1795 -2998 3403 -3002 3393 -1402 1799 -1398 1791 -1398 1801 -3002 3401 -3002 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1795 -1398 +RAW_Data: 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -1400 1801 -3002 3393 -3002 1797 -1394 3397 -3002 3401 -7732 14869 -2460 3833 -2818 3409 -3004 3401 -3002 3401 -3002 3403 -3002 3405 -2998 3393 -3004 3393 -2994 3407 -3008 3199 -1596 1789 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -2994 1801 -1400 1801 -1400 1801 -1398 3397 -3002 3401 -1398 1791 -3000 3401 -2994 3401 -1402 1801 -1400 1801 -1400 1795 -2992 3401 -1402 1801 -3002 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 3407 -1400 1791 -2992 3401 -3004 1799 -1402 3407 -1400 1789 -2988 3403 -3830 2193 -2986 3375 -2944 3501 -3050 3235 -3018 3409 -3002 3403 -3002 3401 -3002 3401 -3002 3395 -3002 3393 -3006 3207 -3194 3399 -3004 3393 -1398 1791 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -3002 1799 -1398 1791 -1398 1801 -1400 3403 -3002 3401 -1398 1795 -3002 3395 -3002 3393 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -3006 1601 -1592 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 3399 -1400 1801 -3002 3401 -2994 +RAW_Data: 1801 -1400 3403 -1400 1795 -1396 1795 -6110 417 -1290 1655 -3016 3535 -2958 3375 -2982 3187 -3194 3399 -2996 3395 -3002 3393 -3002 3393 -3004 3393 -3002 3401 -3002 3395 -3002 3407 -2996 3393 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -3000 1799 -1402 1801 -1396 1791 -1398 3403 -3002 3401 -1402 1799 -2994 3407 -2998 3393 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -3002 3401 -2994 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 3395 -1400 1801 -2994 3401 -3002 3395 -3002 1799 -1398 1791 -1398 3603 -200 965 -3206 1811 -2896 3423 -3010 3405 -3006 3401 -3002 3395 -3002 3393 -3002 3403 -2994 3401 -3002 3401 -2994 3403 -2994 3393 -3002 3407 -2998 3401 -1398 1791 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3403 -1396 1791 -3000 3401 -3002 3403 -1396 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -3002 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3401 -1402 1795 -2990 3403 -3002 3401 -3002 1801 -1396 3391 -7600 1899 -3004 3287 -3106 3315 -3134 3159 -3176 3185 -3190 3391 -2994 3393 -3002 3395 -3002 3401 -2994 3401 -3004 3393 -3002 3407 -2996 3395 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1396 1797 -3002 1795 -1398 1801 -1400 1801 -1402 3401 -2994 3401 -1402 1795 -3000 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -3000 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 +RAW_Data: 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 3403 -1404 1795 -2992 3401 -3004 3393 -3002 3401 -2994 3403 -4206 2011 -3272 3159 -3176 3181 -3186 3195 -3190 3393 -3002 3395 -3002 3401 -2998 3405 -2996 3405 -2998 3393 -2994 3403 -2994 3401 -3006 3399 -1396 1791 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -3002 1801 -1400 1801 -1400 1801 -1396 3391 -3002 3401 -1402 1799 -3002 3403 -1396 1797 -3002 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 3407 -1404 1597 -3190 3401 -2994 3403 -3002 3393 -1402 1795 -7316 8443 -2572 3577 -2988 3393 -3002 3393 -3004 3393 -3006 3405 -2994 3395 -3002 3393 -3002 3395 -3002 3401 -3002 3393 -3006 3399 -1396 1793 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -3002 1801 -1396 1797 -1400 1801 -1402 3401 -2998 3397 -1398 1791 -3000 3401 -1400 1801 -3002 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 3395 -3002 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1793 -1398 3401 -1400 1801 -3002 3401 -3004 3393 -1400 1801 -2994 1801 -1400 3603 -4490 1839 -2642 3731 -2746 3573 -2988 3389 -2990 3393 -3000 +RAW_Data: 3405 -2994 3393 -3002 3403 -2994 3401 -2994 3401 -2996 3401 -2994 3401 -3002 3403 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -3000 1801 -1400 1801 -1396 1793 -1398 3401 -3002 3401 -1402 1795 -3004 3405 -1396 1793 -2990 1801 -1400 1801 -1402 1799 -1402 1799 -1398 3397 -3002 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1797 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 3401 -1400 1801 -3002 3393 -3002 3403 -1396 1793 -2998 3401 -8350 1743 -2940 3389 -3000 3397 -2994 3393 -3004 3401 -2994 3401 -2994 3403 -3002 3401 -2994 3401 -2996 3401 -2994 3401 -3002 3407 -2998 3393 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -2990 1801 -1402 1799 -1402 1799 -1402 3401 -2998 3407 -1396 1791 -2992 3401 -1402 1801 -3002 1799 -1398 1797 -1400 1801 -1400 1795 -1396 3397 -1400 1801 -3002 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 3393 -1402 1799 -3002 3395 -3002 3407 -1400 1789 -1392 1797 -3006 3605 -4930 1985 -2864 3367 -2982 3185 -3192 3393 -2994 3393 -3002 3403 -2994 3401 -3002 3395 -3002 3393 -3002 3401 -2998 3207 -3194 3393 -3002 3403 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -2992 1801 -1400 1801 -1400 1801 -1400 3407 -2998 3393 -1398 1791 -3000 3401 -1400 1801 -3002 1795 -1398 1801 -1402 1799 -1398 3389 -3002 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 +RAW_Data: 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 3403 -1400 1801 -3002 3393 -3002 3407 -1400 1789 -1392 1797 -1402 1799 -8070 9613 -1418 3825 -2614 3609 -3002 3401 -3004 3401 -3002 3401 -3002 3403 -2994 3393 -3002 3401 -2996 3401 -3002 3401 -2994 3403 -1396 1797 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -3002 1799 -1402 1795 -1398 1801 -1400 3403 -2994 3401 -1398 1791 -2998 3403 -1400 1801 -3002 1801 -1400 1795 -1398 1801 -1402 3401 -2994 3401 -2996 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 3403 -1400 1801 -3002 3393 -1402 1795 -3000 1799 -1402 1799 -1398 1791 -1398 3603 -4754 8207 -2562 3569 -2984 3389 -2996 3401 -2994 3401 -2994 3403 -3002 3401 -2994 3401 -2996 3401 -2994 3401 -3002 3395 -3002 3393 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -2990 1801 -1402 1799 -1402 1799 -1402 3401 -3002 3395 -1400 1795 -2992 3401 -1402 1799 -3004 1799 -1398 1791 -1398 1801 -1400 3403 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 3401 -1402 1799 -3002 3395 -1400 1801 -2994 1801 -1400 1801 -1398 3389 -7746 8811 -2430 3817 -2810 3411 -3002 3401 -3002 3401 -3002 3395 -3002 3401 -2994 3403 -2994 3401 -3006 3397 -2996 3393 -3002 3401 -1402 1795 -1394 1797 -1400 1801 -1400 +RAW_Data: 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1799 -1402 3401 -2994 3403 -1400 1801 -3002 3401 -1398 1791 -3000 1799 -1402 1801 -1396 1797 -1400 3403 -1396 1791 -1398 1801 -3002 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 3393 -1402 1799 -3004 3393 -1400 1797 -2998 1801 -1400 3403 -3002 3993 -3076 14679 -2816 3619 -2804 3401 -3002 3403 -3002 3393 -3002 3401 -3004 3393 -2994 3401 -3002 3395 -3002 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3393 -1402 1799 -2994 3403 -1396 1797 -3002 1801 -1400 1801 -1396 3391 -3002 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 3395 -1400 1801 -3002 3393 -1402 1799 -3002 1801 -1398 3389 -1400 1801 -6990 1657 -3042 3285 -3122 3305 -3118 3323 -3152 3167 -3174 3187 -3190 3389 -2996 3401 -2994 3401 -3002 3395 -3002 3401 -2994 3393 -3004 3401 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -2994 1801 -1400 1801 -1400 1801 -1398 3389 -3006 3405 -1398 1791 -3000 3401 -1402 1795 -2990 1801 -1402 1799 -1402 3401 -3002 1795 -1394 3399 -3002 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 +RAW_Data: 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1396 1791 -1398 1801 -1402 3401 -1400 1801 -3006 3399 -1396 1797 -3002 3393 -3002 1797 -1394 3597 -4444 1939 -2940 3439 -3026 3413 -3006 3407 -3002 3397 -3006 3393 -2996 3393 -3002 3393 -3006 3207 -3194 3393 -2994 3403 -3002 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1801 -1400 3401 -2996 3401 -1400 1801 -3002 3393 -1398 1791 -3004 1803 -1402 1795 -1398 3403 -3002 3401 -2998 1799 -1394 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 3393 -1402 1801 -3002 3393 -1402 1799 -3002 3399 -3006 3393 -7892 1731 -2682 3593 -2994 3403 -3002 3393 -3002 3393 -3004 3401 -2994 3401 -3002 3403 -2994 3393 -3002 3399 -3006 3393 -2994 3401 -3006 3399 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3006 3397 -1402 1795 -2992 3401 -1402 1799 -3002 1795 -1400 1799 -1402 3401 -2994 3401 -1402 1795 -2992 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1400 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 3401 -1400 1797 -2994 3407 -1400 1795 -3000 3401 -1402 1795 -2992 3601 -4720 1955 -2804 3439 -3022 3413 -3002 3401 -3002 3403 -3002 3401 -2994 3403 -3002 3393 -3002 3393 -3002 3403 -2994 3401 -3002 3395 -3002 3393 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -3002 1801 -1400 1797 -1394 1795 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -1402 1799 -3002 1801 -1402 1795 -1394 3397 -1402 +RAW_Data: 1799 -3002 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 3401 -1400 1801 -2994 3403 -1400 1801 -2998 3411 -1400 1789 -1392 1797 -7942 14895 -2618 3611 -2810 3401 -3002 3401 -3002 3403 -3002 3393 -3002 3401 -2996 3401 -3002 3393 -2998 3407 -2994 3393 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3403 -1400 1795 -2992 3401 -1402 1799 -3008 1599 -1594 1795 -1402 3401 -1402 1795 -2992 3401 -3002 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 3401 -1402 1799 -2994 3403 -1400 1795 -1398 1801 -3002 1795 -1400 1799 -1402 3801 -1294 1075 -840 2397 -2992 3435 -3022 3249 -3164 3313 -2942 3519 -3068 3247 -3026 3413 -3010 3401 -3002 3403 -3002 3393 -3002 3403 -3002 3393 -3002 3393 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -3004 1799 -1398 1791 -1398 1801 -1400 3401 -3004 3401 -1396 1793 -2998 3403 -1400 1801 -3002 1795 -1394 1797 -1400 3403 -1400 1801 -1400 1795 -3000 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 +RAW_Data: 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 3401 -1402 1801 -2994 3401 -1402 1795 -1398 1799 -3004 1795 -1394 3397 -7240 3691 -1402 3855 -2834 3419 -3018 3413 -3002 3401 -3002 3395 -3002 3393 -3002 3401 -2996 3401 -3002 3393 -3002 3395 -3002 3407 -2996 3399 -1404 1597 -1590 1791 -1398 1799 -1402 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3002 3401 -1402 1795 -2992 3401 -1400 1801 -3002 1801 -1396 1793 -1398 3405 -1404 1797 -1394 1795 -1402 1799 -3004 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 3403 -1396 1797 -3002 3401 -1402 1795 -1394 1797 -3002 3407 -3004 3595 -4610 1539 -3058 3381 -2988 3193 -3194 3393 -2996 3401 -3002 3393 -3002 3403 -2994 3407 -3004 3395 -2994 3393 -3002 3401 -2996 3401 -2994 3401 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -3002 1801 -1402 1799 -1402 1795 -1398 3401 -3002 3403 -1396 1791 -3000 3401 -1402 1801 -2994 1799 -1402 3401 -3002 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 3401 -1402 1799 -3004 3401 -1396 1793 -1398 1799 -3002 3403 -1400 1801 -6986 367 -734 1837 -2952 3531 -2896 3279 -3050 3435 -3018 3401 -3002 3401 -3008 3405 -2998 3205 -3198 3399 -2994 3401 -2998 3399 -2994 3393 -3002 3401 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3393 -1400 1801 -3002 3395 -1400 1801 -3002 1795 -1394 3397 -3004 1799 -1402 1799 -1398 3395 -3004 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 +RAW_Data: 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 3399 -1400 1801 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -3002 1801 -1400 3793 -4322 1655 -3012 3323 -3148 3167 -3186 3189 -3192 3389 -2994 3401 -2996 3401 -3002 3393 -3002 3403 -2994 3401 -2998 3407 -2994 3401 -2994 3393 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -3004 1795 -1398 1799 -1402 1801 -1396 3397 -3004 3401 -1396 1793 -2998 3403 -1400 1801 -3002 1795 -1394 3397 -3002 1801 -1402 3401 -2994 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 3401 -1402 1801 -2994 3401 -1398 1795 -1402 1799 -1402 1801 -2994 3401 -3594 835 -1436 377 -1140 1711 -3242 3159 -3176 3181 -3190 3193 -3200 3201 -3202 3197 -3196 3393 -2994 3407 -2996 3395 -2994 3401 -3002 3403 -2994 3401 -2994 3407 -1404 1597 -1592 1791 -1398 1801 -1402 1799 -1402 1795 -3000 1799 -1402 1801 -1400 1801 -1396 3391 -3002 3401 -1396 1797 -3002 3403 -1400 1801 -2994 1801 -1400 3401 -3002 1797 -1394 3397 -1402 1799 -3002 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 +RAW_Data: 1801 -1402 1799 -1402 1799 -1398 1791 -1398 3401 -1402 1801 -3006 3397 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -3006 3799 -1526 441 -1060 2475 -2980 3315 -2928 3499 -3076 3249 -3030 3417 -3014 3411 -3006 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3401 -3000 3209 -3202 3197 -1596 1787 -1392 1797 -1400 1801 -1402 1799 -1402 1799 -2996 1799 -1402 1801 -1400 1801 -1396 3399 -3002 3401 -1396 1793 -2998 3403 -1396 1797 -3002 1801 -1400 3401 -3002 3395 -2994 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 3401 -1402 1801 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -7480 27707 -2512 3729 -2756 3573 -2984 3385 -2994 3399 -2990 3393 -3006 3205 -3192 3393 -3002 3393 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1797 -3002 1799 -1402 1801 -1396 1791 -1398 3403 -3002 3401 -1400 1797 -2998 3403 -1400 1795 -2992 1801 -1400 3401 -3008 3205 -3194 3393 -3002 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 3403 -1400 1801 -1400 1795 -3000 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 3803 -4446 1433 -3026 3349 -3164 3173 -3188 3189 -3198 3197 -3194 3395 -3002 3393 -3002 3403 -2994 3401 -2994 3401 -3004 3401 -2998 3397 -2994 3403 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1402 3401 -2994 3401 -1402 1799 -3004 3393 -1400 1797 -2990 1801 -1400 3403 -3002 3401 -1398 1791 -2998 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 +RAW_Data: 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 1801 -1400 3393 -7770 21481 -2430 3819 -2810 3401 -3002 3401 -3002 3403 -3002 3401 -3002 3393 -3002 3407 -2998 3393 -3002 3395 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -3000 1801 -1400 1801 -1396 1791 -1400 3401 -3002 3401 -1402 1799 -3002 3395 -1400 1801 -2994 1801 -1400 3395 -3002 3401 -1402 1795 -1394 1795 -3004 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1398 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 3403 -1400 1801 -1396 1797 -3002 1801 -1400 1801 -1398 1795 -1402 3401 -3002 3795 -3852 2121 -3066 3329 -3156 3167 -3174 3189 -3192 3393 -3002 3393 -3004 3393 -3002 3401 -2994 3403 -2994 3401 -2994 3401 -3004 3401 -2994 3401 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -3002 1801 -1402 1799 -1402 1795 -1394 3397 -3004 3401 -1400 1801 -3002 3393 -1402 1801 -2994 1799 -1402 3401 -1398 1795 -2996 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 3401 -1402 1795 -1394 1797 -3002 1801 -1400 1801 -1400 1795 -1396 3397 -1400 1801 -7618 +RAW_Data: 15035 -2418 3813 -2810 3403 -3002 3401 -3002 3401 -2996 3401 -3002 3393 -3002 3403 -3002 3393 -2994 3401 -3004 3401 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -2996 1805 -1400 1795 -1398 1801 -1402 3401 -2994 3401 -1402 1795 -2992 3401 -1402 1799 -3002 1801 -1402 3393 -1400 1801 -2994 1801 -1400 3403 -2994 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1795 -1398 1801 -1400 1801 -1400 1801 -1402 3393 -1400 1801 -1402 1795 -2990 1801 -1402 1799 -1402 3401 -3002 1795 -1394 3399 -4894 8261 -2584 3593 -3002 3395 -3002 3393 -3002 3403 -2994 3401 -2994 3401 -2996 3405 -3006 3393 -2994 3395 -3002 3401 -2994 3403 -1400 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3401 -1398 1791 -2998 3403 -1400 1801 -2998 1805 -1396 3395 -1404 1795 -2992 3401 -3006 1805 -1396 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 3403 -1396 1797 -1400 1801 -3002 1795 -1394 1797 -1402 3401 -3006 3397 -7586 1729 -3040 3443 -3022 3417 -3004 3401 -3002 3401 -3002 3403 -2994 3401 -3002 3393 -3000 3405 -2994 3401 -2994 3403 -2998 3205 -3198 3399 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -2992 1799 -1402 1801 -1400 1801 -1396 3395 -3006 3393 -1402 1799 -3002 3395 -1400 1801 -3002 1795 -1394 3399 -1400 1801 -3002 3401 -1398 1791 -3000 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1398 1797 -1400 +RAW_Data: 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 3403 -1400 1801 -1400 1801 -3002 1801 -1396 1793 -1398 3401 -1400 1801 -3002 3803 -3690 8945 -2004 3805 -2802 3407 -3006 3401 -3002 3393 -3002 3395 -3002 3401 -2998 3211 -3198 3393 -2994 3395 -3002 3401 -3002 3393 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -3008 1803 -1398 1791 -1394 1797 -1400 3401 -3004 3401 -1400 1801 -3002 3393 -1402 1801 -2994 1799 -1402 3401 -1398 1797 -1396 1797 -3002 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 3401 -1402 1795 -1394 1797 -3002 1801 -1400 1801 -1396 3399 -1400 1801 -1400 1801 -8146 15111 -2438 3821 -2814 3409 -3004 3401 -3002 3401 -3002 3403 -2994 3401 -3002 3393 -3002 3403 -2994 3401 -2994 3407 -1404 1597 -1592 1793 -1398 1799 -1402 1799 -1402 1801 -2994 1801 -1400 1801 -1396 1797 -1400 3407 -3006 3393 -1398 1791 -3000 3401 -1400 1801 -2994 1801 -1400 3403 -1400 1795 -1394 1797 -3002 3401 -3004 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 3403 -1400 1795 -1394 1797 -3002 1801 -1400 3407 -3006 1595 -1592 1789 -1398 3603 -4270 1767 -2816 3481 -2910 3319 -3118 3293 -3244 3229 -3014 3409 -3006 3407 -3002 3407 -3004 3395 -2994 3401 -2994 3401 -2996 3401 -3002 3399 -1404 +RAW_Data: 1595 -1594 1797 -1400 1801 -1400 1797 -1398 1799 -3002 1801 -1398 1791 -1398 1801 -1400 3401 -3006 3207 -1596 1791 -2992 3401 -1402 1801 -3002 1795 -1398 3401 -1402 1795 -1398 1801 -1400 1801 -3002 1795 -1394 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 3401 -1402 1795 -1394 1797 -3002 1801 -1400 3407 -3004 1597 -1594 3393 -8044 8285 -2600 3601 -3004 3401 -2994 3401 -2994 3403 -3002 3407 -2996 3393 -3004 3393 -3002 3399 -3004 3395 -2994 3401 -3002 3399 -1404 1597 -1592 1793 -1398 1799 -1402 1799 -1402 1801 -3002 1799 -1398 1797 -1396 1797 -1400 3407 -3006 3393 -1398 1791 -3000 3405 -1404 1597 -3190 1801 -1400 3403 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -3004 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 3403 -1396 1791 -1400 1799 -3002 1801 -1400 3403 -3002 3393 -3002 4003 -3520 1767 -3000 3331 -3084 3243 -3026 3409 -3002 3407 -3010 3405 -2998 3397 -2996 3401 -2994 3401 -2994 3403 -3002 3401 -2994 3403 -2994 3401 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3393 -1402 1801 -2994 3407 -1404 1793 -2988 3403 -3002 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 +RAW_Data: 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1394 3397 -1402 1799 -1402 1799 -3004 1799 -1402 3393 -3002 3393 -1402 1801 -4796 787 -2262 1869 -2942 3419 -3010 3405 -3006 3393 -3004 3393 -3002 3401 -2994 3403 -2994 3401 -3002 3393 -3004 3401 -2994 3401 -3002 3399 -3010 3193 -1598 1791 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1799 -1402 3401 -3002 3395 -1400 1795 -3000 3401 -1402 1795 -2992 3401 -3002 1801 -1400 1801 -1400 1797 -1394 3397 -3002 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 3401 -1398 1791 -1398 1801 -3002 1799 -1402 3393 -1402 1799 -3004 1799 -1398 4199 -2960 2227 -2872 3355 -3174 3183 -3186 3389 -2994 3395 -3002 3393 -3002 3401 -2996 3401 -3002 3393 -3002 3395 -3002 3401 -2994 3403 -2994 3401 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -1402 1799 -3002 3395 -3002 1795 -1398 1801 -1400 3407 -2998 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 3397 -1402 1799 -1402 1799 -3004 1799 -1398 3389 -1402 1799 -3002 3403 -7954 27839 -2554 3573 -2988 3389 -2994 3393 -3002 3395 -3002 3399 -3004 3395 -2994 3393 -3002 3401 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -3002 1799 -1398 1791 -1398 1801 -1400 3403 -3002 3393 -1400 1801 -3002 3395 -1400 +RAW_Data: 1801 -2994 3401 -3002 1797 -1394 1795 -1402 3401 -1402 1799 -3002 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 3401 -1402 1795 -1394 1797 -3002 1801 -1400 3401 -1398 1797 -1400 1801 -3002 3393 -4822 15921 -1406 3809 -2610 3601 -3002 3403 -3002 3401 -3002 3401 -3004 3393 -2994 3407 -3004 3395 -2994 3407 -2996 3395 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3399 -1404 1595 -3190 3403 -1400 1801 -3002 3393 -3006 1601 -1594 3389 -3002 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 3403 -1396 1791 -1398 1801 -3002 1801 -1400 3403 -1396 1791 -1398 1801 -1402 1799 -6668 1963 -2566 3673 -2838 3421 -3014 3411 -3006 3393 -3002 3393 -3004 3401 -2994 3407 -2996 3395 -3002 3393 -3002 3395 -3002 3405 -2998 3399 -1400 1791 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -3002 1799 -1398 1791 -1398 1801 -1400 3403 -3002 3393 -1402 1799 -3002 3395 -1400 1801 -3002 3393 -3002 1797 -1394 3397 -3002 3401 -3002 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1795 -1402 +RAW_Data: 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 3407 -1400 1791 -1394 1797 -3002 3401 -3002 1797 -1394 1795 -1402 1801 -1400 3803 -4242 1899 -2672 3763 -2746 3509 -2864 3439 -3026 3417 -3002 3401 -3008 3405 -3002 3393 -2994 3403 -3002 3405 -2998 3393 -2996 3401 -2994 3401 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -3002 1797 -1394 1795 -1402 1801 -1400 3401 -3002 3403 -1396 1793 -2998 3401 -1398 1797 -3002 3401 -3002 1795 -1394 3399 -1400 1801 -3002 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 3401 -1398 1791 -1398 1801 -3002 3401 -3002 1795 -1394 1797 -1402 3401 -7512 21165 -2482 3841 -2832 3413 -3010 3401 -3002 3403 -3002 3401 -3002 3407 -2998 3393 -3002 3393 -3002 3403 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -2994 1801 -1400 1795 -1398 1801 -1400 3403 -2994 3401 -1402 1799 -3002 3395 -1400 1797 -2990 3401 -3004 1799 -1402 3401 -1398 1791 -1398 1799 -3004 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1795 -1398 3403 -1400 1801 -1400 1797 -2998 3395 -3002 1799 -1402 3401 -3002 3399 -3900 661 -442 1987 -2846 3333 -3156 3167 -3182 3185 -3192 3393 -3002 3393 -3004 3393 -3002 3407 -2996 3395 -2994 3401 -3002 3401 -2996 3393 -3002 3401 -1402 1795 -1398 1795 -1398 1801 -1402 1799 -1402 1799 -2996 1799 -1402 1799 -1402 1801 -1396 3389 -3004 3401 -1400 1801 -2994 3401 -1402 1801 -2994 3407 -3004 3193 -3196 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 +RAW_Data: 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 3407 -1400 1789 -1392 1797 -3002 3401 -3002 1801 -1402 3393 -1400 1801 -5854 1449 -3028 3481 -2910 3519 -2928 3493 -2856 3433 -3014 3415 -3010 3405 -2998 3397 -2996 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3407 -1404 1595 -1588 1795 -1402 1799 -1402 1799 -1402 1801 -2994 1799 -1402 1801 -1396 1791 -1398 3403 -3002 3401 -1402 1799 -2994 3403 -1400 1801 -2994 3393 -3002 3403 -3002 1795 -1394 3397 -3002 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 3403 -1400 1801 -1400 1801 -2994 3401 -2996 3401 -3002 1801 -1396 4197 -2116 2985 -3040 3495 -2924 3333 -3160 3173 -3184 3189 -3198 3189 -3196 3393 -3002 3393 -3002 3407 -2998 3393 -3002 3395 -3002 3401 -2994 3393 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -3002 1799 -1402 1795 -1398 1801 -1400 3403 -2994 3401 -1400 1801 -3002 3395 -1400 1801 -2994 3407 -2996 3395 -3002 3401 -2994 1801 -1396 1797 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 3395 -1400 1801 -1400 1795 -2992 3401 -3006 +RAW_Data: 3207 -3194 3407 -3798 1471 -2756 1731 -2764 3451 -3026 3423 -3014 3401 -3002 3393 -3008 3401 -2998 3393 -3002 3403 -2994 3401 -2994 3395 -3002 3401 -3002 3393 -3002 3395 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -3000 1801 -1400 1801 -1400 1801 -1402 3405 -2998 3393 -1398 1797 -3002 3393 -1400 1801 -3002 3395 -3002 3401 -2998 3209 -1602 1591 -3184 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 3401 -1400 1801 -1398 1791 -3000 3401 -3002 3401 -1398 1795 -3002 3603 -3528 2573 -2892 3567 -2982 3387 -2990 3393 -2994 3407 -3006 3393 -2994 3401 -2996 3393 -3002 3401 -3002 3403 -2994 3401 -2994 3399 -3006 3393 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -2994 1801 -1400 1801 -1402 1795 -1394 3403 -3004 3401 -1398 1791 -3000 3401 -1402 1795 -3000 3401 -3006 3403 -1400 1791 -2992 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 3401 -1398 1795 -1402 1801 -3006 3197 -3194 3393 -1402 1801 -1400 1801 -7732 2037 -2694 3601 -2994 3401 -2994 3403 -2994 3401 -3002 3403 -2994 3393 -3002 3401 -2996 3401 -3002 3399 -3004 3399 -2998 3399 -2996 3395 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -3000 1799 -1402 1801 -1400 1801 -1396 3399 -3002 3393 -1402 1799 -3002 3395 -1396 1797 -3006 3397 -3002 3395 -1400 1801 -3002 3393 -3002 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 +RAW_Data: 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1795 -1398 1801 -1400 3403 -1396 1797 -1400 1801 -3002 3393 -1402 1795 -3004 1803 -1398 1791 -1398 3403 -4578 1767 -2596 3785 -2526 3699 -2874 3441 -3022 3419 -3010 3401 -3002 3401 -3002 3403 -3002 3393 -3002 3403 -2994 3401 -2994 3401 -3004 3401 -1396 1793 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -3002 1801 -1400 1801 -1396 1793 -1398 3401 -3002 3407 -1404 1595 -3192 3401 -1396 1793 -2998 3403 -3002 3393 -1402 1799 -1402 1799 -3004 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 3401 -1396 1797 -1402 1799 -3002 3395 -1400 1801 -3002 1795 -1398 3401 -7634 8423 -2600 3601 -3002 3403 -3002 3401 -3002 3403 -2994 3401 -3002 3393 -3002 3395 -3002 3401 -2994 3403 -2994 3401 -3002 3393 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -3004 1799 -1402 1799 -1398 1791 -1398 3403 -3002 3401 -1396 1793 -2998 3403 -1400 1801 -3002 3407 -2996 3395 -1396 1791 -1398 1801 -1402 1799 -3002 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 3401 -1402 1795 -1398 1801 -3002 3401 -1398 1795 -3004 3401 -2994 3601 -5084 8583 -2458 3835 -2822 3413 -3010 3403 -3002 3401 -3002 3395 -3002 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3403 -3002 +RAW_Data: 3393 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -1402 1799 -3002 3403 -1396 1791 -3000 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3407 -1404 1595 -1594 1791 -3000 3405 -1404 1597 -3190 3407 -1404 1597 -7988 1673 -3042 3323 -3148 3363 -2976 3185 -3194 3399 -2998 3393 -3002 3401 -2994 3395 -3006 3397 -2994 3403 -2994 3407 -3004 3393 -2996 3401 -1396 1793 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -1402 1799 -3002 3403 -1396 1791 -3000 1801 -1400 1801 -1400 3403 -3002 1795 -1394 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 3393 -1400 1801 -1398 1791 -3000 3401 -1400 1801 -1400 1801 -3002 1795 -1396 3597 -4754 1619 -2850 3567 -2982 3389 -2990 3395 -3002 3393 -3002 3395 -3002 3393 -3002 3401 -2996 3401 -3002 3407 -2996 3395 -2998 3397 -2994 3403 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -3002 1799 -1402 1801 -1400 1801 -1400 3395 -3002 3401 -1398 1791 -2998 3403 -1400 1801 -2994 3401 -1402 1795 -2992 1799 -1402 3401 -3002 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 +RAW_Data: 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 3403 -1400 1795 -1394 1797 -3002 3401 -1402 1795 -1398 1801 -3002 3401 -7874 2005 -2696 3647 -2838 3423 -3002 3401 -3002 3401 -3004 3401 -3006 3397 -3002 3395 -2994 3401 -3002 3395 -3002 3401 -2994 3407 -2998 3397 -1400 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1795 -1398 1801 -1400 1801 -1398 3401 -3006 3393 -1398 1791 -3000 3401 -1402 1799 -2994 3403 -1400 1795 -2992 1801 -1400 3401 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 3401 -1396 1797 -1402 1799 -2994 3403 -1400 1795 -1396 1795 -1402 1799 -3004 3801 -4428 14941 -2434 3819 -2810 3415 -3004 3403 -3002 3405 -2998 3393 -3000 3397 -3002 3393 -3002 3395 -3002 3393 -3002 3403 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -3004 1803 -1398 1791 -1398 1801 -1400 3407 -2998 3393 -1402 1799 -3002 3395 -1400 1801 -2994 3401 -1398 1797 -3002 3401 -2998 1805 -1396 1793 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 3395 -1400 1801 -1400 1801 -2994 3401 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -7354 2019 -2886 3413 -3002 3401 -3002 3403 -3002 3401 -3002 3393 -3004 3393 -3002 3401 -2994 3403 -3002 3407 -2996 3395 -2994 3393 -3002 3401 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -3004 1795 -1394 1795 -1402 1801 -1400 3401 -3004 +RAW_Data: 3205 -1600 1591 -3188 3403 -1400 1801 -3002 3407 -1400 1791 -2992 3401 -3002 3401 -2994 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 3401 -1402 1801 -1396 1791 -1398 1801 -3006 1805 -1396 1793 -1398 1799 -1402 1801 -1400 3401 -1476 3223 -2870 3519 -2934 3559 -2974 3187 -3190 3389 -2994 3395 -3002 3401 -2994 3403 -3002 3393 -3002 3401 -2996 3401 -2994 3407 -3004 3395 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -3000 1801 -1400 1801 -1396 1797 -1400 3403 -3002 3401 -1398 1791 -3000 3401 -1400 1801 -3002 3393 -1402 1801 -3002 3393 -1402 1799 -3002 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 3403 -1400 1801 -1396 1793 -1398 1799 -3002 1801 -1402 1799 -1402 1795 -1394 3397 -7212 2943 -1710 3963 -2582 3587 -2990 3389 -2994 3403 -2994 3401 -2994 3401 -3004 3393 -3002 3401 -3002 3399 -3006 3393 -2994 3401 -2996 3401 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -2994 1801 -1400 1801 -1396 1797 -1402 3401 -3002 3393 -1402 1801 -2994 3401 -1402 1795 -2990 3403 -1400 1801 -3002 3401 -1398 1791 -1398 1801 -3002 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 +RAW_Data: 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 3401 -1400 1801 -1402 1795 -1394 1797 -3002 1799 -1402 1801 -1400 3401 -3002 3795 -412 421 -3620 8315 -2598 3797 -2810 3401 -3002 3403 -3002 3401 -2994 3403 -3002 3393 -3002 3393 -3002 3395 -3002 3407 -2996 3395 -3002 3393 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3395 -1400 1801 -3002 3393 -1402 1799 -3002 3395 -1400 1801 -1400 1797 -2990 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 3401 -1402 1795 -1394 1797 -1400 1801 -3002 1799 -1402 1801 -1400 3395 -1400 1801 -7154 1989 -2800 3335 -3110 3489 -3052 3239 -3024 3411 -3006 3393 -3002 3401 -3002 3395 -3006 3397 -2994 3407 -3002 3197 -3194 3395 -3002 3393 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3393 -1402 1801 -3002 3393 -1402 1799 -3002 3395 -1400 1801 -1396 1797 -3006 1605 -1596 3391 -3002 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1797 -1398 1799 -1402 3401 -1402 1795 -1394 1795 -1402 1801 -3002 1799 -1402 3401 -2994 1801 -1402 3393 -4578 1987 -2610 3585 -2746 3685 -2908 3493 -2922 3337 -3160 3375 -2982 3389 -2990 3395 -3002 3393 -3002 3395 -3002 3401 -2994 3401 -3002 3395 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1394 1797 -3006 1805 -1396 1791 -1398 1801 -1402 3401 -3002 3401 -1398 1791 -3004 3405 -1396 1793 -2998 3403 -1400 1801 -1396 +RAW_Data: 1793 -2998 3401 -3004 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 3401 -1400 1797 -1394 1795 -1402 1801 -3002 1799 -1402 3401 -2994 3401 -7890 1857 -2976 3401 -3002 3401 -3002 3403 -2994 3401 -3006 3397 -2996 3405 -3002 3197 -3194 3395 -3002 3205 -3198 3395 -2994 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -2996 1799 -1402 1799 -1402 1795 -1394 3403 -3006 3393 -1402 1799 -2998 3207 -1596 1791 -2996 3405 -1402 1795 -1398 1801 -3006 3397 -1398 1791 -3000 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 3403 -1400 1801 -1400 1797 -1394 1795 -3002 1801 -1402 3401 -1400 1801 -3006 3397 -4660 9619 -1422 3829 -2818 3415 -3014 3405 -3002 3401 -3002 3395 -2994 3401 -3002 3395 -3002 3401 -2994 3393 -3004 3401 -3002 3393 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -3002 1801 -1398 1795 -1402 1801 -1400 3393 -3002 3403 -1396 1793 -2998 3401 -1402 1801 -3002 3393 -1402 1799 -1402 1795 -1394 1797 -3006 1803 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 +RAW_Data: 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 3401 -1402 1795 -1394 1797 -1400 1801 -3002 1801 -1400 3403 -1396 1791 -1398 1801 -4378 191 -1688 551 -1116 1659 -3106 3309 -3094 3259 -3038 3421 -3012 3405 -3006 3401 -2994 3403 -2994 3401 -3002 3395 -3002 3401 -2994 3401 -2994 3403 -3002 3393 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -3002 1801 -1402 1795 -1394 1795 -1402 3401 -3002 3403 -1396 1791 -3000 3401 -1402 1799 -3004 3401 -1396 1793 -1398 1799 -1402 1801 -3002 3401 -2994 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1394 3397 -1402 1799 -1402 1801 -1400 1801 -3002 3393 -3002 1797 -1394 1795 -1402 3401 -4704 2681 -1944 3813 -2610 3603 -3002 3401 -3002 3401 -2996 3401 -2994 3401 -3002 3395 -3002 3401 -2994 3403 -3002 3393 -3002 3401 -2998 3399 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -3000 1801 -1400 1795 -1398 1801 -1402 3401 -2994 3401 -1402 1799 -2996 3401 -1400 1797 -2990 3407 -1404 1801 -1396 1793 -1398 1799 -1402 1799 -3004 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 3397 -1400 1801 -1402 1795 -1394 1797 -3002 3401 -3002 1801 -1400 3395 -8456 8271 -2610 3601 -3002 3401 -3002 3403 -2994 3401 -3002 3395 -3002 3401 -2994 3393 -3006 3399 -2994 3401 -2994 3403 -3002 3401 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -3002 1805 -1396 1797 -1402 1799 -1402 3401 -2998 3205 -1598 1791 -2992 3401 -1402 1799 -3004 3401 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -2992 1801 -1400 1801 -1400 1801 -1402 +RAW_Data: 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 3397 -1402 1799 -1402 1801 -1400 1801 -3002 3393 -3002 3395 -3002 3601 -3880 2553 -2922 3559 -2976 3381 -2988 3389 -2994 3401 -3004 3393 -2994 3401 -3002 3203 -3198 3397 -2994 3403 -2994 3401 -3002 3407 -2996 3395 -1396 1797 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -3002 1801 -1400 1801 -1396 1793 -1398 3401 -3002 3401 -1402 1795 -2992 3401 -1400 1801 -1402 1799 -3006 1601 -1594 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 3389 -1400 1801 -1402 1799 -1402 1799 -3004 3393 -3002 3393 -1402 1801 -4436 421 -3014 1755 -3064 3393 -2996 3401 -2998 3205 -3194 3403 -2998 3397 -2994 3403 -3002 3393 -2994 3401 -3002 3395 -3002 3401 -2994 3403 -2994 3401 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3395 -1400 1801 -3002 3393 -1402 1799 -1402 1795 -2992 1799 -1402 1801 -1400 1801 -1400 1801 -1400 3395 -3002 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 +RAW_Data: 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 3401 -1402 1799 -1402 1799 -1402 1801 -2994 3401 -1398 1795 -3006 1605 -1598 4387 -1926 735 -564 1715 -3138 3393 -2994 3403 -3006 3197 -3194 3393 -3004 3401 -3002 3393 -3002 3395 -2994 3401 -3002 3401 -2996 3401 -3002 3393 -3002 3395 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -3002 1801 -1400 1801 -1400 1801 -1402 3393 -3006 3205 -1598 1791 -2992 3401 -1400 1801 -1402 1795 -2998 1801 -1402 1799 -1398 1791 -1398 3401 -3002 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 3401 -1400 1801 -1398 1791 -1398 1799 -3004 3401 -1400 1797 -2998 3401 -7510 1767 -2584 3763 -2696 3659 -2834 3419 -3010 3409 -3002 3401 -3002 3403 -3006 3397 -2994 3401 -2996 3401 -3002 3393 -3002 3403 -2994 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -2990 1801 -1402 1799 -1402 1799 -1402 3407 -3004 3195 -1596 1791 -2992 3401 -1402 1801 -1400 1801 -2994 1801 -1400 1801 -1400 1795 -1398 3403 -1400 1801 -2994 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 3401 -1402 1799 -1402 1795 -1394 1797 -3002 3401 -1402 1799 -1402 1795 -2992 3601 -4408 9397 -1404 3805 -2602 3601 -3002 3401 -3006 3407 -2998 3405 -2994 3395 -3006 3397 -2994 3395 -3002 3401 -2994 3401 -2994 3403 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -3002 1795 -1398 1801 -1400 1801 -1402 3393 -3006 3397 -1402 1795 -2992 3401 -1400 1801 -1402 1795 -2998 1801 -1402 1799 -1398 3389 -3002 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 +RAW_Data: 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 3401 -1396 1797 -1402 1799 -1402 1799 -2996 3401 -1400 1797 -1394 1795 -1402 1799 -7782 2983 -1722 3737 -2764 3575 -2986 3389 -2994 3395 -2994 3401 -3002 3403 -2994 3393 -3002 3401 -2996 3401 -2994 3401 -3002 3403 -2994 3401 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -2994 1801 -1400 1801 -1402 1795 -1394 3397 -3002 3403 -1400 1795 -3004 3205 -1598 1791 -1394 1797 -3002 1801 -1400 1801 -1400 3401 -3004 3393 -3002 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 3401 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -3002 1801 -1400 1801 -1402 1799 -1398 3789 -3630 9707 -1196 3995 -2602 3601 -3004 3401 -3002 3393 -3002 3403 -2994 3407 -3004 3193 -3200 3397 -2994 3401 -2996 3401 -3002 3393 -1402 1799 -1402 1795 -1398 1795 -1394 1797 -1402 1799 -3002 1801 -1402 1799 -1402 1799 -1398 3397 -3002 3407 -1400 1791 -2992 3401 -1402 1801 -1400 1795 -3000 1801 -1400 1795 -1398 3403 -1400 1795 -2992 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 +RAW_Data: 1801 -1402 1799 -1398 1791 -1398 3401 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -2998 1801 -1400 1801 -1402 3401 -7046 2191 -2780 3479 -2930 3487 -3108 3315 -2934 3349 -3166 3383 -2990 3389 -2994 3395 -3002 3401 -2998 3399 -2994 3401 -3002 3393 -3004 3393 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3002 3401 -1402 1795 -2996 3409 -1400 1789 -1394 1795 -3004 1799 -1402 1799 -1402 3407 -1404 1595 -1594 1791 -3000 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 3393 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -3002 1801 -1400 3401 -2996 3401 -5646 14913 -2416 3815 -2810 3401 -3002 3401 -3006 3407 -2994 3401 -2998 3205 -3196 3201 -3194 3393 -3008 3205 -3194 3393 -1398 1797 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -3004 1799 -1402 1799 -1402 1795 -1398 3401 -3002 3395 -1400 1797 -2998 3401 -1402 1801 -1396 1791 -3000 1801 -1400 3401 -3004 1795 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 3401 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -3002 1795 -1398 3395 -1400 1801 -6192 2021 -2460 3747 -2764 3583 -2986 3389 -2994 3395 -3002 3393 -3002 3403 -2994 3405 -3002 3197 -3196 3393 -3002 3393 -3002 3403 -2998 3205 -1598 1791 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -3002 1795 -1396 1795 -1402 1799 -1402 3401 -3002 3395 -1400 1801 -3002 3393 -1402 1795 -1398 1801 -3002 1795 -1398 3401 -3002 1797 -1398 3401 -3002 1795 -1398 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 +RAW_Data: 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 3401 -1402 1795 -1398 1801 -1400 1795 -1394 1797 -3002 3401 -3002 1797 -1398 3601 -4152 2483 -2464 3741 -2764 3575 -2986 3385 -2994 3395 -3002 3393 -3002 3395 -3002 3401 -2994 3401 -2996 3401 -3002 3393 -3002 3403 -3002 3393 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -3006 1601 -1592 1793 -1394 1795 -1402 3401 -3002 3403 -1400 1795 -3000 3401 -1398 1795 -1402 1801 -3006 1599 -1594 3389 -3002 3403 -3002 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1795 -1398 1801 -1400 1801 -1402 1799 -1402 3393 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -3002 3393 -3002 3403 -5836 199 -800 2239 -2970 3487 -2904 3313 -3324 3147 -3168 3173 -3188 3389 -2998 3397 -2996 3401 -2994 3401 -3002 3403 -2994 3393 -3002 3401 -3000 3205 -1596 1793 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -3002 1801 -1396 1793 -1398 1799 -1402 3401 -3002 3393 -1402 1801 -3002 3393 -1402 1799 -1398 1795 -3004 1799 -1402 3393 -3006 3205 -1598 1791 -2992 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 3401 -1402 1799 -1402 1799 -1402 1795 -1394 +RAW_Data: 1797 -3002 3401 -1402 1799 -3004 4001 -1452 1311 -1732 1679 -2834 3579 -2986 3395 -2998 3189 -3198 3199 -3194 3393 -3002 3401 -2996 3401 -2994 3401 -3002 3403 -2994 3401 -2994 3403 -2994 3401 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3401 -1402 1795 -2992 3401 -1402 1799 -1402 1799 -3000 1799 -1394 3397 -1402 1799 -3002 1797 -1398 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 3389 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -3000 3401 -1402 1799 -1402 1801 -7878 14949 -2414 3809 -2802 3401 -3004 3401 -3002 3401 -3002 3395 -2994 3401 -3002 3393 -3004 3401 -2998 3205 -3194 3395 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3006 3403 -1404 1595 -3188 3401 -1400 1801 -1398 1791 -2998 1801 -1402 3401 -1400 1801 -2994 3403 -2994 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 3401 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -3002 1801 -1396 1797 -1400 3603 -4378 1987 -2808 3349 -2882 3487 -3116 3325 -2936 3561 -2974 3385 -2992 3389 -2994 3393 -3004 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3401 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -3000 1799 -1402 1801 -1400 1801 -1400 3395 -3002 3401 -1400 1797 -2990 3403 -1400 1801 -1400 1801 -3006 1601 -1592 3391 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 +RAW_Data: 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 3399 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -3004 1803 -1398 3389 -7766 3599 -1180 3997 -2602 3601 -3002 3401 -3002 3403 -2994 3401 -3002 3401 -2996 3393 -3006 3397 -2994 3403 -3002 3401 -2994 3403 -2994 3401 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -2994 1801 -1400 1801 -1398 1791 -1398 3401 -3002 3403 -1400 1801 -2994 3401 -1398 1791 -1398 1801 -3002 1799 -1402 3401 -1402 1799 -1398 1791 -1398 1801 -3002 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 3401 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -2990 3401 -3004 3801 -4548 2039 -2540 3875 -2646 3423 -3026 3413 -3006 3405 -2996 3401 -2994 3401 -3002 3395 -3002 3393 -3002 3407 -2998 3393 -2994 3401 -3000 3205 -1596 1793 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1801 -1396 1791 -1400 1799 -1402 3401 -3002 3393 -1402 1801 -3002 3393 -1402 1799 -1402 1799 -2996 3401 -2994 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 3397 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -3002 3407 -1404 +RAW_Data: 1595 -7378 2189 -2976 3371 -2942 3489 -2908 3291 -3120 3341 -3164 3173 -3188 3189 -3190 3393 -3006 3399 -2998 3205 -3194 3395 -2994 3401 -3006 3399 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -3002 1799 -1402 1795 -1394 1797 -1400 3403 -3002 3401 -1402 1795 -2994 3407 -1396 1791 -1398 1801 -3002 3403 -2994 1799 -1402 1801 -1400 3401 -2994 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 3391 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -2994 1801 -1400 3401 -4138 9989 -410 4445 -2630 3617 -2814 3415 -3006 3401 -3002 3401 -3004 3393 -3002 3393 -3002 3403 -2994 3401 -3002 3395 -3006 3197 -1598 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -3006 1605 -1596 1793 -1394 1795 -1402 3401 -3002 3401 -1398 1791 -3000 3401 -1402 1799 -1402 1801 -3002 3393 -3002 1795 -1394 3399 -3002 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 3401 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -3002 3395 -7518 2025 -2782 3651 -2826 3417 -3010 3407 -3010 3409 -2998 3389 -2996 3397 -3010 3397 -2994 3203 -3194 3393 -3002 3395 -3002 3401 -2994 3401 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1398 1799 -1402 1801 -1396 3389 -3004 3401 -1400 1801 -3006 3397 -1398 1791 -1398 1801 -3002 3401 -2994 1801 -1402 3401 -1400 1597 -3190 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 +RAW_Data: 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 3401 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -2994 4001 -3412 1945 -2826 3517 -2924 3347 -3164 3381 -2988 3389 -2994 3393 -2996 3401 -3002 3393 -3002 3403 -2994 3401 -2994 3401 -3004 3393 -3002 3393 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -2992 1799 -1402 1799 -1402 1801 -1400 3393 -3004 3401 -1396 1793 -3002 3405 -1398 1797 -1400 1801 -3002 3393 -3006 3399 -2994 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1394 3397 -3004 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 3601 -1280 5101 -3078 3271 -3238 3223 -3014 3409 -3006 3405 -2996 3401 -3002 3401 -2994 3395 -3002 3401 -3002 3393 -3004 3393 -3002 3393 -3002 3395 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -3002 1801 -1400 1801 -1396 1791 -1400 3401 -3002 3401 -1402 1799 -3002 3395 -1400 1797 -1394 1795 -3002 3403 -3002 3393 -3006 3205 -3196 1595 -1594 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 3395 -3002 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 3401 -7728 1751 -3100 3263 -3030 3413 -3014 3415 -3006 3209 -3202 +RAW_Data: 3193 -3200 3197 -3194 3393 -2998 3407 -2994 3393 -3002 3403 -2994 3401 -3002 3393 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1394 1797 -3002 1799 -1402 1801 -1400 1801 -1396 3391 -3002 3401 -1400 1801 -3002 3403 -1396 1791 -1398 1801 -3002 3401 -2996 3401 -1400 1797 -2990 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 3401 -3004 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1797 -1398 3401 -3002 4405 -2758 2807 -2942 3325 -2938 3367 -3180 3379 -2990 3189 -3190 3393 -2996 3401 -2994 3401 -3002 3395 -3002 3401 -2998 3205 -3196 3393 -2994 3401 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -3004 1799 -1402 1799 -1402 1801 -1396 3397 -3004 3393 -1400 1801 -3002 3395 -1400 1801 -1400 1795 -2996 3405 -2996 3401 -1400 1801 -1402 1795 -2990 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1398 1801 -1400 3401 -3004 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1398 3401 -1400 1801 -5956 861 -1316 1441 -3046 3355 -3176 3381 -2988 3389 -2994 3201 -3196 3393 -3002 3401 -2994 3403 -2994 3401 -3006 3397 -2996 3401 -2994 3401 -2994 3403 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -3002 1801 -1400 1801 -1400 1801 -1398 3389 -3002 3401 -1402 1799 -3004 3401 -1396 1793 -1398 1799 -3002 3403 -1396 1791 -3000 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 +RAW_Data: 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1398 3403 -3002 1801 -1400 1801 -1400 1795 -1396 1795 -1402 3401 -3002 1801 -1396 3991 -4480 15153 -2008 3809 -2602 3603 -3002 3401 -3002 3407 -3006 3393 -2994 3393 -3004 3405 -2998 3393 -3002 3395 -3002 3393 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -2994 1805 -1396 1797 -1402 1795 -1398 3401 -3002 3395 -1400 1801 -3006 3397 -1398 1791 -1398 1801 -3002 3401 -1398 1795 -3002 1801 -1402 3401 -3002 1597 -1592 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1597 -1592 1797 -1402 1799 -1402 3401 -3002 1801 -1396 1793 -1398 1799 -1402 1801 -1400 3401 -3002 3395 -7734 2455 -2034 3851 -2834 3419 -3014 3405 -3002 3401 -3002 3403 -3002 3393 -3002 3403 -2994 3401 -3002 3393 -2996 3401 -3002 3407 -2996 3399 -1404 1795 -1392 1795 -1402 1799 -1398 1797 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3006 3397 -1398 1791 -3000 3401 -1400 1801 -1398 1791 -2998 3403 -1400 1801 -3002 3401 -2994 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 3403 -3002 1795 -1394 1797 -1400 1801 -1402 1799 -1402 3401 -1398 1791 -3002 3607 -3594 2481 -2584 3775 -2732 3541 -2914 3491 -2916 3333 -3160 3375 -2982 3389 -2992 3393 -2994 3401 -3004 3393 -3002 3401 -2994 3395 -3002 3401 -1402 +RAW_Data: 1795 -1394 1797 -1400 1801 -1396 1797 -1400 1801 -3002 1801 -1400 1801 -1398 1795 -1402 3401 -3002 3395 -1400 1801 -2994 3401 -1402 1799 -1398 1791 -3000 3401 -1402 1799 -3002 3395 -1400 1801 -3002 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 3401 -3002 1801 -1400 1801 -1402 1795 -1394 1797 -1400 3401 -1402 1801 -1400 1801 -7478 1559 -3038 3563 -2982 3391 -2992 3395 -3002 3399 -2996 3391 -2994 3393 -2994 3403 -3002 3407 -3004 3393 -2996 3393 -3002 3401 -2994 3403 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -2994 1801 -1400 1801 -1396 1797 -1402 3401 -2994 3401 -1402 1799 -2996 3401 -1400 1801 -1402 1795 -2990 3407 -1404 1795 -1394 1797 -3002 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1597 -1594 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 3403 -2998 1603 -1598 1791 -1394 1797 -1402 3401 -3006 1605 -1596 1791 -1394 3399 -4468 1663 -3040 3363 -2940 3339 -3112 3293 -3122 3329 -3156 3367 -2982 3387 -2990 3393 -2994 3403 -3002 3401 -2994 3401 -3002 3395 -2994 3401 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -3002 1801 -1398 1791 -1398 1801 -1400 3401 -3006 3207 -1594 1789 -2992 3401 -1402 1801 -1400 1801 -2994 3401 -1402 1799 -1398 1797 -3002 3401 -3002 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 +RAW_Data: 1797 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 3401 -3002 1801 -1398 1795 -1402 1799 -1398 3403 -3004 1597 -1594 3389 -3402 1499 -440 419 -600 599 -766 1693 -3100 3401 -3002 3395 -2994 3401 -3002 3395 -3002 3393 -3006 3205 -3200 3197 -3194 3201 -3194 3403 -2994 3401 -3002 3395 -3006 3397 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1793 -2998 1801 -1400 1801 -1402 1799 -1402 3393 -3002 3401 -1398 1797 -3002 3401 -1398 1795 -1398 1797 -3002 3401 -1400 1797 -1398 1799 -1402 1801 -2994 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 3401 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3401 -2996 4203 -806 201 -2874 1835 -2990 3405 -2996 3393 -3002 3393 -3004 3405 -2998 3393 -2994 3403 -2994 3401 -2994 3403 -3002 3401 -2994 3401 -2994 3403 -3002 3393 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -3002 1801 -1398 1795 -1402 1799 -1398 3397 -3002 3403 -1396 1791 -3000 3401 -1402 1799 -1402 1801 -2998 3205 -1598 1791 -1394 1797 -1400 1801 -1400 1801 -3006 1605 -1596 1793 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 3401 -3002 1801 -1402 1799 -1402 1799 -1402 3393 -3002 3395 -1400 1801 -6000 21381 -2268 3645 -2836 3417 -3010 3407 -3008 3403 -2998 3399 -2996 3395 -2994 3401 -2994 3401 -2996 3401 -1400 1801 -1402 1795 -1398 1799 -1402 1795 -1394 1797 -3002 1801 -1400 +RAW_Data: 1801 -1400 1801 -1398 3397 -3002 3401 -1398 1791 -3000 3405 -1406 1795 -1394 1795 -1402 1801 -3006 1599 -1594 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 3401 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -1398 1795 -3002 1801 -1402 3601 -4730 8239 -2608 3611 -3002 3401 -3002 3401 -3002 3395 -3002 3401 -2998 3399 -3002 3393 -3002 3401 -2996 3401 -2994 3407 -2996 3399 -1404 1795 -1396 1791 -1398 1799 -1402 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3006 3397 -1398 1791 -3000 3401 -1400 1801 -1398 1795 -1402 1801 -3002 1795 -1398 1801 -1400 1801 -1396 3391 -3002 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 3401 -2994 1801 -1400 1801 -1396 1793 -1398 3401 -1400 1801 -3006 3397 -7406 3789 -200 4429 -2816 3413 -3014 3407 -3002 3407 -3004 3393 -3000 3397 -2994 3401 -2996 3401 -3002 3399 -3004 3395 -2994 3401 -2994 3401 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -3002 3393 -1402 1799 -3002 3395 -1400 1801 -1396 1793 -1398 1799 -3006 1805 -1398 1791 -1398 3401 -3002 1801 -1396 1797 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 +RAW_Data: 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 3403 -2994 1799 -1402 1801 -1396 1797 -1400 3403 -1400 1795 -1394 1797 -3002 3401 -4904 1617 -2646 3741 -2764 3575 -2986 3385 -2994 3395 -3002 3393 -3002 3393 -3004 3393 -3002 3401 -3002 3395 -3002 3393 -3002 3403 -2994 3401 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -2994 3401 -1402 1801 -2998 3205 -1598 1791 -1394 1797 -1400 1801 -3002 1801 -1400 1801 -1396 3399 -1400 1801 -3002 1595 -1594 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 3401 -3002 1801 -1400 1801 -1400 1797 -1394 3397 -1402 1799 -1402 1799 -1402 1795 -6010 3547 -1150 3953 -2576 3585 -2990 3395 -2994 3393 -3002 3403 -3002 3393 -3002 3407 -2996 3395 -2994 3401 -3002 3395 -3002 3401 -2994 3393 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -3002 1799 -1402 1795 -1398 1801 -1400 3403 -2994 3401 -1400 1797 -2998 3407 -1404 1597 -1592 1793 -1398 1799 -3002 1801 -1402 3401 -2998 1605 -1596 1791 -1398 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 3403 -2994 1799 -1402 1801 -1400 3401 -2998 1805 -1398 1791 -1398 1801 -1400 3601 -4812 1887 -2884 3391 -2994 3393 -2994 3395 -2994 3401 -3002 3393 -3004 3401 -2994 3401 -3002 3395 -3002 3201 -3198 3205 -3196 3393 -2998 3205 -1598 1791 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1398 1799 -1402 1801 -1400 3393 -3004 +RAW_Data: 3393 -1400 1801 -3002 3395 -1400 1801 -1400 1801 -1396 1793 -2998 1801 -1400 3403 -2994 3401 -3002 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 3401 -3002 1797 -1394 1795 -1402 3401 -3002 1801 -1398 1791 -1398 3401 -4786 197 -1694 1655 -3046 3275 -3160 3351 -3136 3317 -2902 3311 -3324 3147 -3168 3181 -3186 3191 -3194 3393 -3002 3401 -2996 3401 -3002 3393 -3002 3395 -1396 1797 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1402 3401 -3002 3401 -1398 1791 -3004 3405 -1396 1793 -1398 1799 -1402 1801 -3002 1799 -1398 3397 -1402 1799 -2994 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1400 3401 -2998 1805 -1396 1791 -1394 3399 -3002 1801 -1400 3401 -3002 4219 -3452 1989 -2654 3675 -2776 3467 -2882 3487 -3110 3319 -2932 3561 -2974 3381 -2992 3393 -2998 3393 -2996 3393 -3002 3401 -3002 3395 -3002 3393 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -3002 1795 -1398 1801 -1402 1799 -1402 3401 -2994 3403 -1400 1795 -2992 3401 -1402 1799 -1402 1801 -1400 1795 -2992 1801 -1396 3397 -1402 1801 -1400 1801 -3002 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1597 -1592 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 +RAW_Data: 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 3401 -2998 1805 -1400 1797 -1394 3397 -3002 1801 -1396 3399 -1400 1801 -7622 2021 -2904 3499 -2872 3443 -3018 3413 -3006 3411 -3006 3397 -3006 3393 -2994 3403 -2994 3401 -3002 3395 -3002 3393 -3002 3401 -2994 3403 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -2998 1605 -1596 1791 -1394 1797 -1402 3401 -3002 3401 -1402 1799 -3004 3393 -1396 1797 -1402 1799 -1402 1801 -2994 3401 -3002 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 3397 -3002 1801 -1396 1797 -1400 3403 -3002 3393 -3002 1801 -1396 4405 -3580 2203 -2680 3433 -3018 3415 -3006 3401 -3002 3401 -3002 3395 -3002 3393 -3002 3401 -2996 3401 -2994 3401 -3002 3203 -3194 3399 -3004 3393 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -3002 1795 -1394 1797 -1400 1801 -1400 3403 -2998 3205 -1598 1791 -2998 3403 -1400 1801 -1396 1793 -1398 1799 -3002 3403 -3006 1599 -1592 3401 -3004 1597 -1594 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 3391 -3002 1799 -1402 1801 -1400 3401 -2996 3401 -2994 3401 -7234 3089 -2524 3707 -2718 3733 -2896 3467 -2840 3421 -3020 3405 -3002 3401 -3002 3403 -3002 3393 -3002 3407 -2998 3393 -3002 3399 -2996 3399 -1404 1795 -1394 1793 -1398 1799 -1402 1801 -1400 1801 -3002 1801 -1400 1795 -1394 1793 -1398 3401 -3002 3401 -1402 1799 -3004 3401 -1396 1793 -1398 1799 -1402 1799 -3004 3401 -2994 3401 -2998 1805 -1398 +RAW_Data: 1791 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1595 -1594 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1400 3401 -3006 1599 -1594 1791 -1398 3403 -3002 3401 -1398 1791 -2998 4003 -4646 1945 -2714 3615 -2814 3409 -3002 3407 -3004 3395 -3006 3397 -2994 3395 -3002 3401 -3002 3393 -3004 3401 -2994 3393 -3002 3403 -2994 3401 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -3002 1795 -1398 1801 -1402 1799 -1402 3401 -2994 3395 -1400 1801 -3002 3393 -1402 1795 -1398 1801 -1400 1801 -2990 3401 -3002 3403 -1400 1801 -3002 1597 -1592 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 3401 -3002 1801 -1396 1797 -1402 3401 -3002 3393 -1398 1797 -1400 1801 -7714 15297 -1990 4001 -2594 3603 -2994 3401 -3002 3393 -3004 3393 -3002 3401 -3002 3395 -3002 3393 -2994 3407 -3006 3393 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -2998 1801 -1396 1797 -1402 1799 -1402 3401 -2994 3401 -1402 1795 -3000 3401 -1402 1795 -1398 1799 -1398 1797 -3002 3401 -1402 1799 -2994 1801 -1402 1799 -1402 1595 -1594 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 +RAW_Data: 1795 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 3401 -3002 1801 -1396 1797 -1402 3401 -1396 1797 -3002 1801 -1400 1801 -1398 3389 -4226 1665 -3024 3337 -3164 3373 -2986 3387 -2994 3393 -3002 3395 -3002 3407 -2996 3395 -2994 3401 -3002 3393 -2996 3401 -3002 3401 -2998 3399 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -2994 1799 -1398 1797 -1400 1801 -1400 3407 -3006 3193 -1598 1791 -3000 3401 -1396 1797 -1402 1799 -1402 1799 -3002 3395 -1396 1797 -3002 3401 -2996 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1597 -1592 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 3403 -2998 1603 -1598 1791 -1394 3399 -1400 1801 -3002 1801 -1400 3401 -7946 8393 -2610 3601 -3002 3403 -3002 3401 -3002 3393 -3004 3401 -3002 3393 -2994 3407 -3006 3393 -2994 3401 -2996 3401 -2994 3401 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -3002 1801 -1398 1791 -1394 1797 -1400 3407 -3006 3401 -1396 1793 -2998 3407 -1404 1795 -1394 1797 -1400 1801 -3002 3403 -1396 1791 -1394 1797 -3002 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1791 -1400 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 3401 -3004 1595 -1594 1795 -1402 3401 -1402 1799 -3004 3393 -3002 4001 -3612 15189 -2202 3801 -2602 3601 -3004 3401 -3002 3401 -2994 3403 -2994 3407 -2996 3399 -3010 3397 -2990 3393 -3004 3393 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1801 -1396 1791 -1398 1801 -1402 3401 -3002 3401 -1402 1795 -2992 3401 -1400 1801 -1402 1799 -1402 1795 -2992 3401 -1402 1799 -1402 1799 -1398 1791 -3000 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 +RAW_Data: 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 3401 -3006 1601 -1596 1791 -1398 3403 -1400 1801 -3002 3393 -1402 1801 -4208 1657 -1960 1633 -3076 3349 -3166 3183 -3186 3189 -3194 3395 -3002 3401 -2994 3403 -2994 3401 -3002 3399 -3004 3395 -3002 3393 -2994 3403 -3002 3201 -1598 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1793 -2998 1801 -1400 1801 -1402 1799 -1402 3401 -2994 3403 -1396 1791 -3000 3401 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -3002 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1597 -1592 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 3395 -3004 1601 -1596 1793 -1398 3401 -1400 1801 -1402 1799 -3002 1797 -1394 3797 -4466 8859 -2000 3797 -2810 3401 -3002 3401 -3002 3403 -3002 3393 -2994 3403 -3002 3401 -3002 3393 -3002 3407 -2998 3399 -2996 3395 -1396 1797 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -3002 1799 -1402 1801 -1396 1797 -1400 3403 -2998 3205 -1598 1791 -3000 3401 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -3002 1799 -1398 1791 -1398 3401 -3004 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 3403 -2994 1799 -1402 1795 -1394 +RAW_Data: 3399 -1400 1801 -1400 1801 -3002 3205 -4194 389 -3580 1837 -3274 3173 -3082 3345 -3118 3293 -3118 3317 -3142 3163 -3174 3183 -3190 3393 -2996 3401 -2994 3401 -3002 3395 -3002 3205 -3198 3393 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -2992 1799 -1402 1801 -1400 1801 -1400 3403 -2994 3401 -1400 1801 -3002 3395 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -3004 1799 -1398 3389 -3002 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1595 -1594 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 3401 -3004 1799 -1402 1795 -1398 3401 -1398 1797 -1400 1801 -1400 1801 -2994 4407 -3396 2177 -2946 3427 -3018 3407 -3004 3407 -3006 3389 -3002 3393 -3004 3393 -3002 3401 -2994 3403 -3002 3393 -3002 3395 -3002 3393 -3002 3393 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 1799 -2996 1799 -1402 1795 -1398 1801 -1400 3407 -3004 3395 -1396 1793 -2998 3407 -1400 1791 -1394 1797 -1400 1801 -1402 1799 -3002 1801 -1402 3401 -1396 1793 -2998 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 3401 -3004 1799 -1402 1795 -1394 3397 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -7678 1989 -2426 3963 -2528 3683 -2904 3519 -2930 3347 -3168 3373 -2988 3389 -2994 3401 -2996 3401 -2994 3401 -3002 3395 -3002 3401 -2994 3401 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -3002 1799 -1402 1801 -1396 1797 -1400 3403 -3002 3393 -1400 1801 -2994 3403 -1400 1795 -1398 1801 -1402 1799 -1402 1795 -2992 3401 -3002 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 +RAW_Data: 1797 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1599 -1598 1791 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1601 -1598 1791 -1398 1799 -1402 1801 -1396 3397 -3004 1799 -1402 3401 -2994 1801 -1400 1601 -1598 1791 -1398 1801 -1400 3401 -4800 1839 -2646 3737 -2764 3573 -2988 3385 -2994 3395 -3002 3393 -3002 3401 -2994 3403 -3002 3393 -2994 3407 -3006 3393 -2994 3401 -3004 3393 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1400 1801 -1402 3405 -3006 3389 -1398 1797 -3002 3405 -1402 1789 -1392 1797 -1400 1801 -1400 1801 -3002 3401 -3002 3395 -3002 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1795 -1400 1799 -1402 1799 -1402 1795 -1398 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1398 1801 -1402 3401 -2994 1801 -1400 3403 -3002 1595 -1594 1797 -1400 1801 -1400 3403 -7764 1463 -3208 3319 -2936 3563 -2976 3385 -2986 3391 -2994 3401 -2994 3401 -2996 3401 -3002 3401 -2994 3403 -2994 3401 -3002 3395 -3002 3401 -1396 1793 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -3002 1801 -1396 1797 -1402 1799 -1402 3405 -2998 3399 -1404 1597 -3190 3401 -1402 1795 -1398 1801 -1400 1795 -1394 1797 -3002 3401 -1402 1801 -2994 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 3401 -3002 1801 -1396 3391 -3002 1799 -1402 1801 -1400 3401 -2996 3401 -1706 +RAW_Data: 219 -2872 1657 -2822 3519 -2942 3559 -2974 3385 -2992 3389 -3002 3401 -2994 3403 -2994 3407 -2996 3395 -3002 3393 -3002 3393 -3004 3401 -2994 3401 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -3000 1803 -1398 1791 -1398 1801 -1400 3401 -3004 3393 -1400 1801 -2994 3401 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -3002 3403 -1400 1597 -1592 1797 -3002 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 3401 -2994 1801 -1402 3401 -2994 1801 -1400 1795 -1396 3397 -1400 1801 -7342 2387 -2176 3817 -2614 3601 -3002 3403 -3002 3401 -3002 3401 -2996 3405 -2998 3393 -3002 3395 -3002 3393 -3002 3407 -2998 3401 -2994 3393 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -3004 1799 -1402 1795 -1394 1797 -1400 3403 -3002 3401 -1400 1597 -3190 3403 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1795 -3000 1799 -1402 1795 -1398 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 3401 -3004 1799 -1398 3389 -3002 1801 -1400 3395 -3002 1799 -1402 3593 -4558 1793 -2438 3923 -2740 3563 -2976 3385 -2990 3395 -2994 3401 -2994 3403 -2994 3401 -2994 3401 -3004 3401 -2994 3401 -2994 3407 -2998 3393 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -2994 1801 -1402 1799 -1402 1799 -1398 3389 -3002 3403 -1400 1801 -3002 3401 -1398 1791 -1398 1801 -1396 1797 -1400 1801 -1402 1799 -3002 1801 -1398 3397 -3002 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 +RAW_Data: 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1597 -1592 1797 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 3401 -2994 1801 -1400 3403 -3002 1595 -1594 3397 -3002 3395 -7924 1529 -3076 3409 -3002 3403 -3002 3401 -3002 3401 -2996 3393 -3002 3401 -2994 3407 -2998 3393 -3002 3401 -2996 3401 -2994 3401 -3002 3399 -1404 1795 -1394 1793 -1398 1799 -1402 1801 -1396 1797 -3002 1801 -1400 1801 -1400 1801 -1402 3397 -3010 3197 -1598 1791 -2992 3401 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -3002 3401 -3000 1603 -1598 1791 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1597 -1592 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1394 3397 -3002 1801 -1400 3401 -2996 1799 -1402 3407 -1400 1591 -3192 3601 -4992 1735 -2952 3401 -3006 3401 -3002 3403 -3002 3401 -2998 3397 -2996 3405 -2998 3399 -3004 3195 -3194 3401 -2994 3403 -2994 3405 -3006 3193 -1598 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1791 -3000 1799 -1402 1799 -1402 1801 -1400 3395 -3002 3401 -1396 1793 -2990 3403 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -3002 3401 -1398 1791 -2998 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1396 1797 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1402 1599 -1598 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1398 1795 -1402 1801 -1400 1801 -1400 1601 -1596 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1797 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 3401 -3004 1795 -1394 3397 -3002 1801 -1400 3403 -1396 1791 -1398 1801 -8002 1987 -2168 4109 -2272 4115 -2502 3705 -2690 3651 -2834 3423 -3016 +RAW_Data: 3403 -3002 3401 -3002 3401 -3002 3395 -3002 3407 -2996 3395 -2994 3401 -1402 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -3002 1795 -1394 1797 -1402 1799 -1402 3401 -3002 3395 -1400 1795 -3000 3407 -1404 1795 -1394 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -3004 1795 -1394 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1799 -1402 1801 -1396 1791 -1398 1801 -1402 1799 -1402 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1402 1597 -1592 1797 -1400 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1400 1801 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -1398 1795 -1402 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1402 3401 -2994 1801 -1400 3403 -2994 3401 -3002 1795 -1394 1797 -1402 3601 -1036 421 -848 843 -1518 1659 -2912 3565 -2984 3385 -2994 3395 -2994 3401 -2994 3401 -3004 3401 -2994 3401 -2994 3403 -2994 3401 -3002 3393 -3004 3393 -3002 3401 -1402 1795 -1394 1797 -1400 1801 -1400 1801 -1402 1799 -3002 1597 -1594 1795 -1402 1801 -1400 3401 -2996 3401 -1396 1797 -3002 3407 -1404 1597 -1592 1791 -1398 1801 -1402 1799 -1402 1799 -1402 1801 -2994 3401 -2994 1801 -1400 1801 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1801 -1402 1795 -1398 1795 -1398 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1801 -1400 1795 -1394 1797 -1402 1799 -1402 1801 -1396 1797 -1400 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1795 -1396 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1797 -1402 1799 -1398 1795 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1398 1797 -1400 1801 -1400 1797 -1398 1799 -1402 1799 -1402 1795 -1398 1801 -1400 1801 -1402 1795 -1394 1797 -1400 3401 -3002 1801 -1402 3393 -3002 3401 -3002 1597 -1594 3389 -7770 2021 -2912 3517 -3074 3245 -3022 3423 -3008 3411 -2998 3393 -2994 3401 -2994 3403 -3002 3393 -3002 3407 -2998 3393 -2994 3401 -3008 3397 -1396 1793 -1398 1799 -1402 1801 -1400 1801 -1396 1791 -3000 1801 -1400 1801 -1400 1801 -1402 3401 -2994 3393 -1402 1801 -3002 3401 -1398 1791 -1398 1799 -1402 1801 -1400 1801 -1400 1597 -1594 1795 -1402 1799 -3004 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1795 -1398 1801 -1400 1801 -1400 1797 -1394 1795 -1402 1801 -1400 1801 -1400 1801 -1400 1801 -1398 1791 -1398 1801 -1400 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 +RAW_Data: 1791 -1398 1801 -1400 1801 -1402 1799 -1402 1799 -1398 1791 -1398 1801 -1400 1801 -1402 1799 -1398 1797 -1400 1801 -1400 1801 -1400 1797 -1398 1799 -1402 1801 -1400 1795 -1398 1801 -1400 1801 -1402 1795 -1398 1801 -1400 1801 -1400 1597 -1594 1795 -1402 1799 -1402 1801 -1400 1801 -1396 1793 -1398 1799 -1402 1799 -1402 1801 -1400 1795 -1398 1801 -1402 1799 -1402 1799 -1402 1795 -1394 1797 -1400 1801 -1402 3401 -3002 1795 -1394 3399 -3002 3401 -2998 3405 -2996 3599 -1948 429 -20132 735 -734 1509 -192 387 -196272 217 -93450 441 -8180 183 -495896 381 -952 379 -594116 183 -209314 209 -296722 651 -199272 381 -98996 441 diff --git a/assets/resources/subghz/assets/alutech_at_4n b/assets/resources/subghz/assets/alutech_at_4n new file mode 100644 index 000000000..5d7beacec --- /dev/null +++ b/assets/resources/subghz/assets/alutech_at_4n @@ -0,0 +1,6 @@ +Filetype: Flipper SubGhz Keystore RAW File +Version: 0 +Encryption: 1 +IV: 88 64 A6 A6 44 47 67 8A D6 32 36 F6 B9 06 57 31 +Encrypt_data: RAW +E811BD4F0955D217AE6677906E799D45D8DAAFD1F7923E1660B5E24574631B60 \ No newline at end of file diff --git a/assets/resources/subghz/assets/extend_range.txt b/assets/resources/subghz/assets/extend_range.txt index e66e7ceb2..1b404a0e5 100644 --- a/assets/resources/subghz/assets/extend_range.txt +++ b/assets/resources/subghz/assets/extend_range.txt @@ -2,7 +2,7 @@ Filetype: Flipper SubGhz Setting File Version: 1 # Whether to allow extended ranges that can break your flipper -use_ext_range_at_own_risk: true +use_ext_range_at_own_risk: false # Whether to ignore the default TX region settings -ignore_default_tx_region: true +ignore_default_tx_region: false diff --git a/assets/resources/subghz/assets/setting_user b/assets/resources/subghz/assets/setting_user deleted file mode 100644 index d10392341..000000000 --- a/assets/resources/subghz/assets/setting_user +++ /dev/null @@ -1,45 +0,0 @@ -# to use manual settings and prevent them from being deleted on upgrade, rename *_user.example files to *_user -Filetype: Flipper SubGhz Setting File -Version: 1 - -# Add Standard frequencies for your region -Add_standard_frequencies: true - -# Default Frequency: used as default for "Read" and "Read Raw" -Default_frequency: 433920000 - -# Frequencies used for "Read", "Read Raw" and "Frequency Analyzer" -Frequency: 300000000 -Frequency: 310000000 -Frequency: 320000000 - -# Frequencies used for hopping mode (keep this list small or flipper will miss signal) -Hopper_frequency: 300000000 -Hopper_frequency: 310000000 -Hopper_frequency: 310000000 - -# Custom preset -# format for CC1101 "Custom_preset_data:" XX YY XX YY .. 00 00 ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ, where: XX-register, YY - register data, 00 00 - end load register, ZZ - 8 byte Pa table register - -Custom_preset_name: AM_1 -Custom_preset_module: CC1101 -Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00 - -Custom_preset_name: AM_2 -Custom_preset_module: CC1101 -Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00 - -Custom_preset_name: FM95 -Custom_preset_module: CC1101 -Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 24 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00 - -# Honda Presets -Custom_preset_name: Honda1 -Custom_preset_module: CC1101 -# G2 G3 G4 D L0 L1 L2 -Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00 - -Custom_preset_name: Honda2 -Custom_preset_module: CC1101 -# G2 G3 G4 D L0 L1 L2 -Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00 \ No newline at end of file diff --git a/assets/resources/subghz/assets/setting_user.txt b/assets/resources/subghz/assets/setting_user.txt index 06a699a6c..67e89dceb 100644 --- a/assets/resources/subghz/assets/setting_user.txt +++ b/assets/resources/subghz/assets/setting_user.txt @@ -51,6 +51,7 @@ Frequency: 438900000 Frequency: 440175000 Frequency: 446000000 Frequency: 464000000 +Frequency: 467750000 Frequency: 779000000 Frequency: 868350000 Frequency: 868400000 @@ -78,24 +79,3 @@ Hopper_frequency: 868350000 #Custom_preset_name: AM_2 #Custom_preset_module: CC1101 #Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00 - -# Custom presets added in Unleashed FW -# -- Some presets from forum.flipperzero.one -- - -#2-FSK 200khz BW / 135kHz Filter/ 15.86Khz Deviation + Ramping -Custom_preset_name: FM15k -Custom_preset_module: CC1101 -Custom_preset_data: 02 0D 03 47 08 32 0B 06 15 32 14 00 13 00 12 00 11 32 10 A7 18 18 19 1D 1D 92 1C 00 1B 04 20 FB 22 17 21 B6 00 00 00 12 0E 34 60 C5 C1 C0 - -# -- Other presets -- - -# Honda Presets -Custom_preset_name: Honda1 -Custom_preset_module: CC1101 -# G2 G3 G4 D L0 L1 L2 -Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00 - -Custom_preset_name: Honda2 -Custom_preset_module: CC1101 -# G2 G3 G4 D L0 L1 L2 -Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00 diff --git a/assets/resources/wav_player/CartKeyLock78.wav b/assets/resources/wav_player/CartKeyLock78.wav index 71f56f328..744f9d1a0 100644 Binary files a/assets/resources/wav_player/CartKeyLock78.wav and b/assets/resources/wav_player/CartKeyLock78.wav differ diff --git a/assets/resources/wav_player/CartKeyUnlock78.wav b/assets/resources/wav_player/CartKeyUnlock78.wav index 41bd420e9..a82a45803 100644 Binary files a/assets/resources/wav_player/CartKeyUnlock78.wav and b/assets/resources/wav_player/CartKeyUnlock78.wav differ diff --git a/assets/slideshow/update_default/frame_00.png b/assets/slideshow/update_default/frame_00.png index 5be266606..9d2da78f8 100644 Binary files a/assets/slideshow/update_default/frame_00.png and b/assets/slideshow/update_default/frame_00.png differ diff --git a/assets/unit_tests/subghz/alutech_at_4n_raw.sub b/assets/unit_tests/subghz/alutech_at_4n_raw.sub new file mode 100644 index 000000000..ae5db9715 --- /dev/null +++ b/assets/unit_tests/subghz/alutech_at_4n_raw.sub @@ -0,0 +1,10 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: -854 811 -454 811 -444 409 -838 811 -454 823 -432 385 -842 811 -454 389 -854 821 -418 837 -444 401 -850 417 -854 395 -830 417 -846 819 -432 811 -448 789 -444 839 -454 401 -856 381 -850 825 -410 841 -418 417 -834 411 -840 827 -442 417 -844 799 -472 809 -420 411 -842 419 -848 397 -822 413 -850 799 -486 381 -848 415 -854 423 -16394 449 -358 437 -386 411 -384 449 -382 417 -384 419 -386 417 -386 419 -388 419 -388 419 -388 419 -390 437 -4036 421 -810 425 -820 393 -866 813 -422 415 -856 397 -858 811 -456 427 -820 815 -416 419 -850 401 -854 805 -420 835 -444 409 -842 809 -454 433 -820 421 -838 813 -420 417 -822 435 -820 419 -834 431 -852 411 -866 805 -420 815 -444 805 -454 403 -824 809 -448 819 -448 413 -844 811 -446 811 -456 409 -816 809 -456 389 -866 387 -842 809 -454 827 -432 413 -850 829 -428 809 -452 381 -852 799 -452 413 -852 807 -450 801 -444 409 -872 411 -840 413 -812 413 -832 807 -450 815 -442 801 -454 809 -454 429 -820 419 -838 811 -456 785 -428 409 -842 439 -824 813 -448 415 -858 819 -418 831 -426 449 -808 427 -820 393 -866 421 -808 825 -436 413 -852 403 -884 421 -16394 407 -478 257 -574 229 -576 229 -564 231 -592 267 -490 305 -520 307 -486 309 -522 307 -458 341 -486 337 -4096 343 -882 389 -880 341 -874 807 -476 351 -882 397 -860 807 -450 431 -824 811 -450 399 -824 417 -844 817 -432 807 -448 411 -872 801 -460 417 -810 425 -836 809 -420 411 -838 409 -852 417 -844 425 -852 385 -872 801 -426 841 -420 811 -422 409 -844 809 -454 823 -432 415 -842 835 -450 805 -454 403 -822 809 -450 399 -826 417 -844 821 -434 807 -448 411 -876 801 -440 807 -450 383 -850 833 -416 415 -852 807 -456 811 -444 411 -838 419 -848 401 -852 377 -850 819 -454 795 -436 809 -448 821 -448 411 -846 417 -842 817 -432 811 -412 411 -864 417 -844 791 -438 415 -876 793 -458 809 -450 383 -832 413 -840 407 -866 387 -844 821 -434 413 -874 377 -868 419 -16408 411 -392 421 -390 421 -388 421 -376 427 -394 433 -388 409 -386 411 -384 449 -382 419 -384 419 -384 419 -4018 343 -89684 97 -430 65 -166 163 -66 231 -100 161 -392 161 -64 229 -1056 97 -198 97 -198 259 -166 691 -66 395 -98 131 -100 99 -66 199 -198 1657 -406 365 -462 361 -436 357 -438 387 -444 353 -444 385 -414 387 -448 355 -448 355 -444 395 -394 399 -4050 819 -434 811 -414 819 -450 409 -852 809 -450 805 -448 805 -446 831 -428 409 -846 389 -854 395 -862 811 +RAW_Data: -452 783 -462 811 -446 411 -874 383 -852 403 -852 777 -450 411 -838 805 -452 397 -858 805 -484 387 -872 803 -442 805 -448 383 -846 797 -484 777 -474 381 -846 831 -430 807 -482 387 -852 817 -418 805 -452 823 -430 385 -878 377 -876 411 -846 391 -884 811 -444 805 -420 415 -846 399 -852 807 -452 805 -444 803 -450 803 -454 807 -452 397 -850 395 -862 385 -844 427 -840 809 -456 379 -876 407 -880 383 -846 819 -432 387 -872 375 -854 413 -846 387 -886 779 -476 803 -450 801 -444 415 -846 793 -438 415 -846 417 -822 407 -852 417 -852 817 -444 409 -16426 443 -358 431 -388 409 -386 447 -350 449 -382 419 -386 419 -386 417 -386 419 -388 453 -354 453 -356 445 -4018 813 -416 839 -420 817 -418 451 -816 835 -444 809 -450 811 -440 803 -444 407 -830 419 -844 419 -836 805 -420 835 -444 803 -446 409 -868 421 -814 431 -822 807 -452 397 -828 819 -452 415 -856 787 -454 419 -848 837 -410 839 -416 395 -866 787 -450 811 -454 407 -850 805 -454 805 -470 381 -850 833 -418 805 -438 809 -448 397 -860 421 -810 431 -856 381 -888 791 -424 841 -422 415 -820 437 -818 813 -450 813 -454 803 -446 817 -448 829 -410 451 -816 403 -818 413 -850 409 -846 811 -448 415 -834 413 -884 399 -822 815 -452 381 -852 407 -846 415 -846 385 -866 807 -456 809 -446 835 -412 407 -834 815 -450 415 -822 405 -848 419 -844 427 -852 809 -442 407 -16420 425 -422 335 -486 309 -486 309 -522 307 -492 337 -454 351 -466 329 -498 327 -468 323 -472 355 -442 355 -4120 757 -456 773 -478 781 -458 381 -874 771 -482 801 -470 777 -482 805 -450 399 -826 415 -846 387 -866 805 -420 813 -446 831 -458 417 -846 401 -852 381 -840 835 -420 415 -846 795 -440 413 -842 835 -450 407 -860 811 -418 815 -424 413 -842 807 -454 823 -428 411 -842 801 -454 807 -488 401 -822 805 -448 803 -446 803 -426 447 -844 397 -856 381 -870 411 -870 777 -452 829 -432 385 -840 419 -848 797 -438 809 -450 815 -448 833 -440 803 -452 411 -820 415 -848 409 -844 411 -846 779 -462 409 -848 409 -864 421 -844 793 -438 385 -846 419 -850 399 -838 415 -872 777 -478 803 -448 799 -442 417 -848 799 -438 415 -842 409 -826 417 -844 427 -854 807 -452 409 -16402 461 -352 421 -386 421 -386 419 -388 453 -354 453 -354 447 -378 409 -386 439 -376 421 -410 385 -414 415 -4024 831 -418 809 -438 807 -444 409 -838 809 -456 821 -432 841 -414 255 -87638 131 -66 97 -296 97 -264 131 -196 65 -132 231 -632 197 -664 131 +RAW_Data: -500 395 -132 461 -132 689 -98 2685 -100 997 -1508 99 -2186 231 -166 231 -134 133 -932 65 -268 99 -132 65 -200 97 -68 163 -234 65 -68 99 -930 331 -98 763 -100 2025 -418 353 -446 385 -414 385 -416 387 -448 355 -442 383 -412 397 -424 405 -388 409 -418 379 -418 415 -4014 443 -814 413 -822 817 -454 801 -436 409 -842 409 -866 415 -838 441 -836 811 -432 387 -842 419 -846 793 -440 807 -448 837 -446 803 -448 835 -420 807 -448 383 -868 379 -850 409 -866 387 -844 825 -468 381 -884 793 -426 415 -842 427 -818 817 -440 407 -830 419 -844 429 -852 387 -872 409 -826 811 -450 813 -418 837 -412 409 -864 417 -844 397 -852 809 -454 805 -448 409 -840 809 -420 813 -458 409 -844 407 -860 385 -878 793 -470 809 -420 817 -416 417 -850 403 -852 381 -852 827 -428 447 -844 401 -854 813 -424 421 -840 419 -812 823 -438 415 -846 409 -844 415 -846 389 -868 809 -458 803 -416 409 -866 813 -418 417 -854 397 -862 419 -842 401 -854 415 -16404 435 -376 409 -410 407 -384 439 -384 409 -410 417 -368 421 -410 407 -378 447 -376 415 -378 447 -380 407 -4022 421 -844 423 -822 821 -418 807 -454 429 -820 421 -836 439 -854 421 -810 821 -436 385 -840 441 -822 813 -448 811 -452 803 -444 835 -444 801 -446 801 -426 447 -808 423 -834 413 -852 407 -840 819 -452 389 -856 813 -444 409 -848 415 -812 809 -458 409 -848 411 -842 415 -844 421 -834 415 -834 835 -418 819 -418 807 -456 393 -856 393 -866 421 -846 799 -474 809 -420 421 -836 811 -420 813 -458 407 -850 413 -842 415 -846 819 -428 835 -416 835 -412 407 -832 421 -842 423 -822 813 -446 407 -864 419 -846 799 -440 413 -850 419 -816 797 -442 413 -850 409 -844 417 -846 423 -834 841 -428 805 -414 435 -822 813 -450 413 -822 437 -818 421 -844 429 -854 411 -16406 427 -418 309 -522 307 -488 303 -520 289 -530 295 -500 323 -470 325 -504 321 -476 321 -476 355 -444 357 -4080 355 -906 339 -882 771 -476 777 -486 381 -874 383 -884 375 -884 387 -852 819 -418 417 -846 399 -854 809 -418 815 -446 837 -420 839 -454 801 -436 807 -452 399 -826 417 -844 391 -852 423 -838 809 -452 431 -852 811 -414 409 -836 417 -844 821 -432 385 -876 385 -850 409 -848 415 -854 421 -840 817 -420 815 -424 817 -448 409 -848 413 -844 389 -854 815 -446 829 -426 413 -842 819 -434 809 -446 409 -838 419 -846 401 -852 811 -456 811 -444 803 -418 417 -848 403 -850 381 -864 805 -450 395 -866 419 -848 801 -474 381 -848 411 +RAW_Data: -842 807 -446 381 -872 377 -866 421 -846 401 -854 813 -458 779 -446 407 -832 811 -450 415 -856 399 -856 385 -876 399 -854 411 -16398 435 -392 395 -400 421 -412 385 -412 417 -384 415 -386 415 -418 385 -420 385 -420 417 -390 417 -388 419 -4020 421 -838 421 -812 819 -434 809 -448 397 -864 421 -844 401 -850 413 -858 789 -426 413 -844 419 -836 807 -424 843 -410 829 -442 835 -446 801 -454 809 -420 417 -832 411 -848 249 -88020 133 -896 231 -466 67 -1062 131 -728 163 -98 621 -98 1051 -100 680933 -452 269 -522 273 -554 273 -558 239 -558 271 -490 337 -488 321 -498 295 -500 325 -470 323 -474 353 -4082 757 -492 375 -880 357 -872 777 -486 773 -480 807 -450 805 -444 805 -476 407 -812 413 -834 411 -848 407 -828 813 -450 811 -458 803 -448 835 -446 791 -424 447 -808 427 -818 423 -840 419 -848 401 -854 811 -458 809 -446 801 -416 439 -826 415 -848 813 -430 809 -450 395 -866 419 -846 403 -850 413 -820 407 -848 415 -846 781 -460 805 -446 803 -474 803 -448 835 -420 805 -454 389 -836 409 -842 407 -866 419 -842 399 -854 809 -456 809 -446 409 -840 385 -844 819 -434 809 -450 395 -860 811 -452 393 -886 779 -446 409 -830 419 -842 423 -818 423 -838 419 -844 799 -472 809 -454 385 -844 807 -454 391 -854 395 -860 385 -844 429 -852 809 -454 385 -874 409 -16402 427 -368 455 -358 433 -380 443 -378 415 -378 447 -380 411 -384 409 -406 421 -408 387 -412 415 -386 415 -4026 831 -398 441 -810 417 -832 837 -418 833 -444 803 -446 833 -448 801 -424 449 -810 427 -820 423 -838 419 -812 825 -438 841 -416 845 -446 825 -418 809 -422 419 -822 433 -822 419 -844 425 -820 421 -840 841 -458 797 -436 809 -414 435 -822 419 -844 819 -432 809 -448 395 -864 421 -846 407 -850 411 -808 433 -824 419 -844 819 -432 809 -446 823 -416 837 -454 807 -440 809 -414 435 -828 417 -844 425 -828 415 -848 419 -818 839 -446 807 -422 411 -844 419 -846 795 -438 807 -450 395 -866 811 -454 391 -854 845 -412 407 -832 421 -842 419 -832 411 -824 435 -820 815 -450 811 -460 409 -850 799 -454 407 -824 413 -848 411 -842 415 -844 815 -432 415 -848 405 -16400 441 -432 327 -492 301 -516 307 -484 309 -520 307 -492 339 -454 337 -490 331 -464 327 -500 325 -472 325 -4110 763 -480 373 -852 385 -878 759 -482 775 -474 813 -458 781 -482 789 -454 415 -846 397 -820 411 -840 405 -852 809 -450 811 -458 809 -450 817 -448 803 -426 411 -844 391 -854 393 -866 419 -848 399 -854 811 +RAW_Data: -454 811 -444 803 -418 417 -846 403 -850 809 -452 805 -444 411 -840 419 -846 407 -850 415 -836 385 -842 419 -850 797 -438 807 -452 817 -446 801 -486 813 -444 775 -450 409 -838 419 -810 431 -854 379 -848 405 -884 809 -450 817 -430 385 -874 375 -856 811 -446 809 -422 421 -836 835 -452 419 -848 783 -460 409 -814 407 -856 415 -846 383 -870 381 -848 819 -450 811 -472 383 -850 803 -454 415 -838 399 -854 379 -850 407 -848 811 -448 415 -872 387 -16400 451 -374 445 -374 415 -378 415 -412 411 -384 405 -422 409 -410 387 -410 417 -382 417 -384 415 -420 383 -4030 827 -428 411 -842 425 -820 817 -418 833 -426 845 -452 815 -428 837 -416 409 -842 421 -810 431 -820 421 -89106 265 -662 99 -532 131 -598 97 -668 65 -300 761 -198 231 -132 265 -100 233 -100 197 diff --git a/assets/unit_tests/subghz/dooya.sub b/assets/unit_tests/subghz/dooya.sub new file mode 100644 index 000000000..0767a1a73 --- /dev/null +++ b/assets/unit_tests/subghz/dooya.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: Dooya +Bit: 40 +Key: 00 00 00 E1 DC 03 05 11 diff --git a/assets/unit_tests/subghz/dooya_raw.sub b/assets/unit_tests/subghz/dooya_raw.sub new file mode 100644 index 000000000..6c3ca1627 --- /dev/null +++ b/assets/unit_tests/subghz/dooya_raw.sub @@ -0,0 +1,8 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 4046 -17306 65 -298 97 -100 133 -268 265 -330 133 -132 1723 -16806 165 -132 99 -920 65 -622 789 -130 99 -66 361 -98 295 -166 73573 -17510 97 -492 129 -728 529 -100 1063 -164 295 -66 1119 -14962 627 -166 363 -264 427 -132 593 -100 633 -132 39555 -16938 99 -2024 65 -100 97 -164 99 -66 399 -100 123891 -16736 163 -200 97 -200 165 -264 65 -828 427 -132 871 -5132 591 -490 595 -486 605 -454 275 -822 241 -824 273 -784 321 -782 649 -444 653 -408 657 -428 321 -744 693 -388 699 -388 707 -392 313 -752 345 -750 317 -744 351 -730 355 -738 323 -774 327 -748 329 -750 695 -386 701 -354 381 -722 351 -720 385 -718 351 -718 345 -738 705 -382 329 -736 713 -360 387 -718 369 -718 367 -706 735 -352 375 -726 351 -722 351 -720 719 -7808 4845 -1474 743 -332 741 -370 705 -370 349 -718 383 -716 345 -712 381 -704 747 -326 747 -350 737 -352 351 -718 719 -360 741 -366 687 -362 375 -704 381 -724 351 -740 353 -712 357 -718 359 -744 363 -688 365 -722 727 -354 727 -354 379 -724 351 -722 353 -720 387 -718 353 -718 703 -374 351 -716 735 -354 365 -708 353 -734 351 -746 717 -356 359 -720 371 -704 371 -720 731 -7786 4847 -1482 711 -386 711 -358 743 -330 373 -708 359 -748 349 -740 351 -716 719 -356 727 -354 739 -354 351 -718 719 -362 743 -364 721 -330 373 -706 381 -722 351 -740 353 -712 359 -720 361 -722 361 -720 361 -720 725 -354 731 -354 381 -720 353 -722 385 -720 351 -720 349 -716 735 -354 361 -748 711 -364 347 -740 365 -722 365 -720 695 -384 371 -704 381 -702 377 -710 709 -7804 4853 -1468 743 -336 735 -358 719 -352 379 -724 353 -722 353 -720 387 -686 721 -360 721 -362 743 -332 387 -718 721 -366 701 -382 701 -350 377 -720 351 -740 353 -714 357 -710 397 -710 365 -702 385 -688 377 -724 731 -352 703 -354 379 -736 343 -740 357 -720 349 -706 385 -718 719 -354 365 -724 735 -352 377 -724 355 -720 353 -720 721 -358 387 -686 387 -718 353 -718 733 -7796 4821 -1492 739 -350 719 -334 737 -350 365 -722 373 -722 367 -708 371 -702 747 -352 711 -358 743 -364 343 -706 749 -352 717 -350 717 -384 327 -736 351 -746 355 -716 357 -720 359 -710 365 -742 365 -708 367 -704 711 -354 743 -356 387 -684 373 -706 381 -722 351 -740 353 -714 721 -356 361 -720 733 -352 375 -694 385 -724 353 -722 719 -356 385 -686 385 -718 351 -716 731 -7792 4843 -1480 717 -354 719 -386 717 -354 359 -720 351 -708 387 -712 355 -718 721 -356 727 -354 739 -356 351 -718 741 -364 +RAW_Data: 705 -370 703 -372 351 -718 383 -720 347 -720 347 -714 381 -704 353 -744 357 -718 355 -720 723 -356 725 -354 379 -722 351 -722 353 -722 385 -718 351 -718 721 -372 351 -716 719 -372 351 -718 383 -716 345 -714 743 -346 361 -740 353 -712 357 -710 725 -7818 4837 -1498 713 -356 709 -360 741 -332 375 -706 359 -750 351 -706 353 -748 719 -356 723 -352 739 -354 351 -718 709 -364 719 -362 721 -364 385 -718 353 -718 383 -682 377 -712 349 -734 353 -742 355 -712 359 -722 723 -354 729 -352 381 -722 353 -722 351 -720 387 -718 353 -716 701 -388 345 -722 737 -354 357 -722 351 -708 387 -712 717 -350 731 -354 741 -356 743 -330 375 -8180 4829 -1468 739 -364 707 -354 729 -352 379 -722 353 -720 387 -686 387 -718 707 -368 721 -366 707 -368 351 -718 735 -354 719 -354 719 -388 329 -746 349 -738 351 -712 359 -718 361 -742 365 -708 371 -706 373 -720 733 -320 733 -354 383 -720 353 -720 387 -718 351 -716 385 -714 703 -388 327 -746 705 -348 387 -702 385 -690 385 -724 713 -358 709 -362 743 -364 709 -370 351 -8162 4837 -1482 715 -388 715 -352 715 -384 325 -730 353 -744 353 -712 359 -720 723 -354 733 -354 745 -356 351 -720 719 -362 741 -330 737 -382 349 -722 345 -724 361 -744 349 -704 383 -716 357 -718 357 -720 361 -720 723 -354 733 -354 383 -720 387 -686 387 -718 353 -718 349 -716 731 -384 347 -724 721 -352 365 -706 353 -732 353 -746 717 -356 723 -352 739 -354 711 -360 385 -8146 4841 -1470 737 -344 739 -326 751 -352 377 -690 387 -724 353 -724 353 -722 711 -360 743 -364 721 -330 387 -716 703 -386 721 -356 721 -354 363 -706 349 -734 351 -746 355 -718 355 -712 363 -744 365 -708 369 -722 695 -352 731 -354 381 -722 353 -722 351 -734 351 -716 383 -720 723 -354 333 -736 739 -348 361 -708 351 -748 355 -712 725 -354 727 -352 741 -352 713 -358 385 -8134 4855 -1474 719 -358 709 -362 721 -364 387 -716 351 -718 385 -712 347 -712 739 -334 739 -354 729 -352 379 -722 717 -354 711 -360 743 -332 387 -718 351 -716 377 -708 349 -730 353 -742 355 -710 359 -720 359 -720 723 -354 729 -352 381 -720 353 -722 351 -722 387 -684 387 -716 703 -384 349 -722 737 -354 329 -750 349 -738 353 -712 719 -356 725 -354 741 -354 717 -358 385 -8126 4861 -1470 735 -344 731 -346 729 -348 383 -718 347 -712 353 -734 353 -746 715 -356 725 -350 741 -352 351 -718 741 -366 721 -366 705 -370 353 -718 385 -682 377 -710 349 -734 353 -744 355 -710 359 -710 397 -688 +RAW_Data: 727 -354 729 -352 379 -724 353 -722 353 -718 387 -716 353 -716 735 -348 383 -682 727 -386 347 -722 347 -712 381 -706 747 -326 747 -350 737 -352 711 -358 diff --git a/assets/unit_tests/subghz/kinggates_stylo4k_raw.sub b/assets/unit_tests/subghz/kinggates_stylo4k_raw.sub new file mode 100644 index 000000000..49b190002 --- /dev/null +++ b/assets/unit_tests/subghz/kinggates_stylo4k_raw.sub @@ -0,0 +1,11 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 377 -386 1117 -410 1121 -352 1141 -384 1151 -378 1119 -350 1139 -386 1115 -1134 389 -1114 395 -1122 363 -1136 389 -358 1167 -356 1145 -1120 389 -1110 391 -356 1139 -1126 389 -1114 391 -1122 363 -1146 389 -1110 395 -1122 363 -1138 389 -1110 393 -1122 363 -1140 389 -1112 393 -1120 389 -1118 389 -1112 397 -1124 363 -1142 389 -1112 359 -1154 367 -1134 389 -1144 365 -1138 355 -394 1119 -380 1107 -1152 353 -398 1113 -384 1139 -1118 385 -376 1141 -386 1129 -350 1143 -388 1109 -1132 389 -1112 393 -390 1107 -1128 389 -1112 397 -388 1111 -1132 389 -358 1127 -1118 417 -1116 383 -1120 353 -1158 389 -1108 375 -384 1121 -408 1123 -350 1139 -386 1111 -1130 389 -1114 395 -1122 395 -1114 389 -1116 395 -1122 363 -1138 387 -9444 373 -374 379 -374 381 -346 403 -346 389 -376 389 -390 353 -376 359 -382 383 -360 419 -360 359 -386 359 -2264 777 -356 1127 -390 1143 -362 1131 -1138 365 -1122 359 -386 1153 -1106 377 -1152 385 -372 1113 -1140 385 -1118 381 -1114 383 -1150 383 -1120 355 -1122 389 -358 1165 -386 1113 -1128 389 -360 1125 -384 1131 -368 1157 -350 1139 -386 1115 -406 1099 -384 1141 -1122 383 -1110 373 -1130 385 -1128 393 -380 1131 -380 1129 -1112 383 -1132 391 -356 1143 -1124 383 -1130 367 -1136 385 -1136 387 -1112 371 -1120 389 -1118 383 -1130 371 -1130 383 -1110 383 -1120 413 -1118 383 -1144 347 -1144 389 -1110 393 -1122 363 -1140 389 -1112 359 -1154 363 -1146 389 -1110 393 -374 1115 -384 1115 -1144 385 -368 1141 -388 1111 -1110 421 -360 1125 -388 1109 -392 1137 -358 1125 -1144 365 -1138 389 -358 1123 -1118 401 -1138 389 -360 1121 -1120 417 -358 1109 -1154 355 -1120 375 -1138 385 -1130 391 -1136 355 -398 1115 -380 1141 -384 1121 -382 1119 -1104 413 -1118 355 -1156 387 -1112 377 -1122 389 -1118 387 -1112 397 -9422 417 -352 363 -416 355 -388 345 -382 377 -380 375 -380 375 -380 375 -380 385 -356 379 -366 385 -374 387 -2246 745 -380 1141 -386 1113 -370 1125 -1140 373 -1152 355 -394 1117 -1140 381 -1120 385 -374 1145 -1112 385 -1122 381 -1116 383 -1120 375 -1120 389 -1120 373 -380 1171 -358 1121 -1142 377 -356 1127 -384 1137 -378 1155 -390 1105 -366 1125 -386 1135 -386 1111 -1132 389 -1112 393 -1120 365 -1138 387 -360 1163 -356 1143 -1126 387 -1114 357 -386 1141 -1126 383 -1130 365 -1132 381 -1140 377 -1116 383 -1130 371 -1128 381 -1140 347 -1148 385 -1128 369 -1128 381 -1142 377 -1114 389 -1112 395 -1124 361 -1142 389 -1114 393 -1122 365 -1138 389 -1114 397 -1108 389 -392 1119 -350 1139 -1152 355 -396 1115 -382 1109 -1156 385 -374 1111 -384 1139 -368 1147 -388 1109 -1112 389 -1120 383 -388 1107 -1150 389 -1112 +RAW_Data: 393 -390 1109 -1128 389 -360 1125 -1120 381 -1152 383 -1118 353 -1158 387 -1112 375 -386 1117 -408 1121 -350 1143 -388 1109 -1132 389 -1114 391 -1122 395 -1120 389 -1112 393 -1122 365 -1136 389 -9442 373 -376 389 -354 377 -366 387 -384 357 -378 361 -418 347 -394 385 -358 363 -382 361 -414 357 -392 333 -2290 751 -384 1113 -406 1121 -350 1137 -1136 353 -1160 385 -356 1135 -1120 361 -1146 385 -388 1137 -1108 361 -1150 387 -1112 395 -1136 349 -1154 353 -1142 371 -384 1145 -378 1117 -1138 381 -382 1087 -410 1121 -382 1143 -380 1121 -380 1115 -384 1107 -418 1115 -1106 385 -1148 365 -1118 359 -1146 387 -388 1135 -388 1113 -1126 383 -1130 367 -376 1113 -1142 383 -1114 375 -1154 355 -1160 385 -1110 371 -1152 357 -1118 385 -1146 365 -1122 361 -1146 387 -1114 395 -1134 355 -1160 351 -1146 369 -1154 355 -1120 387 -1114 397 -1136 357 -1118 407 -1144 351 -1134 359 -420 1111 -366 1131 -1142 379 -384 1089 -410 1119 -1142 379 -366 1141 -386 1109 -388 1131 -350 1141 -1118 391 -1114 375 -378 1153 -1116 385 -1136 383 -358 1139 -1120 359 -420 1099 -1142 383 -1118 383 -1138 347 -1144 385 -1144 369 -386 1113 -404 1089 -386 1141 -382 1099 -1136 381 -1128 375 -1130 383 -1140 359 -1146 387 -1114 395 -1138 357 -9430 383 -378 359 -418 347 -392 387 -360 363 -384 361 -414 357 -386 347 -384 375 -382 385 -358 383 -364 387 -2252 773 -354 1131 -384 1137 -386 1111 -1132 387 -1112 397 -388 1113 -1124 389 -1116 387 -388 1115 -1132 389 -1114 393 -1120 365 -1140 389 -1114 357 -1154 365 -378 1151 -358 1127 -1156 367 -376 1135 -358 1125 -388 1141 -368 1125 -386 1133 -388 1109 -370 1155 -1106 375 -1122 389 -1118 389 -1114 395 -386 1117 -410 1123 -1106 377 -1130 383 -388 1107 -1152 353 -1148 353 -1150 367 -1142 389 -1110 397 -1120 365 -1138 389 -1110 391 -1122 363 -1142 387 -1116 389 -1120 391 -1116 389 -1116 395 -1122 365 -1140 389 -1114 357 -1154 363 -1138 389 -1142 365 -1138 355 -396 1115 -382 1141 -1118 353 -400 1111 -384 1139 -1120 381 -386 1139 -366 1119 -392 1121 -388 1107 -1152 389 -1114 355 -388 1139 -1126 387 -1114 397 -376 1111 -1144 375 -380 1129 -1138 375 -1098 385 -1140 377 -1118 387 -1144 371 -386 1115 -404 1121 -348 1137 -386 1113 -1134 389 -1112 395 -1124 395 -1118 389 -1110 395 -1122 363 -1138 389 -9418 391 -360 407 -384 361 -388 355 -390 367 -376 373 -380 387 -356 377 -366 385 -388 355 -378 359 -384 377 -2266 777 -346 1149 -388 1107 -390 1129 -1104 415 -1118 353 -398 1113 -1138 383 -1122 381 -388 1141 -1118 389 -1112 357 -1154 365 -1138 389 -1114 357 -1154 363 -378 1155 -358 1123 -1156 381 -360 1107 -384 +RAW_Data: 1153 -378 1119 -382 1143 -382 1121 -382 1117 -382 1113 -1120 389 -1120 387 -1112 399 -1120 393 -392 1119 -350 1141 -1154 357 -1116 389 -360 1163 -1120 365 -1138 387 -1114 389 -1122 389 -1116 387 -1114 397 -1104 379 -1156 353 -1148 367 -1118 377 -1122 423 -1110 373 -1122 389 -1118 383 -1130 373 -1128 383 -1140 345 -1146 383 -1130 399 -1130 353 -1142 377 -358 1127 -384 1143 -1118 385 -372 1111 -386 1137 -1120 381 -388 1141 -364 1127 -384 1133 -374 1111 -1148 383 -1114 373 -384 1115 -1136 387 -1144 371 -386 1115 -1132 387 -360 1123 -1150 345 -1148 383 -1128 371 -1132 381 -1140 379 -390 1123 -350 1139 -388 1113 -406 1089 -1142 373 -1120 389 -1118 423 -1110 371 -1120 379 -1122 407 -1104 417 -9440 389 -356 379 -366 385 -388 355 -378 359 -384 381 -394 387 -358 361 -386 359 -416 355 -388 345 -384 377 -2262 747 -384 1149 -380 1115 -382 1113 -1120 389 -1120 389 -360 1129 -1152 367 -1136 389 -358 1131 -1152 367 -1138 389 -1116 355 -1152 367 -1134 389 -1116 353 -388 1141 -368 1123 -1138 375 -386 1113 -408 1121 -350 1175 -372 1105 -386 1145 -352 1141 -366 1145 -1114 385 -1116 377 -1122 389 -1120 421 -354 1139 -388 1109 -1132 383 -1130 369 -374 1113 -1144 385 -1114 377 -1120 391 -1128 373 -1138 385 -1130 359 -1138 377 -1120 373 -1138 383 -1130 359 -1138 379 -1160 375 -1106 385 -1130 393 -1120 377 -1118 389 -1112 393 -1140 355 -1120 421 -1114 371 -1122 391 -390 1123 -350 1139 -1134 353 -402 1113 -384 1141 -1118 385 -376 1143 -352 1161 -352 1135 -386 1113 -1132 387 -1114 395 -388 1111 -1128 387 -1114 399 -374 1115 -1142 375 -380 1117 -1118 387 -1144 363 -1136 385 -1130 367 -1130 383 -388 1107 -392 1129 -380 1115 -384 1113 -1136 389 -1114 393 -1124 393 -1120 389 -1114 393 -1124 363 -1140 389 -9416 391 -360 405 -386 329 -416 357 -392 365 -374 377 -380 343 -412 341 -412 353 -390 375 -366 385 -386 355 -2264 743 -394 1123 -388 1111 -392 1133 -1110 395 -1120 363 -382 1133 -1142 381 -1118 383 -376 1111 -1146 383 -1122 383 -1146 347 -1150 381 -1116 353 -1158 343 -410 1133 -382 1111 -1152 355 -394 1119 -382 1109 -382 1153 -378 1131 -354 1137 -396 1119 -388 1111 -1150 351 -1152 351 -1150 365 -1136 387 -356 1131 -386 1143 -1122 387 -1112 357 -420 1107 -1128 387 -1114 359 -1152 363 -1148 387 -1114 395 -1122 361 -1140 387 -1110 395 -1120 361 -1140 387 -1114 393 -1154 355 -1120 387 -1146 365 -1118 361 -1146 387 -1112 395 -1120 363 -1140 385 -1144 367 -1120 359 -420 1099 -384 1139 -1118 383 -384 1109 -392 1129 -1138 379 -366 1147 -388 1109 -386 1099 -384 1139 -1132 349 -1158 375 -380 1131 -1104 411 -1122 351 -416 1111 -1148 +RAW_Data: 353 -396 1121 -1142 347 -1150 381 -1116 355 -1156 375 -1144 387 -360 1119 -388 1107 -394 1131 -386 1101 -1152 363 -1138 387 -1112 391 -1152 357 -1116 375 -1136 383 -1122 383 -9448 357 -392 357 -398 363 -378 385 -358 383 -364 389 -386 357 -380 389 -386 347 -382 375 -384 375 -380 373 -2262 747 -376 1145 -390 1107 -386 1129 -1104 413 -1120 353 -396 1115 -1140 381 -1122 383 -376 1143 -1110 385 -1118 383 -1114 417 -1114 383 -1120 353 -1156 389 -356 1135 -386 1113 -1134 389 -358 1129 -390 1107 -392 1153 -358 1127 -388 1143 -362 1131 -356 1131 -1154 365 -1136 389 -1114 357 -1150 363 -386 1153 -358 1125 -1118 417 -1120 381 -350 1123 -1134 391 -1112 395 -1124 395 -1116 389 -1112 393 -1124 363 -1140 389 -1114 359 -1154 363 -1138 389 -1114 391 -1124 361 -1144 389 -1112 393 -1122 363 -1138 389 -1112 391 -1122 363 -1138 389 -1144 365 -1124 361 -382 1155 -350 1137 -1120 391 -386 1131 -350 1151 -1120 383 -378 1141 -352 1137 -394 1117 -390 1107 -1150 389 -1114 355 -388 1143 -1120 387 -1112 397 -388 1113 -1130 385 -344 1163 -1104 379 -1122 373 -1140 383 -1130 389 -1124 359 -386 1127 -386 1139 -368 1141 -390 1107 -1112 387 -1116 385 -1150 367 -1140 389 -1112 393 -1124 363 -1136 389 -9444 379 -340 417 -360 359 -386 359 -416 355 -386 347 -384 375 -382 375 -380 375 -378 375 -380 385 -356 379 -2278 745 -354 1151 -368 1141 -390 1105 -1114 387 -1116 385 -386 1141 -1120 389 -1114 389 -388 1113 -1130 389 -1112 393 -1124 363 -1138 389 -1112 389 -1122 363 -380 1159 -350 1137 -1122 391 -388 1097 -384 1139 -382 1125 -386 1145 -352 1141 -366 1145 -390 1107 -1110 387 -1150 353 -1150 367 -1138 387 -360 1125 -390 1109 -1152 389 -1112 357 -388 1141 -1122 389 -1110 391 -1122 395 -1112 389 -1110 397 -1120 363 -1144 389 -1114 391 -1122 365 -1138 389 -1116 389 -1142 355 -1120 389 -1112 397 -1122 363 -1140 389 -1110 393 -1130 349 -1140 405 -1134 389 -1112 357 -388 1141 -364 1129 -1142 367 -388 1111 -370 1131 -1140 383 -364 1149 -388 1109 -388 1137 -356 1127 -1118 383 -1120 413 -350 1121 -1132 407 -1140 355 -364 1149 -1112 371 -406 1129 -1104 409 -1098 383 -1116 417 -1118 381 -1118 385 -388 1111 -390 1129 -350 1137 -386 1113 -1138 389 -1114 395 -1122 393 -1120 389 -1112 393 -1124 363 -1138 389 -9444 379 -340 417 -360 359 -386 361 -414 357 -386 347 -384 375 -382 375 -380 375 -380 375 -378 373 -380 373 -2262 749 -386 1111 -408 1117 -348 1143 -1120 391 -1116 389 -358 1127 -1154 365 -1136 387 -360 1129 -1154 365 -1136 389 -1114 357 -1154 365 -1134 389 -1112 357 -390 1137 -406 1119 -1106 377 -386 1117 -406 1123 -350 1143 -384 +RAW_Data: 1149 -378 1121 -350 1145 -380 1133 -1104 375 -1136 385 -1130 359 -1138 379 -400 1129 -354 1139 -1148 355 -1150 365 -378 1119 -1146 355 -1152 365 -1134 389 -1110 397 -1122 363 -1140 389 -1110 395 -1122 363 -1142 389 -1116 357 -1152 365 -1146 389 -1112 393 -1130 349 -1138 383 -1116 413 -1120 353 -1122 387 -1114 397 -1154 355 -1124 387 -360 1133 -384 1131 -1134 383 -376 1133 -352 1133 -1132 383 -376 1139 -378 1135 -380 1115 -382 1141 -1118 353 -1160 387 -356 1133 -1118 379 -1158 353 -392 1133 -1104 379 -398 1117 -1138 383 -1118 353 -1164 353 -1146 403 -1120 353 -398 1115 -382 1143 -384 1089 -412 1121 -1106 377 -1154 355 -1118 407 -1146 351 -1130 395 -1138 355 -1118 407 -9434 353 -396 363 -380 383 -360 383 -364 389 -386 357 -414 355 -386 345 -386 375 -382 375 -380 375 -378 375 -2256 769 -384 1119 -382 1117 -380 1113 -1122 389 -1118 389 -360 1131 -1140 377 -1118 421 -354 1139 -1140 355 -1118 405 -1104 387 -1128 391 -1122 363 -1138 387 -360 1157 -354 1143 -1128 387 -360 1121 -388 1141 -362 1129 -384 1139 -388 1111 -370 1127 -384 1135 -1122 363 -1140 389 -1116 393 -1122 395 -356 1129 -384 1141 -1120 383 -1134 387 -356 1133 -1130 349 -1140 383 -1116 413 -1118 381 -1110 377 -1146 389 -1114 391 -1124 365 -1138 391 -1112 357 -1150 365 -1144 387 -1112 395 -1122 361 -1140 387 -1112 393 -1104 379 -1158 353 -1144 403 -1118 353 -1158 353 -390 1133 -390 1107 -1130 389 -358 1125 -388 1111 -1154 389 -358 1129 -386 1131 -368 1129 -382 1139 -1118 353 -1164 387 -356 1135 -1120 393 -1118 389 -358 1131 -1154 365 -376 1135 -1108 395 -1136 347 -1126 387 -1144 403 -1120 353 -398 1115 -384 1141 -372 1103 -386 1145 -1108 387 -1120 383 -1116 403 -1140 389 -1116 353 -1146 361 -1144 389 -9420 393 -362 401 -338 377 -388 385 -374 361 -382 375 -382 375 -380 373 -380 373 -380 373 -380 389 -354 379 -2272 743 -388 1137 -360 1121 -386 1111 -1152 351 -1148 359 -384 1143 -1126 387 -1114 391 -384 1117 -1130 383 -1132 369 -1134 351 -1138 377 -1142 385 -1112 359 -420 1107 -406 1121 -1104 377 -384 1119 -406 1119 -352 1171 -382 1123 -378 1119 -384 1107 -384 1119 -1136 385 -1116 393 -1120 361 -1142 387 -388 1137 -386 1113 -1128 385 -1116 357 -420 1113 -1124 387 -1114 359 -1148 395 -1116 385 -1146 363 -1116 361 -1144 387 -1144 363 -1120 361 -1144 385 -1112 393 -1152 355 -1154 353 -1144 367 -1136 355 -1158 351 -1146 369 -1120 361 -1144 385 -1148 369 -1152 357 -392 1117 -380 1107 -1152 355 -398 1119 -382 1109 -1152 385 -374 1113 -386 1139 -366 1145 -388 1111 -1110 385 -1148 353 -386 1139 -1124 387 -1142 365 -386 1113 -1132 385 -360 1125 -1144 +RAW_Data: 363 -1140 387 -1114 357 -1152 363 -1146 387 -358 1129 -386 1139 -366 1125 -384 1139 -1120 363 -1140 387 -1112 393 -1130 381 -1136 383 -1114 371 -1132 383 -116626 65 -934 133 -1954 131 -102 133 -136 97 -332 65 -430 299 -296 129 -100 265 -168 367 -100 65 -66 231 -336 9643 -7766 529 -68 467 -166 65 -134 99 -500 331 -132 65 -130 329 -98 497 -100 1195 -100 1959 -66 4163 -7346 97 -392 165 -194 97 -2978 433 -298 531 -298 65 -200 131 -132 261 -98 229 -68 12837 -340 99 -268 165 -134 65 -898 67 -100 265 -66 165 -100 597 -166 199 -298 199 -200 99 -132 233 -132 299 -132 233 -166 65 -66 4021 -168 133 -68 231 -168 4647 -130 1399 -7750 133 -1714 197 -2480 131 -200 65 -100 265 -890 63 -1152 197 -98 293 -134 65 -300 361 -100 1035 -100 231 -132 299 -100 3399 -66 6287 -4506 99 -100 65 -130 99 -196 461 -98 331 -164 97 -162 227 -64 197 -98 229 -130 195 -100 425 -526 165 -130 95 -522 457 -560 233 -98 261 -66 1155 -100 259 -130 1407 -98 553 -66 7793 -494 65 -232 65 -3652 229 -2716 361 -266 333 -200 133 -166 99 -132 267 -66 133 -132 199 -166 331 -132 331 -166 197 -950 229 -198 303 -298 365 -100 4839 -3816 165 -130 229 -696 131 -130 261 -262 97 -166 263 -894 165 -230 365 -566 129 -560 197 -324 99 -98 261 -134 131 -100 67 -334 67 -232 199 -132 165 -302 67 -100 1467 -98 459 -100 1081 -130 131 -66 8927 -232 165 -3104 99 -2812 65 -982 131 -98 195 -98 263 -264 231 -66 195 -132 193 -164 65 -100 365 -132 1629 -66 1009 -132 8383 -632 131 -3060 131 -492 425 -100 763 -166 371 -132 1197 -134 229 -694 461 -366 365 -98 329 -198 267 -168 399 -68 131 -332 493 -132 231 -132 569 -66 7765 -7568 99 -532 65 -634 133 -3540 65 -100 263 -592 261 -1484 299 -302 265 -234 1129 -304 99 -436 163 -360 97 -556 231 -166 265 -1164 165 -134 235 -100 163 -332 297 -100 197 -132 99 -566 133 -234 133 -328 295 -98 985 -98 163 -396 399 -134 1557 -134 297 -266 6875 -68 1759 -7194 133 -166 99 -266 65 -432 67 -432 393 -5086 99 -66 199 -68 263 -866 429 -100 359 -130 261 -132 267 -134 533 -134 9251 -4184 65 -1156 165 -198 65 -426 297 -492 67 -164 131 -198 259 -164 199 -100 733 -134 865 -100 397 -132 65 -100 197 -66 327 -164 227 -98 231 -132 97 -262 99 -130 229 -66 589 -96 1119 -98 1905 -7486 599 -66 561 -66 359 -98 757 -162 261 -66 323 -130 5573 -8538 99 -894 131 -594 229 -364 63 -1378 197 -1682 331 -100 199 -166 diff --git a/assets/unit_tests/subghz/linear_delta3.sub b/assets/unit_tests/subghz/linear_delta3.sub new file mode 100644 index 000000000..f00507428 --- /dev/null +++ b/assets/unit_tests/subghz/linear_delta3.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: LinearDelta3 +Bit: 8 +Key: 00 00 00 00 00 00 00 D0 diff --git a/assets/unit_tests/subghz/linear_delta3_raw.sub b/assets/unit_tests/subghz/linear_delta3_raw.sub new file mode 100644 index 000000000..1973622a5 --- /dev/null +++ b/assets/unit_tests/subghz/linear_delta3_raw.sub @@ -0,0 +1,8 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: -66 11813 -100 14655 -98 40111 -66 1625 -2116 1933 -34732 501 -11730 235 -3728 1887 -2106 1933 -2092 1971 -2072 1959 -34712 511 -3554 445 -3556 1997 -2036 455 -3594 1963 -2046 1979 -2076 1961 -2070 1989 -34690 483 -7724 1739 -2226 355 -3684 1857 -2138 1929 -2078 1965 -2074 1947 -34750 487 -3538 473 -3544 1993 -2042 485 -3548 1961 -2070 1965 -2070 1969 -2042 1997 -34716 443 -7734 1753 -2236 323 -3676 1903 -2098 1945 -2102 1927 -2070 1989 -34710 521 -3532 473 -3544 1991 -2032 481 -3556 1969 -2076 1967 -2036 1991 -2066 1969 -34718 467 -7756 1739 -2192 363 -3654 1889 -2132 1929 -2096 1935 -2070 1987 -34716 511 -3522 471 -3554 2009 -2036 459 -3550 2003 -2038 1979 -2042 1999 -2042 1999 -34704 471 -11774 225 -3710 1879 -2162 1885 -2112 1925 -2110 1939 -34738 459 -3636 403 -3612 1939 -2062 451 -3566 1985 -2044 1995 -2040 2009 -2032 2003 -34684 495 -3680 295 -3648 1935 -2098 423 -3562 2001 -2038 1989 -2044 2003 -2036 1977 -34718 461 -3678 295 -3684 1901 -2098 429 -3596 1967 -2036 1981 -2048 1993 -2042 2013 -34686 521 -3530 457 -3568 1999 -2036 455 -3552 1999 -2032 2019 -2024 1995 -2022 1997 -34716 441 -15774 1809 -2192 1905 -2100 1919 -2112 1961 -34720 417 -3830 167 -3710 1863 -2144 357 -3674 1909 -2100 1955 -2062 1977 -2072 1965 -34710 487 -3562 453 -3554 1985 -2052 481 -3536 2019 -2010 2001 -2042 1997 -2038 2005 -34716 451 -3602 433 -3584 1959 -2070 451 -3560 2001 -2038 1993 -2042 1967 -2072 1973 -34712 459 -3622 393 -3624 1933 -2068 457 -3584 1965 -2064 1979 -2052 1967 -2044 1981 -34722 477 -3608 397 -3588 1961 -2096 413 -3596 1971 -2040 1979 -2072 1963 -2070 1959 -34714 495 -3558 483 -3538 1985 -2042 479 -3562 1985 -2046 1967 -2070 1973 -2054 1995 -34688 493 -3578 413 -3614 1939 -2074 465 -3560 1971 -2038 2017 -2018 1995 -2042 2013 -34726 479 -3528 475 -3556 1999 -2036 455 -3570 1999 -2040 1973 -2054 2001 -2032 1987 -34720 477 -3562 445 -3602 1949 -2054 481 -3562 1975 -2060 1963 -2064 1977 -2038 2005 -34702 485 -3570 447 -3550 2015 -2020 479 -3564 1983 -2048 1999 -2034 1971 -2064 1993 -34688 517 -3516 497 -3532 1999 -2038 481 -3558 1997 -2004 2027 -2042 1963 -2038 1997 -34716 491 -3562 461 -3548 1995 -2032 491 -3524 2005 -2036 1989 -2038 1995 -2046 1979 -34714 465 -3682 293 -3680 1905 -2096 431 -3592 1969 -2070 1977 -2052 1965 -2044 1981 -34734 479 -3564 463 -3556 1999 -2032 457 -3550 1995 -2044 2011 -2042 1997 -2006 2027 -34680 531 -3524 483 -3538 1987 -2044 479 -3534 2013 -2048 1965 -2062 1987 -2030 1997 -34712 473 -3592 445 -3562 1975 -2072 451 -3566 1965 -2042 2013 -2046 1963 -2064 1993 -34700 459 -3632 371 -3638 1915 -2084 449 -3568 1987 -2046 1971 -2070 1983 -2022 1997 -34726 487 -3524 477 -3562 1985 -2044 481 -3542 2005 -2040 1995 -2038 1967 -2046 1993 -34710 511 -3528 471 -3560 1967 -2070 459 -3558 1971 +RAW_Data: -2072 1971 -2056 1971 -2074 1973 -34714 455 -3634 373 -3634 1901 -2110 419 -3620 1941 -2070 1991 -2040 1999 -2038 1965 -34740 467 -3562 481 -3534 1983 -2070 449 -3546 1999 -2044 1993 -2042 2003 -2036 1975 -34702 521 -3560 443 -3586 1969 -2044 449 -3562 1997 -2046 1987 -2042 2007 -2034 1973 -34732 487 -3562 443 -3582 1979 -2058 445 -3560 1995 -2044 1997 -2028 1987 -2034 2003 -34710 515 -3518 485 -3566 1977 -2036 483 -3536 1999 -2044 2009 -2024 1995 -2068 1973 -34710 487 -3564 471 -3558 1977 -2054 447 -3564 1991 -2042 1997 -2036 2007 -2034 2001 -34684 529 -3526 469 -3548 1989 -2038 483 -3562 1997 -2038 1973 -2034 1999 -2036 1997 -34728 487 -3536 479 -3534 2013 -2044 449 -3570 1985 -2042 1993 -2044 2005 -2014 1995 -34710 473 -3594 439 -3562 1995 -2040 457 -3564 2001 -2040 1975 -2046 1995 -2046 1999 -34704 491 -3548 451 -3570 1991 -2042 447 -3578 1967 -2046 1995 -2042 1999 -2034 2001 -34712 491 -3562 443 -3584 1981 -2018 479 -3562 1985 -2044 1997 -2030 1989 -2040 1997 -34722 489 -3554 459 -3560 1969 -2068 453 -3554 1999 -2034 1987 -2058 1997 -2046 1983 -34702 487 -3534 479 -3564 1983 -2040 483 -3538 1981 -2048 1993 -2048 2007 -2044 1995 -34696 489 -3550 453 -3570 1995 -2050 447 -3564 1983 -2040 1999 -2034 2003 -2034 1995 -34690 495 -3580 433 -3586 1969 -2064 453 -3552 1995 -2036 1991 -2056 1997 -2046 1987 -34706 441 -3636 373 -3626 1959 -2074 419 -3592 1963 -2074 1989 -2044 1971 -2070 1981 -34698 509 -3526 503 -3528 2005 -2034 481 -3528 1993 -2042 1999 -2066 1989 -2034 2003 -34678 495 -3540 481 -3546 1997 -2046 473 -3554 1999 -2034 2001 -2036 1995 -2046 1983 -34720 475 -3560 469 -3548 1997 -2030 485 -3566 1963 -2066 1983 -2046 1999 -2034 1973 -34734 487 -3560 443 -3584 1981 -2052 445 -3568 1987 -2044 1999 -2032 1993 -2034 2007 -34702 491 -3560 459 -3558 1967 -2070 455 -3556 2003 -2036 1977 -2042 2005 -2028 1997 -34730 461 -3564 473 -3536 2011 -2046 449 -3566 1989 -2044 1997 -2042 1971 -2054 2001 -34708 475 -3560 479 -3528 1999 -2040 485 -3566 1963 -2040 2013 -2042 1995 -2034 1987 -34694 519 -3554 441 -3582 1981 -2052 449 -3564 1985 -2040 1993 -2034 1991 -2062 1975 -34714 529 -3534 463 -3558 1969 -2068 451 -3560 2003 -2038 1993 -2042 1969 -2070 1975 -34720 493 -3582 383 -3616 1937 -2072 469 -3558 1995 -2036 1975 -2066 1995 -2042 1989 -34678 531 -3560 391 -3622 1937 -2094 429 -3588 1967 -2070 1981 -2054 1965 -2038 2021 -34682 525 -3524 481 -3564 1989 -2040 445 -3554 1997 -2040 2005 -2034 2001 -2024 1991 -34706 517 -3586 409 -3610 1927 -2076 451 -3558 1967 -2074 1993 -2038 2001 -2040 1975 -34714 495 -3588 409 -3602 1933 -2088 447 -3584 1965 -2044 1999 -2036 2007 -2030 1995 -34692 525 -3538 447 -3580 1981 -2042 487 -3542 1995 -2040 1969 -2072 1969 -2044 1991 -34714 443 -3636 399 -3630 1899 -2106 413 -3584 1997 +RAW_Data: -2034 2007 -2038 1969 -2076 1965 -34708 493 -3564 451 -3570 1965 -2074 449 -3548 2003 -2044 1987 -2038 1999 -2030 1991 -34710 493 -3602 403 -3612 1943 -2092 419 -3596 1963 -2062 1963 -2042 2001 -2064 1967 -34716 497 -3616 357 -3648 1903 -2132 399 -3596 1963 -2068 1977 -2052 1967 -2046 2019 -34684 497 -3614 359 -3650 1909 -2100 405 -3630 1925 -2098 1965 -2066 1965 -2056 1971 -34712 477 -3634 371 -3628 1931 -2104 391 -3624 1939 -2066 1975 -2052 2005 -2036 1985 -34714 449 -3668 337 -3664 1901 -2124 417 -3594 1963 -2048 1995 -2028 1993 -2066 1971 -34698 463 -3642 353 -3650 1943 -2066 433 -3594 1963 -2066 1995 -2034 1997 -2046 1981 -34730 479 -3560 445 -3562 1997 -2032 485 -3560 1965 -2062 1989 -2044 1999 -2032 1971 -34724 463 -3608 399 -3620 1943 -2096 421 -3592 1961 -2074 1979 -2036 2011 -2032 1971 -34734 469 -3558 485 -3552 1999 -2028 473 -3552 2003 -2032 2003 -2032 1997 -2044 1993 -34704 443 -3602 431 -3596 1967 -2076 447 -3556 1975 -2058 1997 -2040 1991 -2048 1971 -161100 97 -428 165 -200 395 -428 97 -100 559 -130 97 -164 129 -98 391 -98 295 -166 52395 -66 16239 -66 42541 -66 755 -132 14015 -98 2885 -68 10385 -98 40045 -100 987 -68 25539 -66 19799 -98 136101 -100 5141 -66 5709 -68 23177 -66 11097 -66 329 -100 261 -66 15755 -98 20575 -66 3645 -100 51411 -66 14441 -132 4467 -66 3965 -132 3707 -66 33107 -66 10373 -66 1775 -66 4185 -132 1429 -68 4675 -100 13419 -66 33985 diff --git a/assets/unit_tests/subghz/nice_one_raw.sub b/assets/unit_tests/subghz/nice_one_raw.sub new file mode 100644 index 000000000..169b3f088 --- /dev/null +++ b/assets/unit_tests/subghz/nice_one_raw.sub @@ -0,0 +1,12 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok650Async +Protocol: RAW +RAW_Data: 7855 -12784 1413 -1544 469 -1040 465 -1010 479 -1020 967 -548 445 -1046 973 -524 967 -520 981 -516 483 -1042 449 -1034 949 -528 495 -1008 479 -1016 985 -518 453 -1042 449 -1052 949 -514 483 -1012 985 -512 477 -1042 445 -1050 951 -548 971 -512 975 -520 967 -554 949 -548 451 -1040 967 -520 987 -518 455 -1038 475 -1016 977 -518 983 -514 473 -1018 975 -518 487 -1002 475 -1020 965 -516 477 -1012 1007 -522 445 -1034 491 -1008 973 -524 +RAW_Data: 481 -992 481 -1010 483 -1030 977 -520 487 -1008 973 -522 987 -518 983 -514 965 -522 987 -520 489 -1004 473 -1018 471 -1016 1005 -476 511 -1012 457 -1018 1001 -510 975 -520 471 -1022 483 -1016 969 -536 1003 -454 981 -480 479 -986 981 -486 479 -946 989 -492 973 -484 473 -976 1503 -23606 1433 -1542 493 -1006 473 -1032 441 -1048 971 -514 483 -1012 985 -518 479 -1014 481 -1012 457 -1050 443 -1044 977 -520 473 -1004 495 -1004 969 -556 453 -1036 451 -1038 973 -520 485 -994 981 -520 457 -1050 477 -1014 977 -494 985 -538 961 -512 1005 -518 951 -526 491 -1006 969 -520 985 -524 455 -1044 447 -1048 983 -518 983 -514 441 -1050 981 -518 453 -1042 447 -1050 981 -518 451 -1046 975 -520 451 -1022 483 -1008 1001 -522 447 -1020 485 -1008 473 -1016 981 -550 449 -1044 977 -520 949 -550 979 -516 967 -520 983 -522 455 -1042 447 -1050 451 -1024 981 -520 483 -1018 963 -546 479 -1010 967 -520 483 -1022 975 -522 967 -552 487 -960 481 -990 451 -994 481 -980 479 -986 449 -984 969 -480 983 -510 1465 -23612 1473 -1520 479 -1026 453 -1044 451 -1036 943 -552 453 -1044 949 -518 481 -1018 977 -524 459 -1046 439 -1046 973 -528 463 -1012 471 -1046 943 -552 443 -1034 457 -1042 977 -518 479 -1028 949 -554 451 -1014 481 -1018 981 -524 985 -518 971 -514 979 -522 987 -512 477 -1016 977 -522 969 -552 449 -1016 483 -1014 985 -518 973 -516 481 -1012 967 -552 449 -1020 483 -1010 969 -554 447 -1022 977 -520 475 -1018 479 -1018 975 -522 457 -1036 479 -1016 479 -1002 969 -552 447 -1054 943 -548 969 -520 983 -520 983 -516 969 -518 479 -1030 453 -1044 449 -1048 943 -548 451 -1044 945 -552 975 -518 947 -552 449 -1034 975 -524 455 -1040 969 -520 449 -982 969 -518 945 -484 481 -984 481 -994 447 -986 477 -998 1435 -23658 1441 -1530 483 -1008 483 -1034 449 -1022 977 -520 485 -1018 479 -1018 975 -506 473 -1036 469 -1042 463 -1010 977 -520 487 -1030 451 -1010 981 -520 481 -1018 481 -1014 983 -518 479 -1016 975 -492 497 -1014 467 -1014 977 -520 975 -526 985 -516 979 -506 1005 -496 493 -1008 975 -522 983 -518 453 -1040 475 -1016 975 -524 987 -514 471 -1038 955 -514 473 -1046 445 -1044 967 -514 477 -1016 975 -520 457 -1050 477 -1010 973 -522 473 -1000 479 -1030 453 -1038 969 -506 473 -1050 971 -512 979 -524 955 -548 973 -512 975 -518 475 -1036 473 -1006 493 -1008 975 -520 973 -526 487 -1004 475 -1018 965 -516 1005 -512 481 -1014 985 -518 483 -986 975 -488 977 -480 977 -486 975 -482 481 -982 975 -480 977 -488 1477 -23618 1389 -1634 369 -1114 383 -1078 431 -1072 +RAW_Data: 931 -550 451 -1046 447 -1042 967 -552 945 -522 459 -1042 445 -1050 943 -552 439 -1036 459 -1046 977 -508 477 -1030 455 -1044 945 -552 451 -1020 979 -524 459 -1046 443 -1048 979 -518 967 -534 957 -516 977 -518 973 -528 455 -1042 973 -520 975 -526 459 -1040 481 -1020 969 -510 967 -546 447 -1050 955 -544 441 -1044 449 -1048 953 -550 443 -1046 975 -518 485 -1010 455 -1044 943 -554 447 -1054 449 -1010 475 -1048 943 -550 453 -1040 969 -520 973 -522 985 -514 969 -554 949 -524 459 -1040 477 -1014 483 -1034 947 -520 981 -554 447 -1016 977 -524 983 -516 973 -516 483 -1016 455 -1046 973 -484 977 -518 449 -986 447 -1016 971 -482 449 -1018 443 -1014 449 -984 1461 -129764 65 -3200 133 -464 133 -298 429 -132 265 -98 231 -134 265 -164 3439 -132 727 -132 199 -2058 133 -1644 361 -166 65 -492 165 -264 591 -428 197 -198 201 -98 831 -68 2313 -100 5839 -10922 65 -1320 425 -262 297 -428 97 -362 2463 -98 1025 -66 5263 -5030 99 -6924 461 -1092 133 -98 333 -166 2739 -132 3131 -66 10535 -2008 131 -434 297 -1058 65 -132 99 -198 529 -198 97 -526 97 -66 493 -664 99 -232 2613 -132 5371 -11166 229 -198 163 -394 199 -398 365 -132 99 -166 2121 -100 1195 -68 1821 -100 10635 -468 67 -1256 65 -2144 229 -100 163 -394 593 -98 67 -166 1677 -66 791 -66 335 -98 11033 -566 65 -1460 165 -1520 497 -1254 491 -564 99 -330 99 -232 1227 -132 2973 -66 3661 -11964 131 -132 99 -398 131 -328 97 -232 363 -396 1379 -98 99 -166 1591 -66 12171 -4136 65 -298 265 -298 199 -462 99 -330 65 -166 163 -66 1591 -66 165 -166 12079 -1002 65 -366 465 -530 97 -134 561 -66 497 -494 99 -64 131 -134 1095 -66 6537 -5066 65 -5458 397 -724 165 -466 131 -166 14293 -436 65 -1590 65 -1462 459 -332 65 -396 563 -794 197 -300 1255 -12100 99 -130 495 -166 97 -296 97 -658 757 -98 959 -66 1029 -1346 165 -2620 395 -494 197 -166 163 -198 65 -98 195 -394 821 -98 3063 -100 4469 -12120 497 -166 65 -462 195 -164 295 -66 4361 -100 1755 -100 131 -66 9415 -3840 99 -530 197 -364 463 -330 365 -332 133 -100 165 -166 2113 -100 1461 -132 4175 -3772 97 -7124 231 -1258 165 -100 429 -1326 995 -200 1755 -66 1519 -100 6437 -7198 133 -300 527 -398 165 -232 131 -166 67 -164 16443 -3270 131 -658 131 -726 97 -858 97 -300 331 -100 629 -10288 67 -164 133 -1458 297 -364 65 -98 163 -758 1189 -66 199 -68 1791 -66 897 -132 165 -3410 163 -364 99 -98 99 -66 365 -232 789 -494 65 -328 629 -66 1259 -66 365 -11422 7923 -12864 1405 -1562 +RAW_Data: 451 -1040 441 -1052 449 -1050 945 -554 449 -1052 451 -1020 481 -1010 473 -1050 449 -1052 451 -1040 969 -520 977 -520 455 -1042 977 -522 447 -1056 947 -518 979 -546 447 -1052 451 -1040 441 -1048 983 -518 455 -1044 449 -1018 979 -548 947 -554 449 -1032 481 -992 483 -1012 985 -514 999 -512 479 -1012 485 -1014 961 -544 477 -1010 965 -522 981 -512 483 -1012 487 -1020 477 -1014 479 -1016 459 -1014 471 -1012 1003 -492 997 -522 483 -1016 979 -522 985 -520 975 -512 975 -520 999 -488 985 -514 481 -1006 1001 -522 483 -990 483 -1008 483 -1020 977 -516 975 -518 999 -524 451 -1018 1009 -482 999 -506 983 -524 487 -1004 473 -980 501 -952 517 -940 497 -982 489 -974 987 -452 495 -974 487 -954 1485 -23662 1457 -1556 445 -1026 483 -1010 475 -1016 975 -518 483 -1014 487 -1034 447 -1022 977 -522 457 -1046 475 -1018 975 -524 985 -518 477 -1016 977 -524 459 -1048 969 -514 977 -522 457 -1038 479 -1018 481 -1002 1001 -520 447 -1054 449 -1008 1001 -520 977 -520 451 -1040 475 -1014 479 -1028 949 -518 983 -542 447 -1058 449 -1044 947 -552 447 -1024 977 -520 967 -542 479 -1024 451 -1040 441 -1050 451 -1028 481 -1014 483 -1010 965 -548 973 -518 485 -1010 981 -516 967 -520 983 -524 981 -514 969 -538 967 -518 481 -1016 973 -524 485 -1016 465 -1012 479 -1020 983 -532 959 -514 975 -554 949 -526 985 -512 969 -554 967 -534 461 -1042 443 -1014 967 -478 455 -1006 969 -486 967 -480 983 -486 969 -514 451 -982 1461 -23692 563 -4014 291 -1220 263 -1228 829 -620 883 -626 851 -608 903 -622 387 -1082 391 -1102 409 -1084 913 -588 941 -548 443 -1056 945 -522 445 -1046 971 -552 977 -516 441 -1048 481 -992 483 -1010 979 -554 451 -1018 481 -1014 983 -518 977 -514 479 -1040 447 -1034 485 -996 975 -520 979 -520 483 -1016 481 -1008 999 -506 471 -1050 971 -514 975 -520 473 -1000 483 -1020 481 -1008 473 -1018 481 -1020 481 -1008 967 -554 945 -518 481 -1038 967 -520 985 -520 981 -514 967 -520 985 -520 981 -508 479 -1016 1003 -518 479 -1010 479 -1010 473 -1018 975 -516 979 -520 983 -520 975 -514 977 -518 999 -520 979 -518 451 -1040 479 -986 479 -962 1007 -486 451 -986 975 -486 977 -482 483 -980 477 -982 1473 -23656 1453 -1548 447 -1016 485 -1012 491 -1012 973 -520 981 -526 983 -514 971 -554 947 -526 491 -1008 475 -1020 983 -498 989 -516 483 -1014 977 -524 453 -1044 979 -518 979 -520 453 -1042 449 -1048 447 -1022 975 -518 475 -1050 447 -1020 977 -522 983 -518 481 -1016 481 -1012 473 -1002 973 -550 945 -552 449 -1050 447 -1020 975 -522 487 -1034 973 -520 +RAW_Data: 979 -514 443 -1046 479 -1028 451 -1042 451 -1048 447 -1022 485 -1014 983 -520 973 -516 483 -1012 983 -518 973 -516 977 -520 1003 -520 975 -520 981 -514 475 -1034 969 -516 479 -1016 447 -1046 475 -1018 975 -516 975 -522 983 -510 469 -1010 1007 -518 951 -530 989 -516 973 -556 951 -494 481 -978 487 -978 975 -460 1005 -466 979 -486 969 -508 981 -450 1489 -23666 571 -4036 269 -1224 257 -1250 787 -642 867 -622 883 -622 359 -1136 373 -1086 421 -1080 417 -1074 935 -550 947 -552 445 -1048 939 -552 451 -1046 947 -552 947 -550 451 -1040 443 -1048 453 -1024 977 -522 471 -1034 449 -1020 973 -540 975 -508 479 -1032 453 -1042 449 -1050 977 -518 979 -518 449 -1018 481 -1018 975 -518 473 -1034 963 -542 961 -544 447 -1044 473 -1020 479 -1014 481 -1010 473 -1032 471 -1010 959 -546 973 -492 499 -1006 997 -510 977 -524 953 -552 971 -512 973 -508 979 -554 451 -1016 977 -518 471 -1038 485 -1010 457 -1036 969 -506 999 -520 481 -1014 975 -522 967 -520 975 -548 451 -1038 475 -1022 965 -518 463 -978 985 -486 465 -978 457 -1016 463 -978 985 -486 963 -480 1477 -129906 495 -726 197 -328 295 -132 2547 -66 233 -98 11033 -1856 233 -1458 65 -198 165 -134 199 -168 101 -694 463 -530 165 -300 99 -232 2479 -98 1745 -98 3029 -132 163 -1460 65 -500 65 -400 99 -664 895 -398 65 -564 331 -166 97 -66 197 -98 3813 -98 10097 -3848 165 -232 67 -266 397 -596 165 -66 199 -166 99 -66 199 -398 165 -166 1721 -232 429 -166 133 -330 133 -698 493 -200 197 -428 11029 -12118 65 -198 199 -68 231 -230 101 -166 99 -664 131 -132 3163 -4238 331 -298 531 -398 299 -98 199 -166 563 -100 131 -98 893 -66 3141 -1556 133 -1722 131 -830 197 -262 195 -66 163 -462 195 -396 195 -134 499 -132 265 -66 1717 -166 3175 -11366 199 -164 131 -66 163 -98 525 -98 363 -264 4495 -100 229 -66 131 -66 593 -3002 97 -394 131 -426 99 -462 597 -692 295 -298 431 -230 4231 -66 9711 -3246 131 -100 99 -400 263 -498 65 -100 297 -98 99 -132 65 -862 131 -66 365 -396 99 -166 1991 -98 1611 -132 10333 -790 65 -1984 99 -896 165 -332 365 -232 131 -830 65 -66 397 -166 197 -66 65 -496 199 -100 9975 -1728 67 -5008 727 -98 131 -100 2873 -66 12011 -3150 67 -960 99 -234 99 -298 231 -232 195 -266 165 -296 261 -166 757 -66 629 -196 657 -100 197 -134 297 -364 11237 -1684 65 -2076 165 -462 491 -100 663 -630 329 -264 263 -100 1357 -66 461 -1676 99 -1782 295 -296 65 -296 163 -230 99 -132 295 -66 163 -362 197 -724 757 -66 +RAW_Data: 3785 -66 13551 -1808 97 -730 65 -100 231 -132 131 -1230 593 -232 1579 -66 2667 -200 101 -3480 165 -692 133 -396 427 -1524 363 -66 431 -132 10305 -8288 461 -628 67 -430 725 -66 1053 -66 4501 -230 165 -66 331 -66 355 -266 263 -132 63 -562 459 -462 197 -66 129 -132 65 -100 2643 -132 2107 -66 9651 -3692 99 -100 195 -294 97 -660 759 -328 165 -560 891 -66 1953 -66 11305 -362 263 -662 131 -432 65 -134 563 -430 131 -132 1819 -100 165 -166 1061 -98 10089 -2476 65 -854 395 -198 99 -492 131 -164 229 -466 199 -428 299 -100 927 -200 1557 -134 4269 -10464 133 -1624 65 -198 265 -398 131 -430 729 -134 6189 -66 5421 -2082 165 -3342 19967 -12808 1439 -1536 453 -1046 449 -1032 449 -1056 947 -552 977 -522 977 -518 453 -1038 977 -522 977 -520 457 -1038 977 -506 1005 -496 495 -1008 975 -538 973 -530 465 -1008 975 -554 453 -1036 947 -518 487 -1008 475 -1042 443 -1050 461 -1008 1005 -510 447 -1048 985 -510 469 -1006 1005 -494 997 -514 975 -514 975 -504 999 -506 479 -1034 491 -1010 975 -508 973 -524 491 -1004 473 -1018 997 -520 975 -512 975 -518 473 -1030 983 -516 981 -514 471 -998 997 -522 481 -1012 481 -1012 457 -1050 973 -512 977 -524 459 -1016 1003 -512 479 -1014 459 -1016 475 -1012 1007 -522 969 -502 495 -1008 477 -1030 965 -522 975 -514 479 -1000 471 -1062 471 -964 483 -982 471 -1000 471 -980 979 -448 503 -988 465 -976 487 -974 1459 -23696 1407 -1616 401 -1068 429 -1080 419 -1058 935 -566 923 -584 417 -1078 939 -524 457 -1042 973 -550 443 -1028 949 -554 945 -552 447 -1022 979 -518 971 -542 479 -1024 947 -550 441 -1048 979 -518 453 -1044 449 -1050 449 -1020 485 -1014 981 -518 479 -1014 975 -524 459 -1036 973 -516 979 -518 971 -552 945 -550 945 -552 449 -1030 479 -1026 947 -554 949 -552 449 -1018 479 -1008 981 -518 975 -548 945 -554 451 -1034 967 -514 997 -514 445 -1036 967 -554 447 -1022 485 -1010 475 -1016 975 -518 977 -520 487 -1014 973 -552 451 -1040 441 -1050 447 -1022 485 -1014 987 -516 479 -1014 483 -1014 459 -1046 969 -514 449 -1044 967 -546 973 -488 447 -1016 443 -1000 973 -490 475 -980 983 -482 441 -1016 465 -976 1475 -23652 1451 -1548 479 -1014 461 -1014 471 -1044 975 -520 971 -502 495 -1012 977 -506 1005 -498 989 -516 481 -1016 975 -520 981 -514 475 -1014 979 -522 983 -512 475 -1022 965 -514 471 -1046 973 -494 473 -1016 475 -1046 447 -1050 463 -1012 999 -512 481 -1012 983 -520 477 -1014 977 -524 955 -548 973 -512 975 -520 967 -556 449 -1020 483 -1012 983 -520 973 -516 481 -1008 473 -1034 +RAW_Data: 967 -538 963 -544 973 -522 471 -1006 989 -512 1007 -520 443 -1036 985 -516 449 -1048 451 -1022 483 -1012 983 -520 977 -514 481 -1012 979 -514 483 -1022 481 -1010 471 -1020 479 -1020 979 -524 457 -1048 973 -514 483 -1012 981 -520 483 -1018 481 -1014 485 -986 467 -980 981 -486 469 -978 457 -1004 963 -480 983 -486 971 -514 1441 -23704 1383 -1628 389 -1112 385 -1092 407 -1092 915 -552 941 -570 441 -1064 423 -1046 451 -1044 939 -556 455 -1048 945 -552 973 -522 453 -1046 945 -552 947 -550 451 -1040 969 -518 479 -1028 951 -552 451 -1018 479 -1018 483 -1014 459 -1044 971 -514 483 -1010 971 -544 447 -1020 977 -524 987 -518 973 -516 979 -524 985 -518 479 -1016 447 -1050 953 -548 971 -514 483 -1014 459 -1048 967 -514 977 -526 953 -548 443 -1046 975 -492 995 -512 471 -1050 943 -552 445 -1032 455 -1044 449 -1048 941 -550 945 -552 449 -1050 945 -552 451 -1044 449 -1018 479 -1016 479 -1002 969 -542 973 -522 455 -1040 477 -1022 967 -534 959 -514 975 -554 469 -1008 449 -980 469 -1008 943 -484 1001 -484 467 -980 983 -482 961 -514 1439 -23700 1469 -1510 495 -1008 473 -1036 463 -1012 969 -546 973 -522 473 -1018 479 -1014 975 -526 955 -516 475 -1046 975 -490 999 -518 481 -1014 975 -520 967 -514 481 -1022 979 -524 457 -1048 971 -514 481 -1010 485 -1020 477 -1014 479 -1000 1001 -522 451 -1020 977 -520 473 -1032 967 -538 959 -514 1005 -522 965 -504 989 -514 475 -1046 441 -1050 971 -514 975 -520 473 -1018 481 -1014 979 -520 983 -520 977 -516 485 -1010 979 -544 975 -518 453 -1042 981 -520 453 -1024 483 -1010 457 -1050 975 -512 975 -524 459 -1048 973 -514 481 -1010 473 -1016 479 -1016 477 -1036 967 -506 995 -512 965 -546 445 -1048 957 -516 1005 -512 445 -1046 979 -486 473 -980 979 -486 473 -980 981 -486 473 -980 485 -986 467 -976 1477 -142204 197 -1486 165 -198 165 -664 295 -232 99 -266 231 -166 3045 -100 13411 -3670 197 -498 131 -166 231 -198 165 -66 265 -134 129 -1062 431 -130 465 -134 13447 -3848 329 -100 163 -298 99 -164 463 -98 197 -98 131 -198 65 -296 493 -264 789 -66 7225 -12438 99 -164 463 -132 197 -630 65 -198 2487 -66 165 -100 10097 -6554 459 -664 297 -460 4925 -132 6063 -12078 497 -98 99 -200 97 -234 165 -298 1721 -134 265 -100 3035 -100 12081 -3674 231 -100 97 -200 97 -264 461 -100 99 -132 231 -100 97 -430 527 -200 231 -64 2081 -132 327 -100 529 -66 831 -66 3067 -4704 99 -5520 97 -496 67 -198 167 -498 693 -462 2341 -15926 65 -1392 659 -134 131 -298 165 -66 99 -298 4777 -4208 429 -66 diff --git a/documentation/HardwareTargets.md b/documentation/HardwareTargets.md new file mode 100644 index 000000000..0c3474839 --- /dev/null +++ b/documentation/HardwareTargets.md @@ -0,0 +1,44 @@ +## What a Firmware Target is + +Flipper's firmware is modular and supports different hardware configurations in a common code base. It encapsulates hardware-specific differences in `furi_hal`, board initialization code, linker files, SDK data and other information in a _target definition_. + +Target-specific files are placed in a single sub-folder in `firmware/targets`. It must contain a target definition file, `target.json`, and may contain other files if they are referenced by current target's definition. By default, `fbt` gathers all source files in target folder, unless they are explicitly excluded. + +Targets can inherit most code parts from other targets, to reduce common code duplication. + + +## Target Definition File + +A target definition file, `target.json`, is a JSON file that can contain the following fields: + +* `include_paths`: list of strings, folder paths relative to current target folder to add to global C/C++ header path lookup list. +* `sdk_header_paths`: list of strings, folder paths relative to current target folder to gather headers from for including in SDK. +* `startup_script`: filename of a startup script, performing initial hardware initialization. +* `linker_script_flash`: filename of a linker script for creating the main firmware image. +* `linker_script_ram`: filename of a linker script to use in "updater" build configuration. +* `linker_script_app`: filename of a linker script to use for linking .fap files. +* `sdk_symbols`: filename of a .csv file containing current SDK configuration for this target. +* `linker_dependencies`: list of libraries to link the firmware with. Note that those not in the list won't be built by `fbt`. Also several link passes might be needed, in such case you may need to specify same library name twice. +* `inherit`: string, specifies hardware target to borrow main configuration from. Current configuration may specify additional values for parameters that are lists of strings, or override values that are not lists. +* `excluded_sources`: list of filenames from the inherited configuration(s) NOT to be built. +* `excluded_headers`: list of headers from the inherited configuration(s) NOT to be included in generated SDK. +* `excluded_modules`: list of strings specifying fbt library (module) names to exclude from being used to configure build environment. + + +## Applications & Hardware + +Not all applications are available on different hardware targets. + +* For applications built into the firmware, you have to specify a compatible application set using `FIRMWARE_APP_SET=...` fbt option. See [fbt docs](./fbt.md#firmware-application-set) for details on build configurations. + +* For applications built as external .faps, you have to explicitly specify compatible targets in application's manifest, `application.fam`. For example, to limit application to a single target, add `targets=["f7"],` to the manifest. It won't be built for other targets. + +For details on application manifests, check out [their docs page](./AppManifests.md). + + +## Building Firmware for a Specific Target + +You have to specify TARGET_HW (and, optionally, FIRMWARE_APP_SET) for `fbt` to build firmware for non-default target. For example, building and flashing debug firmware for f18 can be done with + + ./fbt TARGET_HW=18 flash_usb_full + diff --git a/documentation/UniversalRemotes.md b/documentation/UniversalRemotes.md new file mode 100644 index 000000000..325f640d7 --- /dev/null +++ b/documentation/UniversalRemotes.md @@ -0,0 +1,76 @@ +# Universal Remotes + +## Televisions + +Adding your TV set to the universal remote is quite straightforward. Up to 6 signals can be recorded: `Power`, `Mute`, `Vol_up`, `Vol_dn`, `Ch_next`, and `Ch_prev`. Any of them can be omitted if not supported by your TV. + +Each signal is recorded using the following algorithm: + +1. Get the remote and point it to Flipper's IR receiver. +2. Start learning a new remote if it's the first button or press `+` to add a new button otherwise. +3. Press a remote button and save it under a corresponding name. +4. Repeat steps 2-3 until all required signals are saved. + +The signal names are self-explanatory. Remember to make sure that every recorded signal does what it's supposed to. + +If everything checks out, append these signals **to the end** of the [TV universal remote file](/assets/resources/infrared/assets/tv.ir). + +## Audio players + +Adding your audio player to the universal remote is done in the same manner as described above. Up to 8 signals can be recorded: `Power`, `Play`, `Pause`, `Vol_up`, `Vol_dn`, `Next`, `Prev`, and `Mute`. Any of them can be omitted if not supported by the player. + +The signal names are self-explanatory. +On many remotes, the `Play` button doubles as `Pause`. In this case, record it as `Play` omitting the `Pause`. +Make sure that every signal does what it's supposed to. + +If everything checks out, append these signals **to the end** of the [audio player universal remote file](/assets/resources/infrared/assets/audio.ir). + +## Projectors + +Adding your projector to the universal remote is really simple. Up to 4 signals can be recorded: `Power`, `Mute`, `Vol_up`, `Vol_dn`. Any of them can be omitted if not supported by your projector. +To save time, please make sure every recording has been named accordingly. +In case of omitting, on most projectors with the 4 following buttons, you should not have a problem. + + +## Air conditioners + +Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote. +The majority of A/C remotes have a small display that shows the current mode, temperature, and other settings. +When the user presses a button, a whole set of parameters is transmitted to the device, which must be recorded and used as a whole. + +In order to add a particular air conditioner to the universal remote, 6 signals must be recorded: `Off`, `Dh`, `Cool_hi`, `Cool_lo`, `Heat_hi`, and `Heat_lo`. +Each signal (except `Off`) is recorded using the following algorithm: + +1. Get the remote and press the **Power Button** so that the display shows that A/C is ON. +2. Set the A/C to the corresponding mode (see table below), leaving other parameters such as fan speed or vane on **AUTO** (if applicable). +3. Press the **POWER** button to switch the A/C off. +4. Start learning a new remote on Flipper if it's the first button or press `+` to add a new button otherwise. +5. Point the remote to Flipper's IR receiver as directed and press **POWER** button once again. +6. Save the resulting signal under the specified name. +7. Repeat steps 2-6 for each signal from the table below. + +| Signal | Mode | Temperature | Note | +| :-----: | :--------: | :---------: | ----------------------------------- | +| Dh | Dehumidify | N/A | | +| Cool_hi | Cooling | See note | Lowest temperature in cooling mode | +| Cool_lo | Cooling | 23°C | | +| Heat_hi | Heating | See note | Highest temperature in heating mode | +| Heat_lo | Heating | 23°C | | + +Finally, record the `Off` signal: + +1. Make sure the display shows that the A/C is ON. +2. Start learning a new signal on Flipper and point the remote towards the IR receiver. +3. Press the **POWER** button so that the remote shows the OFF state. +4. Save the resulting signal under the name `Off`. + +The resulting remote file should now contain 6 signals. You can omit any of them, but you then won't be able to use their functionality. +Test the file against the actual device. Make sure that every signal does what it's supposed to. + +If everything checks out, append these signals **to the end** of the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir). + +## Final steps + +The order of signals is not important, but they should be preceded by the following comment: `# Model: ` in order to keep the library organized. + +When done, open a pull request containing the changed file. diff --git a/fbt_options.py b/fbt_options.py index 8fb8f1429..d3670b01a 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -14,7 +14,7 @@ DEBUG = 0 # Suffix to add to files when building distribution # If OS environment has DIST_SUFFIX set, it will be used instead -DIST_SUFFIX = "XFW-0040_01252023" +DIST_SUFFIX = "XFW-0041_02142023" # Coprocessor firmware COPRO_OB_DATA = "scripts/ob.data" diff --git a/firmware.scons b/firmware.scons index 3922c136e..92f2d1a91 100644 --- a/firmware.scons +++ b/firmware.scons @@ -16,6 +16,7 @@ env = ENV.Clone( "fwbin", "fbt_apps", "pvsstudio", + "fbt_hwtarget", ], COMPILATIONDB_USE_ABSPATH=False, BUILD_DIR=fw_build_meta["build_dir"], @@ -31,10 +32,6 @@ env = ENV.Clone( CPPPATH=[ "#/furi", *(f"#/{app_dir[0]}" for app_dir in ENV["APPDIRS"] if app_dir[1]), - "#/firmware/targets/f${TARGET_HW}/ble_glue", - "#/firmware/targets/f${TARGET_HW}/fatfs", - "#/firmware/targets/f${TARGET_HW}/furi_hal", - "#/firmware/targets/f${TARGET_HW}/Inc", "#/firmware/targets/furi_hal_include", ], # Specific flags for building libraries - always do optimized builds @@ -74,20 +71,6 @@ env = ENV.Clone( _APP_ICONS=None, ) - -def ApplyLibFlags(env): - flags_to_apply = env["FW_LIB_OPTS"].get( - env.get("FW_LIB_NAME"), - env["FW_LIB_OPTS"]["Default"], - ) - # print("Flags for ", env.get("FW_LIB_NAME", "Default"), flags_to_apply) - env.MergeFlags(flags_to_apply) - - -env.AddMethod(ApplyLibFlags) - -Export("env") - if env["IS_BASE_FIRMWARE"]: env.Append( FIRMWARE_BUILD_CFG="firmware", @@ -102,7 +85,11 @@ else: ], ) -# Invoke child SConscripts to populate global `env` + build their own part of the code +env.ConfigureForTarget(env.subst("${TARGET_HW}")) + +Export("env") + +# Invoke child SCopscripts to populate global `env` + build their own part of the code lib_targets = env.BuildModules( [ "lib", @@ -131,7 +118,7 @@ if extra_int_apps := GetOption("extra_int_apps"): fwenv.Append(APPS=extra_int_apps.split(",")) -for app_dir, _ in env["APPDIRS"]: +for app_dir, _ in fwenv["APPDIRS"]: app_dir_node = env.Dir("#").Dir(app_dir) for entry in app_dir_node.glob("*"): @@ -196,37 +183,11 @@ sources.extend( fwelf = fwenv["FW_ELF"] = fwenv.Program( "${FIRMWARE_BUILD_CFG}", sources, - LIBS=[ - "print", - "flipper${TARGET_HW}", - "furi", - "freertos", - "stm32cubewb", - "hwdrivers", - "fatfs", - "littlefs", - "subghz", - "flipperformat", - "toolbox", - "nfc", - "microtar", - "usb_stm32", - "st25rfal002", - "infrared", - "appframe", - "assets", - "misc", - "mbedtls", - "lfrfid", - "flipper_application", - # 2nd round - "flipperformat", - "toolbox", - ], + LIBS=fwenv["TARGET_CFG"].linker_dependencies, ) # Firmware depends on everything child builders returned -Depends(fwelf, lib_targets) +# Depends(fwelf, lib_targets) # Output extra details after building firmware AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) AddPostAction( diff --git a/firmware/SConscript b/firmware/SConscript index 3581dc3eb..fa96b0adf 100644 --- a/firmware/SConscript +++ b/firmware/SConscript @@ -2,16 +2,6 @@ Import("env") env.Append( LINT_SOURCES=[Dir(".")], - SDK_HEADERS=[ - *env.GlobRecursive("*.h", "targets/furi_hal_include", "*_i.h"), - *env.GlobRecursive("*.h", "targets/f${TARGET_HW}/furi_hal", "*_i.h"), - File("targets/f7/platform_specific/intrinsic_export.h"), - File("#/firmware/targets/furi_hal_include/furi_hal_subghz.h"), - ], -) - -env.SetDefault( - SDK_DEFINITION=env.File("./targets/f${TARGET_HW}/api_symbols.csv").srcnode() ) libenv = env.Clone(FW_LIB_NAME="flipper${TARGET_HW}") @@ -23,9 +13,9 @@ libenv.Append( libenv.ApplyLibFlags() -sources = ["targets/f${TARGET_HW}/startup_stm32wb55xx_cm4.s"] -sources += libenv.GlobRecursive("*.c") - -lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +lib = libenv.StaticLibrary( + "${FW_LIB_NAME}", + env.get("TARGET_CFG").gatherSources(), +) libenv.Install("${LIB_DIST_DIR}", lib) Return("lib") diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv new file mode 100644 index 000000000..e4a7dfdd5 --- /dev/null +++ b/firmware/targets/f18/api_symbols.csv @@ -0,0 +1,2307 @@ +entry,status,name,type,params +Version,+,12.1,, +Header,+,applications/services/bt/bt_service/bt.h,, +Header,+,applications/services/cli/cli.h,, +Header,+,applications/services/cli/cli_vcp.h,, +Header,+,applications/services/dialogs/dialogs.h,, +Header,+,applications/services/dolphin/dolphin.h,, +Header,+,applications/services/gui/elements.h,, +Header,+,applications/services/gui/gui.h,, +Header,+,applications/services/gui/icon_i.h,, +Header,+,applications/services/gui/modules/button_menu.h,, +Header,+,applications/services/gui/modules/button_panel.h,, +Header,+,applications/services/gui/modules/byte_input.h,, +Header,+,applications/services/gui/modules/dialog_ex.h,, +Header,+,applications/services/gui/modules/empty_screen.h,, +Header,+,applications/services/gui/modules/file_browser.h,, +Header,+,applications/services/gui/modules/file_browser_worker.h,, +Header,+,applications/services/gui/modules/loading.h,, +Header,+,applications/services/gui/modules/menu.h,, +Header,+,applications/services/gui/modules/popup.h,, +Header,+,applications/services/gui/modules/submenu.h,, +Header,+,applications/services/gui/modules/text_box.h,, +Header,+,applications/services/gui/modules/text_input.h,, +Header,+,applications/services/gui/modules/validators.h,, +Header,+,applications/services/gui/modules/variable_item_list.h,, +Header,+,applications/services/gui/modules/widget.h,, +Header,+,applications/services/gui/modules/widget_elements/widget_element.h,, +Header,+,applications/services/gui/view_dispatcher.h,, +Header,+,applications/services/gui/view_stack.h,, +Header,+,applications/services/input/input.h,, +Header,+,applications/services/loader/loader.h,, +Header,+,applications/services/locale/locale.h,, +Header,+,applications/services/notification/notification.h,, +Header,+,applications/services/notification/notification_messages.h,, +Header,+,applications/services/power/power_service/power.h,, +Header,+,applications/services/rpc/rpc_app.h,, +Header,+,applications/services/storage/storage.h,, +Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,, +Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,, +Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_console.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_types.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_types.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_uart.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h,, +Header,+,firmware/targets/f7/platform_specific/intrinsic_export.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_bt_serial.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_compress.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_cortex.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_crypto.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_debug.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_i2c.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_info.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_light.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_memory.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_mpu.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_power.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_random.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_region.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_rtc.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_sd.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, +Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_adc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_bus.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_comp.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_cortex.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_crs.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dma.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_dmamux.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_exti.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_gpio.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_hsem.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_i2c.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_ipcc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_iwdg.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lptim.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_lpuart.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pka.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_pwr.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rcc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rng.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_rtc.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_spi.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_system.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_tim.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_usart.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_utils.h,, +Header,+,lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/stm32wbxx_ll_wwdg.h,, +Header,+,lib/flipper_application/flipper_application.h,, +Header,+,lib/flipper_format/flipper_format.h,, +Header,+,lib/flipper_format/flipper_format_i.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_button.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_consumer.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_desktop.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_device.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_game.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_keyboard.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_led.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_ordinal.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_power.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_simulation.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_sport.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_telephony.h,, +Header,+,lib/libusb_stm32/inc/hid_usage_vr.h,, +Header,-,lib/libusb_stm32/inc/stm32_compat.h,, +Header,+,lib/libusb_stm32/inc/usb.h,, +Header,+,lib/libusb_stm32/inc/usb_cdc.h,, +Header,+,lib/libusb_stm32/inc/usb_cdca.h,, +Header,+,lib/libusb_stm32/inc/usb_cdce.h,, +Header,+,lib/libusb_stm32/inc/usb_cdci.h,, +Header,+,lib/libusb_stm32/inc/usb_cdcp.h,, +Header,+,lib/libusb_stm32/inc/usb_cdcw.h,, +Header,+,lib/libusb_stm32/inc/usb_dfu.h,, +Header,+,lib/libusb_stm32/inc/usb_hid.h,, +Header,+,lib/libusb_stm32/inc/usb_std.h,, +Header,+,lib/libusb_stm32/inc/usb_tmc.h,, +Header,+,lib/libusb_stm32/inc/usbd_core.h,, +Header,+,lib/mbedtls/include/mbedtls/des.h,, +Header,+,lib/mbedtls/include/mbedtls/sha1.h,, +Header,+,lib/micro-ecc/uECC.h,, +Header,+,lib/mlib/m-algo.h,, +Header,+,lib/mlib/m-array.h,, +Header,+,lib/mlib/m-bptree.h,, +Header,+,lib/mlib/m-core.h,, +Header,+,lib/mlib/m-deque.h,, +Header,+,lib/mlib/m-dict.h,, +Header,+,lib/mlib/m-list.h,, +Header,+,lib/mlib/m-rbtree.h,, +Header,+,lib/mlib/m-tuple.h,, +Header,+,lib/mlib/m-variant.h,, +Header,+,lib/print/wrappers.h,, +Header,+,lib/toolbox/args.h,, +Header,+,lib/toolbox/crc32_calc.h,, +Header,+,lib/toolbox/dir_walk.h,, +Header,+,lib/toolbox/float_tools.h,, +Header,+,lib/toolbox/hmac_sha256.h,, +Header,+,lib/toolbox/manchester_decoder.h,, +Header,+,lib/toolbox/manchester_encoder.h,, +Header,+,lib/toolbox/md5.h,, +Header,+,lib/toolbox/path.h,, +Header,+,lib/toolbox/protocols/protocol_dict.h,, +Header,+,lib/toolbox/random_name.h,, +Header,+,lib/toolbox/saved_struct.h,, +Header,+,lib/toolbox/stream/buffered_file_stream.h,, +Header,+,lib/toolbox/stream/file_stream.h,, +Header,+,lib/toolbox/stream/stream.h,, +Header,+,lib/toolbox/stream/string_stream.h,, +Header,+,lib/toolbox/tar/tar_archive.h,, +Header,+,lib/toolbox/value_index.h,, +Header,+,lib/toolbox/version.h,, +Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* +Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" +Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* +Function,-,LL_ADC_DeInit,ErrorStatus,ADC_TypeDef* +Function,-,LL_ADC_INJ_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_INJ_InitTypeDef*" +Function,-,LL_ADC_INJ_StructInit,void,LL_ADC_INJ_InitTypeDef* +Function,-,LL_ADC_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_InitTypeDef*" +Function,-,LL_ADC_REG_Init,ErrorStatus,"ADC_TypeDef*, LL_ADC_REG_InitTypeDef*" +Function,-,LL_ADC_REG_StructInit,void,LL_ADC_REG_InitTypeDef* +Function,-,LL_ADC_StructInit,void,LL_ADC_InitTypeDef* +Function,-,LL_COMP_DeInit,ErrorStatus,COMP_TypeDef* +Function,+,LL_COMP_Init,ErrorStatus,"COMP_TypeDef*, LL_COMP_InitTypeDef*" +Function,-,LL_COMP_StructInit,void,LL_COMP_InitTypeDef* +Function,-,LL_CRC_DeInit,ErrorStatus,CRC_TypeDef* +Function,-,LL_CRS_DeInit,ErrorStatus, +Function,+,LL_DMA_DeInit,ErrorStatus,"DMA_TypeDef*, uint32_t" +Function,+,LL_DMA_Init,ErrorStatus,"DMA_TypeDef*, uint32_t, LL_DMA_InitTypeDef*" +Function,-,LL_DMA_StructInit,void,LL_DMA_InitTypeDef* +Function,-,LL_EXTI_DeInit,ErrorStatus, +Function,-,LL_EXTI_Init,ErrorStatus,LL_EXTI_InitTypeDef* +Function,-,LL_EXTI_StructInit,void,LL_EXTI_InitTypeDef* +Function,-,LL_GPIO_DeInit,ErrorStatus,GPIO_TypeDef* +Function,+,LL_GPIO_Init,ErrorStatus,"GPIO_TypeDef*, LL_GPIO_InitTypeDef*" +Function,-,LL_GPIO_StructInit,void,LL_GPIO_InitTypeDef* +Function,-,LL_I2C_DeInit,ErrorStatus,I2C_TypeDef* +Function,+,LL_I2C_Init,ErrorStatus,"I2C_TypeDef*, LL_I2C_InitTypeDef*" +Function,-,LL_I2C_StructInit,void,LL_I2C_InitTypeDef* +Function,-,LL_Init1msTick,void,uint32_t +Function,+,LL_LPTIM_DeInit,ErrorStatus,LPTIM_TypeDef* +Function,-,LL_LPTIM_Disable,void,LPTIM_TypeDef* +Function,+,LL_LPTIM_Init,ErrorStatus,"LPTIM_TypeDef*, LL_LPTIM_InitTypeDef*" +Function,-,LL_LPTIM_StructInit,void,LL_LPTIM_InitTypeDef* +Function,-,LL_LPUART_DeInit,ErrorStatus,USART_TypeDef* +Function,+,LL_LPUART_Init,ErrorStatus,"USART_TypeDef*, LL_LPUART_InitTypeDef*" +Function,-,LL_LPUART_StructInit,void,LL_LPUART_InitTypeDef* +Function,-,LL_PKA_DeInit,ErrorStatus,PKA_TypeDef* +Function,-,LL_PKA_Init,ErrorStatus,"PKA_TypeDef*, LL_PKA_InitTypeDef*" +Function,-,LL_PKA_StructInit,void,LL_PKA_InitTypeDef* +Function,-,LL_PLL_ConfigSystemClock_HSE,ErrorStatus,"uint32_t, LL_UTILS_PLLInitTypeDef*, LL_UTILS_ClkInitTypeDef*" +Function,-,LL_PLL_ConfigSystemClock_HSI,ErrorStatus,"LL_UTILS_PLLInitTypeDef*, LL_UTILS_ClkInitTypeDef*" +Function,-,LL_PLL_ConfigSystemClock_MSI,ErrorStatus,"LL_UTILS_PLLInitTypeDef*, LL_UTILS_ClkInitTypeDef*" +Function,-,LL_PWR_DeInit,ErrorStatus, +Function,-,LL_RCC_DeInit,ErrorStatus, +Function,-,LL_RCC_GetADCClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetCLK48ClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetI2CClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetLPTIMClockFreq,uint32_t,uint32_t +Function,+,LL_RCC_GetLPUARTClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetRFWKPClockFreq,uint32_t, +Function,-,LL_RCC_GetRNGClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetRTCClockFreq,uint32_t, +Function,-,LL_RCC_GetSAIClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetSMPSClockFreq,uint32_t, +Function,-,LL_RCC_GetSystemClocksFreq,void,LL_RCC_ClocksTypeDef* +Function,+,LL_RCC_GetUSARTClockFreq,uint32_t,uint32_t +Function,-,LL_RCC_GetUSBClockFreq,uint32_t,uint32_t +Function,-,LL_RNG_DeInit,ErrorStatus,RNG_TypeDef* +Function,-,LL_RNG_Init,ErrorStatus,"RNG_TypeDef*, LL_RNG_InitTypeDef*" +Function,-,LL_RNG_StructInit,void,LL_RNG_InitTypeDef* +Function,-,LL_RTC_ALMA_Init,ErrorStatus,"RTC_TypeDef*, uint32_t, LL_RTC_AlarmTypeDef*" +Function,-,LL_RTC_ALMA_StructInit,void,LL_RTC_AlarmTypeDef* +Function,-,LL_RTC_ALMB_Init,ErrorStatus,"RTC_TypeDef*, uint32_t, LL_RTC_AlarmTypeDef*" +Function,-,LL_RTC_ALMB_StructInit,void,LL_RTC_AlarmTypeDef* +Function,-,LL_RTC_DATE_Init,ErrorStatus,"RTC_TypeDef*, uint32_t, LL_RTC_DateTypeDef*" +Function,-,LL_RTC_DATE_StructInit,void,LL_RTC_DateTypeDef* +Function,-,LL_RTC_DeInit,ErrorStatus,RTC_TypeDef* +Function,+,LL_RTC_EnterInitMode,ErrorStatus,RTC_TypeDef* +Function,-,LL_RTC_ExitInitMode,ErrorStatus,RTC_TypeDef* +Function,+,LL_RTC_Init,ErrorStatus,"RTC_TypeDef*, LL_RTC_InitTypeDef*" +Function,-,LL_RTC_StructInit,void,LL_RTC_InitTypeDef* +Function,-,LL_RTC_TIME_Init,ErrorStatus,"RTC_TypeDef*, uint32_t, LL_RTC_TimeTypeDef*" +Function,-,LL_RTC_TIME_StructInit,void,LL_RTC_TimeTypeDef* +Function,-,LL_RTC_WaitForSynchro,ErrorStatus,RTC_TypeDef* +Function,-,LL_SPI_DeInit,ErrorStatus,SPI_TypeDef* +Function,+,LL_SPI_Init,ErrorStatus,"SPI_TypeDef*, LL_SPI_InitTypeDef*" +Function,-,LL_SPI_StructInit,void,LL_SPI_InitTypeDef* +Function,-,LL_SetFlashLatency,ErrorStatus,uint32_t +Function,+,LL_SetSystemCoreClock,void,uint32_t +Function,-,LL_TIM_BDTR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_BDTR_InitTypeDef*" +Function,-,LL_TIM_BDTR_StructInit,void,LL_TIM_BDTR_InitTypeDef* +Function,+,LL_TIM_DeInit,ErrorStatus,TIM_TypeDef* +Function,-,LL_TIM_ENCODER_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_ENCODER_InitTypeDef*" +Function,-,LL_TIM_ENCODER_StructInit,void,LL_TIM_ENCODER_InitTypeDef* +Function,-,LL_TIM_HALLSENSOR_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_HALLSENSOR_InitTypeDef*" +Function,-,LL_TIM_HALLSENSOR_StructInit,void,LL_TIM_HALLSENSOR_InitTypeDef* +Function,-,LL_TIM_IC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_IC_InitTypeDef*" +Function,-,LL_TIM_IC_StructInit,void,LL_TIM_IC_InitTypeDef* +Function,+,LL_TIM_Init,ErrorStatus,"TIM_TypeDef*, LL_TIM_InitTypeDef*" +Function,+,LL_TIM_OC_Init,ErrorStatus,"TIM_TypeDef*, uint32_t, LL_TIM_OC_InitTypeDef*" +Function,-,LL_TIM_OC_StructInit,void,LL_TIM_OC_InitTypeDef* +Function,-,LL_TIM_StructInit,void,LL_TIM_InitTypeDef* +Function,-,LL_USART_ClockInit,ErrorStatus,"USART_TypeDef*, LL_USART_ClockInitTypeDef*" +Function,-,LL_USART_ClockStructInit,void,LL_USART_ClockInitTypeDef* +Function,-,LL_USART_DeInit,ErrorStatus,USART_TypeDef* +Function,+,LL_USART_Init,ErrorStatus,"USART_TypeDef*, LL_USART_InitTypeDef*" +Function,-,LL_USART_StructInit,void,LL_USART_InitTypeDef* +Function,-,LL_mDelay,void,uint32_t +Function,-,SystemCoreClockUpdate,void, +Function,-,SystemInit,void, +Function,-,_Exit,void,int +Function,-,__assert,void,"const char*, int, const char*" +Function,+,__assert_func,void,"const char*, int, const char*, const char*" +Function,+,__clear_cache,void,"void*, void*" +Function,-,__eprintf,void,"const char*, const char*, unsigned int, const char*" +Function,+,__errno,int*, +Function,+,__furi_crash,void, +Function,+,__furi_halt,void, +Function,-,__getdelim,ssize_t,"char**, size_t*, int, FILE*" +Function,-,__getline,ssize_t,"char**, size_t*, FILE*" +Function,-,__itoa,char*,"int, char*, int" +Function,-,__locale_mb_cur_max,int, +Function,+,__retarget_lock_acquire,void,_LOCK_T +Function,+,__retarget_lock_acquire_recursive,void,_LOCK_T +Function,-,__retarget_lock_close,void,_LOCK_T +Function,+,__retarget_lock_close_recursive,void,_LOCK_T +Function,-,__retarget_lock_init,void,_LOCK_T* +Function,+,__retarget_lock_init_recursive,void,_LOCK_T* +Function,+,__retarget_lock_release,void,_LOCK_T +Function,+,__retarget_lock_release_recursive,void,_LOCK_T +Function,-,__retarget_lock_try_acquire,int,_LOCK_T +Function,-,__retarget_lock_try_acquire_recursive,int,_LOCK_T +Function,-,__srget_r,int,"_reent*, FILE*" +Function,-,__swbuf_r,int,"_reent*, int, FILE*" +Function,-,__utoa,char*,"unsigned, char*, int" +Function,+,__wrap___assert,void,"const char*, int, const char*" +Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*" +Function,+,__wrap_fflush,int,FILE* +Function,+,__wrap_printf,int,"const char*, ..." +Function,+,__wrap_putc,int,"int, FILE*" +Function,+,__wrap_putchar,int,int +Function,+,__wrap_puts,int,const char* +Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..." +Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list" +Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..." +Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..." +Function,-,_asnprintf_r,char*,"_reent*, char*, size_t*, const char*, ..." +Function,-,_asprintf_r,int,"_reent*, char**, const char*, ..." +Function,-,_atoi_r,int,"_reent*, const char*" +Function,-,_atol_r,long,"_reent*, const char*" +Function,-,_atoll_r,long long,"_reent*, const char*" +Function,-,_calloc_r,void*,"_reent*, size_t, size_t" +Function,-,_diprintf_r,int,"_reent*, int, const char*, ..." +Function,-,_dprintf_r,int,"_reent*, int, const char*, ..." +Function,-,_drand48_r,double,_reent* +Function,-,_dtoa_r,char*,"_reent*, double, int, int, int*, int*, char**" +Function,-,_erand48_r,double,"_reent*, unsigned short[3]" +Function,-,_fclose_r,int,"_reent*, FILE*" +Function,-,_fcloseall_r,int,_reent* +Function,-,_fdopen_r,FILE*,"_reent*, int, const char*" +Function,-,_fflush_r,int,"_reent*, FILE*" +Function,-,_fgetc_r,int,"_reent*, FILE*" +Function,-,_fgetc_unlocked_r,int,"_reent*, FILE*" +Function,-,_fgetpos_r,int,"_reent*, FILE*, fpos_t*" +Function,-,_fgets_r,char*,"_reent*, char*, int, FILE*" +Function,-,_fgets_unlocked_r,char*,"_reent*, char*, int, FILE*" +Function,-,_findenv,char*,"const char*, int*" +Function,-,_findenv_r,char*,"_reent*, const char*, int*" +Function,-,_fiprintf_r,int,"_reent*, FILE*, const char*, ..." +Function,-,_fiscanf_r,int,"_reent*, FILE*, const char*, ..." +Function,-,_fmemopen_r,FILE*,"_reent*, void*, size_t, const char*" +Function,-,_fopen_r,FILE*,"_reent*, const char*, const char*" +Function,-,_fopencookie_r,FILE*,"_reent*, void*, const char*, cookie_io_functions_t" +Function,-,_fprintf_r,int,"_reent*, FILE*, const char*, ..." +Function,-,_fpurge_r,int,"_reent*, FILE*" +Function,-,_fputc_r,int,"_reent*, int, FILE*" +Function,-,_fputc_unlocked_r,int,"_reent*, int, FILE*" +Function,-,_fputs_r,int,"_reent*, const char*, FILE*" +Function,-,_fputs_unlocked_r,int,"_reent*, const char*, FILE*" +Function,-,_fread_r,size_t,"_reent*, void*, size_t, size_t, FILE*" +Function,-,_fread_unlocked_r,size_t,"_reent*, void*, size_t, size_t, FILE*" +Function,-,_free_r,void,"_reent*, void*" +Function,-,_freopen_r,FILE*,"_reent*, const char*, const char*, FILE*" +Function,-,_fscanf_r,int,"_reent*, FILE*, const char*, ..." +Function,-,_fseek_r,int,"_reent*, FILE*, long, int" +Function,-,_fseeko_r,int,"_reent*, FILE*, _off_t, int" +Function,-,_fsetpos_r,int,"_reent*, FILE*, const fpos_t*" +Function,-,_ftell_r,long,"_reent*, FILE*" +Function,-,_ftello_r,_off_t,"_reent*, FILE*" +Function,-,_funopen_r,FILE*,"_reent*, const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" +Function,-,_fwrite_r,size_t,"_reent*, const void*, size_t, size_t, FILE*" +Function,-,_fwrite_unlocked_r,size_t,"_reent*, const void*, size_t, size_t, FILE*" +Function,-,_getc_r,int,"_reent*, FILE*" +Function,-,_getc_unlocked_r,int,"_reent*, FILE*" +Function,-,_getchar_r,int,_reent* +Function,-,_getchar_unlocked_r,int,_reent* +Function,-,_getenv_r,char*,"_reent*, const char*" +Function,-,_gets_r,char*,"_reent*, char*" +Function,-,_iprintf_r,int,"_reent*, const char*, ..." +Function,-,_iscanf_r,int,"_reent*, const char*, ..." +Function,-,_jrand48_r,long,"_reent*, unsigned short[3]" +Function,-,_l64a_r,char*,"_reent*, long" +Function,-,_lcong48_r,void,"_reent*, unsigned short[7]" +Function,-,_lrand48_r,long,_reent* +Function,-,_malloc_r,void*,"_reent*, size_t" +Function,-,_mblen_r,int,"_reent*, const char*, size_t, _mbstate_t*" +Function,-,_mbstowcs_r,size_t,"_reent*, wchar_t*, const char*, size_t, _mbstate_t*" +Function,-,_mbtowc_r,int,"_reent*, wchar_t*, const char*, size_t, _mbstate_t*" +Function,-,_mkdtemp_r,char*,"_reent*, char*" +Function,-,_mkostemp_r,int,"_reent*, char*, int" +Function,-,_mkostemps_r,int,"_reent*, char*, int, int" +Function,-,_mkstemp_r,int,"_reent*, char*" +Function,-,_mkstemps_r,int,"_reent*, char*, int" +Function,-,_mktemp_r,char*,"_reent*, char*" +Function,-,_mrand48_r,long,_reent* +Function,-,_mstats_r,void,"_reent*, char*" +Function,-,_nrand48_r,long,"_reent*, unsigned short[3]" +Function,-,_open_memstream_r,FILE*,"_reent*, char**, size_t*" +Function,-,_perror_r,void,"_reent*, const char*" +Function,-,_printf_r,int,"_reent*, const char*, ..." +Function,-,_putc_r,int,"_reent*, int, FILE*" +Function,-,_putc_unlocked_r,int,"_reent*, int, FILE*" +Function,-,_putchar,void,char +Function,-,_putchar_r,int,"_reent*, int" +Function,-,_putchar_unlocked_r,int,"_reent*, int" +Function,-,_putenv_r,int,"_reent*, char*" +Function,-,_puts_r,int,"_reent*, const char*" +Function,-,_realloc_r,void*,"_reent*, void*, size_t" +Function,-,_reallocf_r,void*,"_reent*, void*, size_t" +Function,-,_reclaim_reent,void,_reent* +Function,-,_remove_r,int,"_reent*, const char*" +Function,-,_rename_r,int,"_reent*, const char*, const char*" +Function,-,_rewind_r,void,"_reent*, FILE*" +Function,-,_scanf_r,int,"_reent*, const char*, ..." +Function,-,_seed48_r,unsigned short*,"_reent*, unsigned short[3]" +Function,-,_setenv_r,int,"_reent*, const char*, const char*, int" +Function,-,_siprintf_r,int,"_reent*, char*, const char*, ..." +Function,-,_siscanf_r,int,"_reent*, const char*, const char*, ..." +Function,-,_sniprintf_r,int,"_reent*, char*, size_t, const char*, ..." +Function,-,_snprintf_r,int,"_reent*, char*, size_t, const char*, ..." +Function,-,_sprintf_r,int,"_reent*, char*, const char*, ..." +Function,-,_srand48_r,void,"_reent*, long" +Function,-,_sscanf_r,int,"_reent*, const char*, const char*, ..." +Function,-,_strdup_r,char*,"_reent*, const char*" +Function,-,_strerror_r,char*,"_reent*, int, int, int*" +Function,-,_strndup_r,char*,"_reent*, const char*, size_t" +Function,-,_strtod_r,double,"_reent*, const char*, char**" +Function,-,_strtol_r,long,"_reent*, const char*, char**, int" +Function,-,_strtold_r,long double,"_reent*, const char*, char**" +Function,-,_strtoll_r,long long,"_reent*, const char*, char**, int" +Function,-,_strtoul_r,unsigned long,"_reent*, const char*, char**, int" +Function,-,_strtoull_r,unsigned long long,"_reent*, const char*, char**, int" +Function,-,_system_r,int,"_reent*, const char*" +Function,-,_tempnam_r,char*,"_reent*, const char*, const char*" +Function,-,_tmpfile_r,FILE*,_reent* +Function,-,_tmpnam_r,char*,"_reent*, char*" +Function,-,_tzset_r,void,_reent* +Function,-,_ungetc_r,int,"_reent*, int, FILE*" +Function,-,_unsetenv_r,int,"_reent*, const char*" +Function,-,_vasiprintf_r,int,"_reent*, char**, const char*, __gnuc_va_list" +Function,-,_vasniprintf_r,char*,"_reent*, char*, size_t*, const char*, __gnuc_va_list" +Function,-,_vasnprintf_r,char*,"_reent*, char*, size_t*, const char*, __gnuc_va_list" +Function,-,_vasprintf_r,int,"_reent*, char**, const char*, __gnuc_va_list" +Function,-,_vdiprintf_r,int,"_reent*, int, const char*, __gnuc_va_list" +Function,-,_vdprintf_r,int,"_reent*, int, const char*, __gnuc_va_list" +Function,-,_vfiprintf_r,int,"_reent*, FILE*, const char*, __gnuc_va_list" +Function,-,_vfiscanf_r,int,"_reent*, FILE*, const char*, __gnuc_va_list" +Function,-,_vfprintf_r,int,"_reent*, FILE*, const char*, __gnuc_va_list" +Function,-,_vfscanf_r,int,"_reent*, FILE*, const char*, __gnuc_va_list" +Function,-,_viprintf_r,int,"_reent*, const char*, __gnuc_va_list" +Function,-,_viscanf_r,int,"_reent*, const char*, __gnuc_va_list" +Function,-,_vprintf_r,int,"_reent*, const char*, __gnuc_va_list" +Function,-,_vscanf_r,int,"_reent*, const char*, __gnuc_va_list" +Function,-,_vsiprintf_r,int,"_reent*, char*, const char*, __gnuc_va_list" +Function,-,_vsiscanf_r,int,"_reent*, const char*, const char*, __gnuc_va_list" +Function,-,_vsniprintf_r,int,"_reent*, char*, size_t, const char*, __gnuc_va_list" +Function,-,_vsnprintf_r,int,"_reent*, char*, size_t, const char*, __gnuc_va_list" +Function,-,_vsprintf_r,int,"_reent*, char*, const char*, __gnuc_va_list" +Function,-,_vsscanf_r,int,"_reent*, const char*, const char*, __gnuc_va_list" +Function,-,_wcstombs_r,size_t,"_reent*, char*, const wchar_t*, size_t, _mbstate_t*" +Function,-,_wctomb_r,int,"_reent*, char*, wchar_t, _mbstate_t*" +Function,-,a64l,long,const char* +Function,+,abort,void, +Function,-,abs,int,int +Function,+,acquire_mutex,void*,"ValueMutex*, uint32_t" +Function,-,aligned_alloc,void*,"size_t, size_t" +Function,+,aligned_free,void,void* +Function,+,aligned_malloc,void*,"size_t, size_t" +Function,-,arc4random,__uint32_t, +Function,-,arc4random_buf,void,"void*, size_t" +Function,-,arc4random_uniform,__uint32_t,__uint32_t +Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*" +Function,+,args_get_first_word_length,size_t,FuriString* +Function,+,args_length,size_t,FuriString* +Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t" +Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*" +Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*" +Function,+,args_read_string_and_trim,_Bool,"FuriString*, FuriString*" +Function,-,asctime,char*,const tm* +Function,-,asctime_r,char*,"const tm*, char*" +Function,-,asiprintf,int,"char**, const char*, ..." +Function,-,asniprintf,char*,"char*, size_t*, const char*, ..." +Function,-,asnprintf,char*,"char*, size_t*, const char*, ..." +Function,-,asprintf,int,"char**, const char*, ..." +Function,-,at_quick_exit,int,void (*)() +Function,-,atexit,int,void (*)() +Function,-,atof,double,const char* +Function,-,atoff,float,const char* +Function,+,atoi,int,const char* +Function,-,atol,long,const char* +Function,-,atoll,long long,const char* +Function,-,basename,char*,const char* +Function,-,bcmp,int,"const void*, const void*, size_t" +Function,-,bcopy,void,"const void*, void*, size_t" +Function,+,ble_app_get_key_storage_buff,void,"uint8_t**, uint16_t*" +Function,+,ble_app_init,_Bool, +Function,+,ble_app_thread_stop,void, +Function,+,ble_glue_force_c2_mode,BleGlueCommandResult,BleGlueC2Mode +Function,-,ble_glue_fus_get_status,BleGlueCommandResult, +Function,-,ble_glue_fus_stack_delete,BleGlueCommandResult, +Function,-,ble_glue_fus_stack_install,BleGlueCommandResult,"uint32_t, uint32_t" +Function,-,ble_glue_fus_wait_operation,BleGlueCommandResult, +Function,+,ble_glue_get_c2_info,const BleGlueC2Info*, +Function,-,ble_glue_get_c2_status,BleGlueStatus, +Function,+,ble_glue_init,void, +Function,+,ble_glue_is_alive,_Bool, +Function,+,ble_glue_is_radio_stack_ready,_Bool, +Function,+,ble_glue_reinit_c2,_Bool, +Function,+,ble_glue_set_key_storage_changed_callback,void,"BleGlueKeyStorageChangedCallback, void*" +Function,+,ble_glue_start,_Bool, +Function,+,ble_glue_thread_stop,void, +Function,+,ble_glue_wait_for_c2_start,_Bool,int32_t +Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_t" +Function,+,bt_disconnect,void,Bt* +Function,+,bt_forget_bonded_devices,void,Bt* +Function,+,bt_keys_storage_set_default_path,void,Bt* +Function,+,bt_keys_storage_set_storage_path,void,"Bt*, const char*" +Function,+,bt_set_profile,_Bool,"Bt*, BtProfile" +Function,+,bt_set_status_changed_callback,void,"Bt*, BtStatusChangedCallback, void*" +Function,+,buffered_file_stream_alloc,Stream*,Storage* +Function,+,buffered_file_stream_close,_Bool,Stream* +Function,+,buffered_file_stream_get_error,FS_Error,Stream* +Function,+,buffered_file_stream_open,_Bool,"Stream*, const char*, FS_AccessMode, FS_OpenMode" +Function,+,buffered_file_stream_sync,_Bool,Stream* +Function,+,button_menu_add_item,ButtonMenuItem*,"ButtonMenu*, const char*, int32_t, ButtonMenuItemCallback, ButtonMenuItemType, void*" +Function,+,button_menu_alloc,ButtonMenu*, +Function,+,button_menu_free,void,ButtonMenu* +Function,+,button_menu_get_view,View*,ButtonMenu* +Function,+,button_menu_reset,void,ButtonMenu* +Function,+,button_menu_set_header,void,"ButtonMenu*, const char*" +Function,+,button_menu_set_selected_item,void,"ButtonMenu*, uint32_t" +Function,+,button_panel_add_item,void,"ButtonPanel*, uint32_t, uint16_t, uint16_t, uint16_t, uint16_t, const Icon*, const Icon*, ButtonItemCallback, void*" +Function,+,button_panel_add_label,void,"ButtonPanel*, uint16_t, uint16_t, Font, const char*" +Function,+,button_panel_alloc,ButtonPanel*, +Function,+,button_panel_free,void,ButtonPanel* +Function,+,button_panel_get_view,View*,ButtonPanel* +Function,+,button_panel_reserve,void,"ButtonPanel*, size_t, size_t" +Function,+,button_panel_reset,void,ButtonPanel* +Function,+,byte_input_alloc,ByteInput*, +Function,+,byte_input_free,void,ByteInput* +Function,+,byte_input_get_view,View*,ByteInput* +Function,+,byte_input_set_header_text,void,"ByteInput*, const char*" +Function,+,byte_input_set_result_callback,void,"ByteInput*, ByteInputCallback, ByteChangedCallback, void*, uint8_t*, uint8_t" +Function,-,bzero,void,"void*, size_t" +Function,-,calloc,void*,"size_t, size_t" +Function,+,canvas_clear,void,Canvas* +Function,+,canvas_commit,void,Canvas* +Function,+,canvas_current_font_height,uint8_t,Canvas* +Function,+,canvas_draw_bitmap,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" +Function,+,canvas_draw_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_circle,void,"Canvas*, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_disc,void,"Canvas*, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_dot,void,"Canvas*, uint8_t, uint8_t" +Function,+,canvas_draw_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_glyph,void,"Canvas*, uint8_t, uint8_t, uint16_t" +Function,+,canvas_draw_icon,void,"Canvas*, uint8_t, uint8_t, const Icon*" +Function,+,canvas_draw_icon_animation,void,"Canvas*, uint8_t, uint8_t, IconAnimation*" +Function,+,canvas_draw_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_rbox,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_rframe,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,canvas_draw_str,void,"Canvas*, uint8_t, uint8_t, const char*" +Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" +Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" +Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" +Function,+,canvas_get_font_params,CanvasFontParameters*,"Canvas*, Font" +Function,+,canvas_glyph_width,uint8_t,"Canvas*, char" +Function,+,canvas_height,uint8_t,Canvas* +Function,+,canvas_invert_color,void,Canvas* +Function,+,canvas_reset,void,Canvas* +Function,+,canvas_set_bitmap_mode,void,"Canvas*, _Bool" +Function,+,canvas_set_color,void,"Canvas*, Color" +Function,+,canvas_set_font,void,"Canvas*, Font" +Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" +Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" +Function,+,canvas_width,uint8_t,Canvas* +Function,-,cfree,void,void* +Function,-,clearerr,void,FILE* +Function,-,clearerr_unlocked,void,FILE* +Function,+,cli_add_command,void,"Cli*, const char*, CliCommandFlag, CliCallback, void*" +Function,+,cli_cmd_interrupt_received,_Bool,Cli* +Function,+,cli_delete_command,void,"Cli*, const char*" +Function,+,cli_getc,char,Cli* +Function,+,cli_is_connected,_Bool,Cli* +Function,+,cli_nl,void, +Function,+,cli_print_usage,void,"const char*, const char*, const char*" +Function,+,cli_read,size_t,"Cli*, uint8_t*, size_t" +Function,+,cli_read_timeout,size_t,"Cli*, uint8_t*, size_t, uint32_t" +Function,+,cli_session_close,void,Cli* +Function,+,cli_session_open,void,"Cli*, void*" +Function,+,cli_write,void,"Cli*, const uint8_t*, size_t" +Function,-,clock,clock_t, +Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" +Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" +Function,-,ctermid,char*,char* +Function,-,ctime,char*,const time_t* +Function,-,ctime_r,char*,"const time_t*, char*" +Function,-,cuserid,char*,char* +Function,+,delete_mutex,_Bool,ValueMutex* +Function,+,dialog_ex_alloc,DialogEx*, +Function,+,dialog_ex_disable_extended_events,void,DialogEx* +Function,+,dialog_ex_enable_extended_events,void,DialogEx* +Function,+,dialog_ex_free,void,DialogEx* +Function,+,dialog_ex_get_view,View*,DialogEx* +Function,+,dialog_ex_reset,void,DialogEx* +Function,+,dialog_ex_set_center_button_text,void,"DialogEx*, const char*" +Function,+,dialog_ex_set_context,void,"DialogEx*, void*" +Function,+,dialog_ex_set_header,void,"DialogEx*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,dialog_ex_set_icon,void,"DialogEx*, uint8_t, uint8_t, const Icon*" +Function,+,dialog_ex_set_left_button_text,void,"DialogEx*, const char*" +Function,+,dialog_ex_set_result_callback,void,"DialogEx*, DialogExResultCallback" +Function,+,dialog_ex_set_right_button_text,void,"DialogEx*, const char*" +Function,+,dialog_ex_set_text,void,"DialogEx*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,dialog_file_browser_set_basic_options,void,"DialogsFileBrowserOptions*, const char*, const Icon*" +Function,+,dialog_file_browser_show,_Bool,"DialogsApp*, FuriString*, FuriString*, const DialogsFileBrowserOptions*" +Function,+,dialog_message_alloc,DialogMessage*, +Function,+,dialog_message_free,void,DialogMessage* +Function,+,dialog_message_set_buttons,void,"DialogMessage*, const char*, const char*, const char*" +Function,+,dialog_message_set_header,void,"DialogMessage*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,dialog_message_set_icon,void,"DialogMessage*, const Icon*, uint8_t, uint8_t" +Function,+,dialog_message_set_text,void,"DialogMessage*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMessage*" +Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" +Function,-,difftime,double,"time_t, time_t" +Function,-,diprintf,int,"int, const char*, ..." +Function,+,dir_walk_alloc,DirWalk*,Storage* +Function,+,dir_walk_close,void,DirWalk* +Function,+,dir_walk_free,void,DirWalk* +Function,+,dir_walk_get_error,FS_Error,DirWalk* +Function,+,dir_walk_open,_Bool,"DirWalk*, const char*" +Function,+,dir_walk_read,DirWalkResult,"DirWalk*, FuriString*, FileInfo*" +Function,+,dir_walk_set_filter_cb,void,"DirWalk*, DirWalkFilterCb, void*" +Function,+,dir_walk_set_recursive,void,"DirWalk*, _Bool" +Function,-,div,div_t,"int, int" +Function,+,dolphin_deed,void,"Dolphin*, DolphinDeed" +Function,+,dolphin_deed_get_app,DolphinApp,DolphinDeed +Function,+,dolphin_deed_get_app_limit,uint8_t,DolphinApp +Function,+,dolphin_deed_get_weight,uint8_t,DolphinDeed +Function,+,dolphin_flush,void,Dolphin* +Function,+,dolphin_get_pubsub,FuriPubSub*,Dolphin* +Function,+,dolphin_stats,DolphinStats,Dolphin* +Function,+,dolphin_upgrade_level,void,Dolphin* +Function,-,dprintf,int,"int, const char*, ..." +Function,-,drand48,double, +Function,-,eTaskConfirmSleepModeStatus,eSleepModeStatus, +Function,-,eTaskGetState,eTaskState,TaskHandle_t +Function,+,elements_bold_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_bubble,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_bubble_str,void,"Canvas*, uint8_t, uint8_t, const char*, Align, Align" +Function,+,elements_button_center,void,"Canvas*, const char*" +Function,+,elements_button_left,void,"Canvas*, const char*" +Function,+,elements_button_right,void,"Canvas*, const char*" +Function,+,elements_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_multiline_text,void,"Canvas*, uint8_t, uint8_t, const char*" +Function,+,elements_multiline_text_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" +Function,+,elements_multiline_text_framed,void,"Canvas*, uint8_t, uint8_t, const char*" +Function,+,elements_progress_bar,void,"Canvas*, uint8_t, uint8_t, uint8_t, float" +Function,+,elements_progress_bar_with_text,void,"Canvas*, uint8_t, uint8_t, uint8_t, float, const char*" +Function,+,elements_scrollable_text_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, FuriString*, size_t, _Bool" +Function,+,elements_scrollbar,void,"Canvas*, uint16_t, uint16_t" +Function,+,elements_scrollbar_pos,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t" +Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t" +Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool" +Function,+,empty_screen_alloc,EmptyScreen*, +Function,+,empty_screen_free,void,EmptyScreen* +Function,+,empty_screen_get_view,View*,EmptyScreen* +Function,-,erand48,double,unsigned short[3] +Function,-,exit,void,int +Function,-,explicit_bzero,void,"void*, size_t" +Function,-,fclose,int,FILE* +Function,-,fcloseall,int, +Function,-,fdopen,FILE*,"int, const char*" +Function,-,feof,int,FILE* +Function,-,feof_unlocked,int,FILE* +Function,-,ferror,int,FILE* +Function,-,ferror_unlocked,int,FILE* +Function,-,fflush,int,FILE* +Function,-,fflush_unlocked,int,FILE* +Function,-,ffs,int,int +Function,-,ffsl,int,long +Function,-,ffsll,int,long long +Function,-,fgetc,int,FILE* +Function,-,fgetc_unlocked,int,FILE* +Function,-,fgetpos,int,"FILE*, fpos_t*" +Function,-,fgets,char*,"char*, int, FILE*" +Function,-,fgets_unlocked,char*,"char*, int, FILE*" +Function,+,file_browser_alloc,FileBrowser*,FuriString* +Function,+,file_browser_configure,void,"FileBrowser*, const char*, const char*, _Bool, _Bool, const Icon*, _Bool" +Function,+,file_browser_free,void,FileBrowser* +Function,+,file_browser_get_view,View*,FileBrowser* +Function,+,file_browser_set_callback,void,"FileBrowser*, FileBrowserCallback, void*" +Function,+,file_browser_set_item_callback,void,"FileBrowser*, FileBrowserLoadItemCallback, void*" +Function,+,file_browser_start,void,"FileBrowser*, FuriString*" +Function,+,file_browser_stop,void,FileBrowser* +Function,+,file_browser_worker_alloc,BrowserWorker*,"FuriString*, const char*, const char*, _Bool, _Bool" +Function,+,file_browser_worker_folder_enter,void,"BrowserWorker*, FuriString*, int32_t" +Function,+,file_browser_worker_folder_exit,void,BrowserWorker* +Function,+,file_browser_worker_folder_refresh,void,"BrowserWorker*, int32_t" +Function,+,file_browser_worker_free,void,BrowserWorker* +Function,+,file_browser_worker_is_in_start_folder,_Bool,BrowserWorker* +Function,+,file_browser_worker_load,void,"BrowserWorker*, uint32_t, uint32_t" +Function,+,file_browser_worker_set_callback_context,void,"BrowserWorker*, void*" +Function,+,file_browser_worker_set_config,void,"BrowserWorker*, FuriString*, const char*, _Bool, _Bool" +Function,+,file_browser_worker_set_folder_callback,void,"BrowserWorker*, BrowserWorkerFolderOpenCallback" +Function,+,file_browser_worker_set_item_callback,void,"BrowserWorker*, BrowserWorkerListItemCallback" +Function,+,file_browser_worker_set_list_callback,void,"BrowserWorker*, BrowserWorkerListLoadCallback" +Function,+,file_browser_worker_set_long_load_callback,void,"BrowserWorker*, BrowserWorkerLongLoadCallback" +Function,+,file_stream_alloc,Stream*,Storage* +Function,+,file_stream_close,_Bool,Stream* +Function,+,file_stream_get_error,FS_Error,Stream* +Function,+,file_stream_open,_Bool,"Stream*, const char*, FS_AccessMode, FS_OpenMode" +Function,-,fileno,int,FILE* +Function,-,fileno_unlocked,int,FILE* +Function,+,filesystem_api_error_get_desc,const char*,FS_Error +Function,-,fiprintf,int,"FILE*, const char*, ..." +Function,-,fiscanf,int,"FILE*, const char*, ..." +Function,+,flipper_application_alloc,FlipperApplication*,"Storage*, const ElfApiInterface*" +Function,+,flipper_application_free,void,FlipperApplication* +Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,FlipperApplication* +Function,+,flipper_application_load_status_to_string,const char*,FlipperApplicationLoadStatus +Function,+,flipper_application_manifest_is_compatible,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*" +Function,+,flipper_application_manifest_is_target_compatible,_Bool,const FlipperApplicationManifest* +Function,+,flipper_application_manifest_is_valid,_Bool,const FlipperApplicationManifest* +Function,+,flipper_application_map_to_memory,FlipperApplicationLoadStatus,FlipperApplication* +Function,+,flipper_application_preload,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" +Function,+,flipper_application_preload_manifest,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" +Function,-,flipper_application_preload_status_to_string,const char*,FlipperApplicationPreloadStatus +Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" +Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* +Function,+,flipper_format_buffered_file_close,_Bool,FlipperFormat* +Function,+,flipper_format_buffered_file_open_existing,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_delete_key,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_file_alloc,FlipperFormat*,Storage* +Function,+,flipper_format_file_close,_Bool,FlipperFormat* +Function,+,flipper_format_file_open_always,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_file_open_append,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_file_open_existing,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_file_open_new,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_free,void,FlipperFormat* +Function,+,flipper_format_get_raw_stream,Stream*,FlipperFormat* +Function,+,flipper_format_get_value_count,_Bool,"FlipperFormat*, const char*, uint32_t*" +Function,+,flipper_format_insert_or_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" +Function,+,flipper_format_insert_or_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" +Function,+,flipper_format_insert_or_update_hex,_Bool,"FlipperFormat*, const char*, const uint8_t*, const uint16_t" +Function,+,flipper_format_insert_or_update_int32,_Bool,"FlipperFormat*, const char*, const int32_t*, const uint16_t" +Function,+,flipper_format_insert_or_update_string,_Bool,"FlipperFormat*, const char*, FuriString*" +Function,+,flipper_format_insert_or_update_string_cstr,_Bool,"FlipperFormat*, const char*, const char*" +Function,+,flipper_format_insert_or_update_uint32,_Bool,"FlipperFormat*, const char*, const uint32_t*, const uint16_t" +Function,+,flipper_format_key_exist,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_read_bool,_Bool,"FlipperFormat*, const char*, _Bool*, const uint16_t" +Function,+,flipper_format_read_float,_Bool,"FlipperFormat*, const char*, float*, const uint16_t" +Function,+,flipper_format_read_header,_Bool,"FlipperFormat*, FuriString*, uint32_t*" +Function,+,flipper_format_read_hex,_Bool,"FlipperFormat*, const char*, uint8_t*, const uint16_t" +Function,+,flipper_format_read_hex_uint64,_Bool,"FlipperFormat*, const char*, uint64_t*, const uint16_t" +Function,+,flipper_format_read_int32,_Bool,"FlipperFormat*, const char*, int32_t*, const uint16_t" +Function,+,flipper_format_read_string,_Bool,"FlipperFormat*, const char*, FuriString*" +Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32_t*, const uint16_t" +Function,+,flipper_format_rewind,_Bool,FlipperFormat* +Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat* +Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool" +Function,+,flipper_format_string_alloc,FlipperFormat*, +Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" +Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" +Function,+,flipper_format_update_hex,_Bool,"FlipperFormat*, const char*, const uint8_t*, const uint16_t" +Function,+,flipper_format_update_int32,_Bool,"FlipperFormat*, const char*, const int32_t*, const uint16_t" +Function,+,flipper_format_update_string,_Bool,"FlipperFormat*, const char*, FuriString*" +Function,+,flipper_format_update_string_cstr,_Bool,"FlipperFormat*, const char*, const char*" +Function,+,flipper_format_update_uint32,_Bool,"FlipperFormat*, const char*, const uint32_t*, const uint16_t" +Function,+,flipper_format_write_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" +Function,+,flipper_format_write_comment,_Bool,"FlipperFormat*, FuriString*" +Function,+,flipper_format_write_comment_cstr,_Bool,"FlipperFormat*, const char*" +Function,+,flipper_format_write_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" +Function,+,flipper_format_write_header,_Bool,"FlipperFormat*, FuriString*, const uint32_t" +Function,+,flipper_format_write_header_cstr,_Bool,"FlipperFormat*, const char*, const uint32_t" +Function,+,flipper_format_write_hex,_Bool,"FlipperFormat*, const char*, const uint8_t*, const uint16_t" +Function,+,flipper_format_write_hex_uint64,_Bool,"FlipperFormat*, const char*, const uint64_t*, const uint16_t" +Function,+,flipper_format_write_int32,_Bool,"FlipperFormat*, const char*, const int32_t*, const uint16_t" +Function,+,flipper_format_write_string,_Bool,"FlipperFormat*, const char*, FuriString*" +Function,+,flipper_format_write_string_cstr,_Bool,"FlipperFormat*, const char*, const char*" +Function,+,flipper_format_write_uint32,_Bool,"FlipperFormat*, const char*, const uint32_t*, const uint16_t" +Function,+,float_is_equal,_Bool,"float, float" +Function,-,flockfile,void,FILE* +Function,-,fls,int,int +Function,-,flsl,int,long +Function,-,flsll,int,long long +Function,-,fmemopen,FILE*,"void*, size_t, const char*" +Function,-,fopen,FILE*,"const char*, const char*" +Function,-,fopencookie,FILE*,"void*, const char*, cookie_io_functions_t" +Function,-,fprintf,int,"FILE*, const char*, ..." +Function,-,fpurge,int,FILE* +Function,-,fputc,int,"int, FILE*" +Function,-,fputc_unlocked,int,"int, FILE*" +Function,-,fputs,int,"const char*, FILE*" +Function,-,fputs_unlocked,int,"const char*, FILE*" +Function,-,fread,size_t,"void*, size_t, size_t, FILE*" +Function,-,fread_unlocked,size_t,"void*, size_t, size_t, FILE*" +Function,+,free,void,void* +Function,-,freopen,FILE*,"const char*, const char*, FILE*" +Function,-,fscanf,int,"FILE*, const char*, ..." +Function,-,fseek,int,"FILE*, long, int" +Function,-,fseeko,int,"FILE*, off_t, int" +Function,-,fsetpos,int,"FILE*, const fpos_t*" +Function,-,ftell,long,FILE* +Function,-,ftello,off_t,FILE* +Function,-,ftrylockfile,int,FILE* +Function,-,funlockfile,void,FILE* +Function,-,funopen,FILE*,"const void*, int (*)(void*, char*, int), int (*)(void*, const char*, int), fpos_t (*)(void*, fpos_t, int), int (*)(void*)" +Function,+,furi_delay_ms,void,uint32_t +Function,+,furi_delay_tick,void,uint32_t +Function,+,furi_delay_until_tick,FuriStatus,uint32_t +Function,+,furi_delay_us,void,uint32_t +Function,+,furi_event_flag_alloc,FuriEventFlag*, +Function,+,furi_event_flag_clear,uint32_t,"FuriEventFlag*, uint32_t" +Function,+,furi_event_flag_free,void,FuriEventFlag* +Function,+,furi_event_flag_get,uint32_t,FuriEventFlag* +Function,+,furi_event_flag_set,uint32_t,"FuriEventFlag*, uint32_t" +Function,+,furi_event_flag_wait,uint32_t,"FuriEventFlag*, uint32_t, uint32_t, uint32_t" +Function,+,furi_get_tick,uint32_t, +Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*" +Function,+,furi_hal_bt_clear_white_list,_Bool, +Function,+,furi_hal_bt_dump_state,void,FuriString* +Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode +Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" +Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, +Function,+,furi_hal_bt_get_rssi,float, +Function,+,furi_hal_bt_get_transmitted_packets,uint32_t, +Function,+,furi_hal_bt_hid_consumer_key_press,_Bool,uint16_t +Function,+,furi_hal_bt_hid_consumer_key_release,_Bool,uint16_t +Function,+,furi_hal_bt_hid_consumer_key_release_all,_Bool, +Function,+,furi_hal_bt_hid_kb_press,_Bool,uint16_t +Function,+,furi_hal_bt_hid_kb_release,_Bool,uint16_t +Function,+,furi_hal_bt_hid_kb_release_all,_Bool, +Function,+,furi_hal_bt_hid_mouse_move,_Bool,"int8_t, int8_t" +Function,+,furi_hal_bt_hid_mouse_press,_Bool,uint8_t +Function,+,furi_hal_bt_hid_mouse_release,_Bool,uint8_t +Function,+,furi_hal_bt_hid_mouse_release_all,_Bool, +Function,+,furi_hal_bt_hid_mouse_scroll,_Bool,int8_t +Function,+,furi_hal_bt_hid_start,void, +Function,+,furi_hal_bt_hid_stop,void, +Function,-,furi_hal_bt_init,void, +Function,+,furi_hal_bt_is_active,_Bool, +Function,+,furi_hal_bt_is_alive,_Bool, +Function,+,furi_hal_bt_is_ble_gatt_gap_supported,_Bool, +Function,+,furi_hal_bt_is_testing_supported,_Bool, +Function,+,furi_hal_bt_lock_core2,void, +Function,+,furi_hal_bt_nvm_sram_sem_acquire,void, +Function,+,furi_hal_bt_nvm_sram_sem_release,void, +Function,+,furi_hal_bt_reinit,void, +Function,+,furi_hal_bt_serial_notify_buffer_is_empty,void, +Function,+,furi_hal_bt_serial_set_event_callback,void,"uint16_t, FuriHalBtSerialCallback, void*" +Function,+,furi_hal_bt_serial_set_rpc_status,void,FuriHalBtSerialRpcStatus +Function,+,furi_hal_bt_serial_start,void, +Function,+,furi_hal_bt_serial_stop,void, +Function,+,furi_hal_bt_serial_tx,_Bool,"uint8_t*, uint16_t" +Function,+,furi_hal_bt_set_key_storage_change_callback,void,"BleGlueKeyStorageChangedCallback, void*" +Function,+,furi_hal_bt_start_advertising,void, +Function,+,furi_hal_bt_start_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*" +Function,+,furi_hal_bt_start_packet_rx,void,"uint8_t, uint8_t" +Function,+,furi_hal_bt_start_packet_tx,void,"uint8_t, uint8_t, uint8_t" +Function,+,furi_hal_bt_start_radio_stack,_Bool, +Function,+,furi_hal_bt_start_rx,void,uint8_t +Function,+,furi_hal_bt_start_tone_tx,void,"uint8_t, uint8_t" +Function,+,furi_hal_bt_stop_advertising,void, +Function,+,furi_hal_bt_stop_packet_test,uint16_t, +Function,+,furi_hal_bt_stop_rx,void, +Function,+,furi_hal_bt_stop_tone_tx,void, +Function,+,furi_hal_bt_unlock_core2,void, +Function,+,furi_hal_bt_update_battery_level,void,uint8_t +Function,+,furi_hal_bt_update_power_state,void, +Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t +Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t +Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" +Function,+,furi_hal_cdc_send,void,"uint8_t, uint8_t*, uint16_t" +Function,+,furi_hal_cdc_set_callbacks,void,"uint8_t, CdcCallbacks*, void*" +Function,-,furi_hal_clock_deinit_early,void, +Function,-,furi_hal_clock_init,void, +Function,-,furi_hal_clock_init_early,void, +Function,+,furi_hal_clock_mco_disable,void, +Function,+,furi_hal_clock_mco_enable,void,"FuriHalClockMcoSourceId, FuriHalClockMcoDivisorId" +Function,-,furi_hal_clock_resume_tick,void, +Function,-,furi_hal_clock_suspend_tick,void, +Function,-,furi_hal_clock_switch_to_hsi,void, +Function,-,furi_hal_clock_switch_to_pll,void, +Function,-,furi_hal_compress_alloc,FuriHalCompress*,uint16_t +Function,-,furi_hal_compress_decode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" +Function,-,furi_hal_compress_encode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" +Function,-,furi_hal_compress_free,void,FuriHalCompress* +Function,-,furi_hal_compress_icon_decode,void,"const uint8_t*, uint8_t**" +Function,-,furi_hal_compress_icon_init,void, +Function,+,furi_hal_console_disable,void, +Function,+,furi_hal_console_enable,void, +Function,+,furi_hal_console_init,void, +Function,+,furi_hal_console_printf,void,"const char[], ..." +Function,+,furi_hal_console_puts,void,const char* +Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" +Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" +Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" +Function,+,furi_hal_cortex_delay_us,void,uint32_t +Function,-,furi_hal_cortex_init_early,void, +Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, +Function,+,furi_hal_cortex_timer_get,FuriHalCortexTimer,uint32_t +Function,+,furi_hal_cortex_timer_is_expired,_Bool,FuriHalCortexTimer +Function,+,furi_hal_cortex_timer_wait,void,FuriHalCortexTimer +Function,+,furi_hal_crypto_decrypt,_Bool,"const uint8_t*, uint8_t*, size_t" +Function,+,furi_hal_crypto_encrypt,_Bool,"const uint8_t*, uint8_t*, size_t" +Function,-,furi_hal_crypto_init,void, +Function,+,furi_hal_crypto_store_add_key,_Bool,"FuriHalCryptoKey*, uint8_t*" +Function,+,furi_hal_crypto_store_load_key,_Bool,"uint8_t, const uint8_t*" +Function,+,furi_hal_crypto_store_unload_key,_Bool,uint8_t +Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*" +Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t +Function,+,furi_hal_debug_disable,void, +Function,+,furi_hal_debug_enable,void, +Function,-,furi_hal_deinit_early,void, +Function,-,furi_hal_flash_erase,void,uint8_t +Function,-,furi_hal_flash_get_base,size_t, +Function,-,furi_hal_flash_get_cycles_count,size_t, +Function,-,furi_hal_flash_get_free_end_address,const void*, +Function,-,furi_hal_flash_get_free_page_count,size_t, +Function,-,furi_hal_flash_get_free_page_start_address,size_t, +Function,-,furi_hal_flash_get_free_start_address,const void*, +Function,-,furi_hal_flash_get_page_number,int16_t,size_t +Function,-,furi_hal_flash_get_page_size,size_t, +Function,-,furi_hal_flash_get_read_block_size,size_t, +Function,-,furi_hal_flash_get_write_block_size,size_t, +Function,-,furi_hal_flash_init,void, +Function,-,furi_hal_flash_ob_apply,void, +Function,-,furi_hal_flash_ob_get_raw_ptr,const FuriHalFlashRawOptionByteData*, +Function,-,furi_hal_flash_ob_set_word,_Bool,"size_t, const uint32_t" +Function,-,furi_hal_flash_program_page,void,"const uint8_t, const uint8_t*, uint16_t" +Function,-,furi_hal_flash_write_dword,void,"size_t, uint64_t" +Function,+,furi_hal_gpio_add_int_callback,void,"const GpioPin*, GpioExtiCallback, void*" +Function,+,furi_hal_gpio_disable_int_callback,void,const GpioPin* +Function,+,furi_hal_gpio_enable_int_callback,void,const GpioPin* +Function,+,furi_hal_gpio_init,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed" +Function,+,furi_hal_gpio_init_ex,void,"const GpioPin*, const GpioMode, const GpioPull, const GpioSpeed, const GpioAltFn" +Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode" +Function,+,furi_hal_gpio_remove_int_callback,void,const GpioPin* +Function,+,furi_hal_hid_consumer_key_press,_Bool,uint16_t +Function,+,furi_hal_hid_consumer_key_release,_Bool,uint16_t +Function,+,furi_hal_hid_get_led_state,uint8_t, +Function,+,furi_hal_hid_is_connected,_Bool, +Function,+,furi_hal_hid_kb_press,_Bool,uint16_t +Function,+,furi_hal_hid_kb_release,_Bool,uint16_t +Function,+,furi_hal_hid_kb_release_all,_Bool, +Function,+,furi_hal_hid_mouse_move,_Bool,"int8_t, int8_t" +Function,+,furi_hal_hid_mouse_press,_Bool,uint8_t +Function,+,furi_hal_hid_mouse_release,_Bool,uint8_t +Function,+,furi_hal_hid_mouse_scroll,_Bool,int8_t +Function,+,furi_hal_hid_set_state_callback,void,"HidStateCallback, void*" +Function,+,furi_hal_hid_u2f_get_request,uint32_t,uint8_t* +Function,+,furi_hal_hid_u2f_is_connected,_Bool, +Function,+,furi_hal_hid_u2f_send_response,void,"uint8_t*, uint8_t" +Function,+,furi_hal_hid_u2f_set_callback,void,"HidU2fCallback, void*" +Function,+,furi_hal_i2c_acquire,void,FuriHalI2cBusHandle* +Function,-,furi_hal_i2c_deinit_early,void, +Function,-,furi_hal_i2c_init,void, +Function,-,furi_hal_i2c_init_early,void, +Function,+,furi_hal_i2c_is_device_ready,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint32_t" +Function,+,furi_hal_i2c_read_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t" +Function,+,furi_hal_i2c_read_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t*, uint32_t" +Function,+,furi_hal_i2c_read_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint32_t" +Function,+,furi_hal_i2c_release,void,FuriHalI2cBusHandle* +Function,+,furi_hal_i2c_rx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, uint8_t*, const uint8_t, uint32_t" +Function,+,furi_hal_i2c_trx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, const uint8_t*, const uint8_t, uint8_t*, const uint8_t, uint32_t" +Function,+,furi_hal_i2c_tx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, const uint8_t*, const uint8_t, uint32_t" +Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t" +Function,+,furi_hal_i2c_write_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t" +Function,+,furi_hal_i2c_write_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t, uint32_t" +Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*" +Function,-,furi_hal_init,void, +Function,-,furi_hal_init_early,void, +Function,-,furi_hal_interrupt_init,void, +Function,+,furi_hal_interrupt_set_isr,void,"FuriHalInterruptId, FuriHalInterruptISR, void*" +Function,+,furi_hal_interrupt_set_isr_ex,void,"FuriHalInterruptId, uint16_t, FuriHalInterruptISR, void*" +Function,+,furi_hal_light_blink_set_color,void,Light +Function,+,furi_hal_light_blink_start,void,"Light, uint8_t, uint16_t, uint16_t" +Function,+,furi_hal_light_blink_stop,void, +Function,-,furi_hal_light_init,void, +Function,+,furi_hal_light_sequence,void,const char* +Function,+,furi_hal_light_set,void,"Light, uint8_t" +Function,+,furi_hal_memory_alloc,void*,size_t +Function,+,furi_hal_memory_get_free,size_t, +Function,+,furi_hal_memory_init,void, +Function,+,furi_hal_memory_max_pool_block,size_t, +Function,+,furi_hal_mpu_disable,void, +Function,+,furi_hal_mpu_enable,void, +Function,-,furi_hal_mpu_init,void, +Function,+,furi_hal_mpu_protect_disable,void,FuriHalMpuRegion +Function,+,furi_hal_mpu_protect_no_access,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" +Function,+,furi_hal_mpu_protect_read_only,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" +Function,-,furi_hal_os_init,void, +Function,+,furi_hal_os_tick,void, +Function,+,furi_hal_power_check_otg_status,void, +Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*" +Function,+,furi_hal_power_deep_sleep_available,_Bool, +Function,+,furi_hal_power_disable_external_3_3v,void, +Function,+,furi_hal_power_disable_otg,void, +Function,+,furi_hal_power_enable_external_3_3v,void, +Function,+,furi_hal_power_enable_otg,void, +Function,+,furi_hal_power_gauge_is_ok,_Bool, +Function,+,furi_hal_power_get_bat_health_pct,uint8_t, +Function,+,furi_hal_power_get_battery_charging_voltage,float, +Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC +Function,+,furi_hal_power_get_battery_design_capacity,uint32_t, +Function,+,furi_hal_power_get_battery_full_capacity,uint32_t, +Function,+,furi_hal_power_get_battery_remaining_capacity,uint32_t, +Function,+,furi_hal_power_get_battery_temperature,float,FuriHalPowerIC +Function,+,furi_hal_power_get_battery_voltage,float,FuriHalPowerIC +Function,+,furi_hal_power_get_pct,uint8_t, +Function,+,furi_hal_power_get_usb_voltage,float, +Function,+,furi_hal_power_info_get,void,"PropertyValueCallback, char, void*" +Function,-,furi_hal_power_init,void, +Function,+,furi_hal_power_insomnia_enter,void, +Function,+,furi_hal_power_insomnia_exit,void, +Function,-,furi_hal_power_insomnia_level,uint16_t, +Function,+,furi_hal_power_is_charging,_Bool, +Function,+,furi_hal_power_is_charging_done,_Bool, +Function,+,furi_hal_power_is_otg_enabled,_Bool, +Function,+,furi_hal_power_off,void, +Function,+,furi_hal_power_reset,void, +Function,+,furi_hal_power_set_battery_charging_voltage,void,float +Function,+,furi_hal_power_shutdown,void, +Function,+,furi_hal_power_sleep,void, +Function,+,furi_hal_power_sleep_available,_Bool, +Function,+,furi_hal_power_suppress_charge_enter,void, +Function,+,furi_hal_power_suppress_charge_exit,void, +Function,+,furi_hal_pwm_set_params,void,"FuriHalPwmOutputId, uint32_t, uint8_t" +Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t" +Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId +Function,+,furi_hal_random_fill_buf,void,"uint8_t*, uint32_t" +Function,+,furi_hal_random_get,uint32_t, +Function,+,furi_hal_region_get,const FuriHalRegion*, +Function,+,furi_hal_region_get_band,const FuriHalRegionBand*,uint32_t +Function,+,furi_hal_region_get_name,const char*, +Function,-,furi_hal_region_init,void, +Function,+,furi_hal_region_is_frequency_allowed,_Bool,uint32_t +Function,+,furi_hal_region_is_provisioned,_Bool, +Function,+,furi_hal_region_set,void,FuriHalRegion* +Function,-,furi_hal_resources_deinit_early,void, +Function,-,furi_hal_resources_init,void, +Function,-,furi_hal_resources_init_early,void, +Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* +Function,-,furi_hal_rtc_deinit_early,void, +Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, +Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime* +Function,+,furi_hal_rtc_get_fault_data,uint32_t, +Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode, +Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat, +Function,+,furi_hal_rtc_get_locale_timeformat,FuriHalRtcLocaleTimeFormat, +Function,+,furi_hal_rtc_get_locale_units,FuriHalRtcLocaleUnits, +Function,+,furi_hal_rtc_get_log_level,uint8_t, +Function,+,furi_hal_rtc_get_pin_fails,uint32_t, +Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister +Function,+,furi_hal_rtc_get_timestamp,uint32_t, +Function,-,furi_hal_rtc_init,void, +Function,-,furi_hal_rtc_init_early,void, +Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag +Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag +Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode +Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* +Function,+,furi_hal_rtc_set_fault_data,void,uint32_t +Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag +Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode +Function,+,furi_hal_rtc_set_locale_dateformat,void,FuriHalRtcLocaleDateFormat +Function,+,furi_hal_rtc_set_locale_timeformat,void,FuriHalRtcLocaleTimeFormat +Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits +Function,+,furi_hal_rtc_set_log_level,void,uint8_t +Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t +Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" +Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* +Function,+,furi_hal_speaker_acquire,_Bool,uint32_t +Function,-,furi_hal_speaker_deinit,void, +Function,-,furi_hal_speaker_init,void, +Function,+,furi_hal_speaker_is_mine,_Bool, +Function,+,furi_hal_speaker_release,void, +Function,+,furi_hal_speaker_set_volume,void,float +Function,+,furi_hal_speaker_start,void,"float, float" +Function,+,furi_hal_speaker_stop,void, +Function,+,furi_hal_spi_acquire,void,FuriHalSpiBusHandle* +Function,+,furi_hal_spi_bus_deinit,void,FuriHalSpiBus* +Function,+,furi_hal_spi_bus_handle_deinit,void,FuriHalSpiBusHandle* +Function,+,furi_hal_spi_bus_handle_init,void,FuriHalSpiBusHandle* +Function,+,furi_hal_spi_bus_init,void,FuriHalSpiBus* +Function,+,furi_hal_spi_bus_rx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_trx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_tx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, uint32_t" +Function,-,furi_hal_spi_config_deinit_early,void, +Function,-,furi_hal_spi_config_init,void, +Function,-,furi_hal_spi_config_init_early,void, +Function,+,furi_hal_spi_release,void,FuriHalSpiBusHandle* +Function,+,furi_hal_switch,void,void* +Function,+,furi_hal_uart_deinit,void,FuriHalUartId +Function,+,furi_hal_uart_init,void,"FuriHalUartId, uint32_t" +Function,+,furi_hal_uart_resume,void,FuriHalUartId +Function,+,furi_hal_uart_set_br,void,"FuriHalUartId, uint32_t" +Function,+,furi_hal_uart_set_irq_cb,void,"FuriHalUartId, void (*)(UartIrqEvent, uint8_t, void*), void*" +Function,+,furi_hal_uart_suspend,void,FuriHalUartId +Function,+,furi_hal_uart_tx,void,"FuriHalUartId, uint8_t*, size_t" +Function,+,furi_hal_usb_disable,void, +Function,+,furi_hal_usb_enable,void, +Function,+,furi_hal_usb_get_config,FuriHalUsbInterface*, +Function,-,furi_hal_usb_init,void, +Function,+,furi_hal_usb_is_locked,_Bool, +Function,+,furi_hal_usb_lock,void, +Function,+,furi_hal_usb_reinit,void, +Function,+,furi_hal_usb_set_config,_Bool,"FuriHalUsbInterface*, void*" +Function,-,furi_hal_usb_set_state_callback,void,"FuriHalUsbStateCallback, void*" +Function,+,furi_hal_usb_unlock,void, +Function,+,furi_hal_version_do_i_belong_here,_Bool, +Function,+,furi_hal_version_get_ble_local_device_name_ptr,const char*, +Function,+,furi_hal_version_get_ble_mac,const uint8_t*, +Function,+,furi_hal_version_get_device_name_ptr,const char*, +Function,+,furi_hal_version_get_fcc_id,const char*, +Function,+,furi_hal_version_get_firmware_version,const Version*, +Function,+,furi_hal_version_get_hw_body,uint8_t, +Function,+,furi_hal_version_get_hw_color,FuriHalVersionColor, +Function,+,furi_hal_version_get_hw_connect,uint8_t, +Function,+,furi_hal_version_get_hw_display,FuriHalVersionDisplay, +Function,+,furi_hal_version_get_hw_region,FuriHalVersionRegion, +Function,+,furi_hal_version_get_hw_region_name,const char*, +Function,+,furi_hal_version_get_hw_target,uint8_t, +Function,+,furi_hal_version_get_hw_timestamp,uint32_t, +Function,+,furi_hal_version_get_hw_version,uint8_t, +Function,+,furi_hal_version_get_ic_id,const char*, +Function,+,furi_hal_version_get_model_code,const char*, +Function,+,furi_hal_version_get_model_name,const char*, +Function,+,furi_hal_version_get_name_ptr,const char*, +Function,+,furi_hal_version_get_otp_version,FuriHalVersionOtpVersion, +Function,-,furi_hal_version_init,void, +Function,+,furi_hal_version_uid,const uint8_t*, +Function,+,furi_hal_version_uid_size,size_t, +Function,-,furi_hal_vibro_init,void, +Function,+,furi_hal_vibro_on,void,_Bool +Function,-,furi_init,void, +Function,+,furi_kernel_get_tick_frequency,uint32_t, +Function,+,furi_kernel_is_irq_or_masked,_Bool, +Function,+,furi_kernel_lock,int32_t, +Function,+,furi_kernel_restore_lock,int32_t,int32_t +Function,+,furi_kernel_unlock,int32_t, +Function,+,furi_log_get_level,FuriLogLevel, +Function,-,furi_log_init,void, +Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..." +Function,+,furi_log_set_level,void,FuriLogLevel +Function,-,furi_log_set_puts,void,FuriLogPuts +Function,-,furi_log_set_timestamp,void,FuriLogTimestamp +Function,+,furi_message_queue_alloc,FuriMessageQueue*,"uint32_t, uint32_t" +Function,+,furi_message_queue_free,void,FuriMessageQueue* +Function,+,furi_message_queue_get,FuriStatus,"FuriMessageQueue*, void*, uint32_t" +Function,+,furi_message_queue_get_capacity,uint32_t,FuriMessageQueue* +Function,+,furi_message_queue_get_count,uint32_t,FuriMessageQueue* +Function,+,furi_message_queue_get_message_size,uint32_t,FuriMessageQueue* +Function,+,furi_message_queue_get_space,uint32_t,FuriMessageQueue* +Function,+,furi_message_queue_put,FuriStatus,"FuriMessageQueue*, const void*, uint32_t" +Function,+,furi_message_queue_reset,FuriStatus,FuriMessageQueue* +Function,+,furi_ms_to_ticks,uint32_t,uint32_t +Function,+,furi_mutex_acquire,FuriStatus,"FuriMutex*, uint32_t" +Function,+,furi_mutex_alloc,FuriMutex*,FuriMutexType +Function,+,furi_mutex_free,void,FuriMutex* +Function,+,furi_mutex_get_owner,FuriThreadId,FuriMutex* +Function,+,furi_mutex_release,FuriStatus,FuriMutex* +Function,+,furi_pubsub_alloc,FuriPubSub*, +Function,-,furi_pubsub_free,void,FuriPubSub* +Function,+,furi_pubsub_publish,void,"FuriPubSub*, void*" +Function,+,furi_pubsub_subscribe,FuriPubSubSubscription*,"FuriPubSub*, FuriPubSubCallback, void*" +Function,+,furi_pubsub_unsubscribe,void,"FuriPubSub*, FuriPubSubSubscription*" +Function,+,furi_record_close,void,const char* +Function,+,furi_record_create,void,"const char*, void*" +Function,-,furi_record_destroy,_Bool,const char* +Function,+,furi_record_exists,_Bool,const char* +Function,-,furi_record_init,void, +Function,+,furi_record_open,void*,const char* +Function,+,furi_run,void, +Function,+,furi_semaphore_acquire,FuriStatus,"FuriSemaphore*, uint32_t" +Function,+,furi_semaphore_alloc,FuriSemaphore*,"uint32_t, uint32_t" +Function,+,furi_semaphore_free,void,FuriSemaphore* +Function,+,furi_semaphore_get_count,uint32_t,FuriSemaphore* +Function,+,furi_semaphore_release,FuriStatus,FuriSemaphore* +Function,+,furi_stream_buffer_alloc,FuriStreamBuffer*,"size_t, size_t" +Function,+,furi_stream_buffer_bytes_available,size_t,FuriStreamBuffer* +Function,+,furi_stream_buffer_free,void,FuriStreamBuffer* +Function,+,furi_stream_buffer_is_empty,_Bool,FuriStreamBuffer* +Function,+,furi_stream_buffer_is_full,_Bool,FuriStreamBuffer* +Function,+,furi_stream_buffer_receive,size_t,"FuriStreamBuffer*, void*, size_t, uint32_t" +Function,+,furi_stream_buffer_reset,FuriStatus,FuriStreamBuffer* +Function,+,furi_stream_buffer_send,size_t,"FuriStreamBuffer*, const void*, size_t, uint32_t" +Function,+,furi_stream_buffer_spaces_available,size_t,FuriStreamBuffer* +Function,+,furi_stream_set_trigger_level,_Bool,"FuriStreamBuffer*, size_t" +Function,+,furi_string_alloc,FuriString*, +Function,+,furi_string_alloc_move,FuriString*,FuriString* +Function,+,furi_string_alloc_printf,FuriString*,"const char[], ..." +Function,+,furi_string_alloc_set,FuriString*,const FuriString* +Function,+,furi_string_alloc_set_str,FuriString*,const char[] +Function,+,furi_string_alloc_vprintf,FuriString*,"const char[], va_list" +Function,+,furi_string_cat,void,"FuriString*, const FuriString*" +Function,+,furi_string_cat_printf,int,"FuriString*, const char[], ..." +Function,+,furi_string_cat_str,void,"FuriString*, const char[]" +Function,+,furi_string_cat_vprintf,int,"FuriString*, const char[], va_list" +Function,+,furi_string_cmp,int,"const FuriString*, const FuriString*" +Function,+,furi_string_cmp_str,int,"const FuriString*, const char[]" +Function,+,furi_string_cmpi,int,"const FuriString*, const FuriString*" +Function,+,furi_string_cmpi_str,int,"const FuriString*, const char[]" +Function,+,furi_string_empty,_Bool,const FuriString* +Function,+,furi_string_end_with,_Bool,"const FuriString*, const FuriString*" +Function,+,furi_string_end_with_str,_Bool,"const FuriString*, const char[]" +Function,+,furi_string_equal,_Bool,"const FuriString*, const FuriString*" +Function,+,furi_string_equal_str,_Bool,"const FuriString*, const char[]" +Function,+,furi_string_free,void,FuriString* +Function,+,furi_string_get_char,char,"const FuriString*, size_t" +Function,+,furi_string_get_cstr,const char*,const FuriString* +Function,+,furi_string_hash,size_t,const FuriString* +Function,+,furi_string_left,void,"FuriString*, size_t" +Function,+,furi_string_mid,void,"FuriString*, size_t, size_t" +Function,+,furi_string_move,void,"FuriString*, FuriString*" +Function,+,furi_string_printf,int,"FuriString*, const char[], ..." +Function,+,furi_string_push_back,void,"FuriString*, char" +Function,+,furi_string_replace,size_t,"FuriString*, FuriString*, FuriString*, size_t" +Function,+,furi_string_replace_all,void,"FuriString*, const FuriString*, const FuriString*" +Function,+,furi_string_replace_all_str,void,"FuriString*, const char[], const char[]" +Function,+,furi_string_replace_at,void,"FuriString*, size_t, size_t, const char[]" +Function,+,furi_string_replace_str,size_t,"FuriString*, const char[], const char[], size_t" +Function,+,furi_string_reserve,void,"FuriString*, size_t" +Function,+,furi_string_reset,void,FuriString* +Function,+,furi_string_right,void,"FuriString*, size_t" +Function,+,furi_string_search,size_t,"const FuriString*, const FuriString*, size_t" +Function,+,furi_string_search_char,size_t,"const FuriString*, char, size_t" +Function,+,furi_string_search_rchar,size_t,"const FuriString*, char, size_t" +Function,+,furi_string_search_str,size_t,"const FuriString*, const char[], size_t" +Function,+,furi_string_set,void,"FuriString*, FuriString*" +Function,+,furi_string_set_char,void,"FuriString*, size_t, const char" +Function,+,furi_string_set_n,void,"FuriString*, const FuriString*, size_t, size_t" +Function,+,furi_string_set_str,void,"FuriString*, const char[]" +Function,+,furi_string_set_strn,void,"FuriString*, const char[], size_t" +Function,+,furi_string_size,size_t,const FuriString* +Function,+,furi_string_start_with,_Bool,"const FuriString*, const FuriString*" +Function,+,furi_string_start_with_str,_Bool,"const FuriString*, const char[]" +Function,+,furi_string_swap,void,"FuriString*, FuriString*" +Function,+,furi_string_trim,void,"FuriString*, const char[]" +Function,+,furi_string_utf8_decode,void,"char, FuriStringUTF8State*, FuriStringUnicodeValue*" +Function,+,furi_string_utf8_length,size_t,FuriString* +Function,+,furi_string_utf8_push,void,"FuriString*, FuriStringUnicodeValue" +Function,+,furi_string_vprintf,int,"FuriString*, const char[], va_list" +Function,+,furi_thread_alloc,FuriThread*, +Function,+,furi_thread_alloc_ex,FuriThread*,"const char*, uint32_t, FuriThreadCallback, void*" +Function,+,furi_thread_catch,void, +Function,-,furi_thread_disable_heap_trace,void,FuriThread* +Function,+,furi_thread_enable_heap_trace,void,FuriThread* +Function,+,furi_thread_enumerate,uint32_t,"FuriThreadId*, uint32_t" +Function,+,furi_thread_flags_clear,uint32_t,uint32_t +Function,+,furi_thread_flags_get,uint32_t, +Function,+,furi_thread_flags_set,uint32_t,"FuriThreadId, uint32_t" +Function,+,furi_thread_flags_wait,uint32_t,"uint32_t, uint32_t, uint32_t" +Function,+,furi_thread_free,void,FuriThread* +Function,+,furi_thread_get_current,FuriThread*, +Function,+,furi_thread_get_current_id,FuriThreadId, +Function,+,furi_thread_get_heap_size,size_t,FuriThread* +Function,+,furi_thread_get_id,FuriThreadId,FuriThread* +Function,+,furi_thread_get_name,const char*,FuriThreadId +Function,+,furi_thread_get_return_code,int32_t,FuriThread* +Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId +Function,+,furi_thread_get_state,FuriThreadState,FuriThread* +Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, +Function,+,furi_thread_is_suspended,_Bool,FuriThreadId +Function,+,furi_thread_join,_Bool,FuriThread* +Function,+,furi_thread_mark_as_service,void,FuriThread* +Function,+,furi_thread_resume,void,FuriThreadId +Function,+,furi_thread_set_callback,void,"FuriThread*, FuriThreadCallback" +Function,+,furi_thread_set_context,void,"FuriThread*, void*" +Function,+,furi_thread_set_name,void,"FuriThread*, const char*" +Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" +Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" +Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" +Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" +Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback +Function,+,furi_thread_start,void,FuriThread* +Function,+,furi_thread_stdout_flush,int32_t, +Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" +Function,+,furi_thread_suspend,void,FuriThreadId +Function,+,furi_thread_yield,void, +Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" +Function,+,furi_timer_free,void,FuriTimer* +Function,+,furi_timer_is_running,uint32_t,FuriTimer* +Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" +Function,+,furi_timer_stop,FuriStatus,FuriTimer* +Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" +Function,-,fwrite_unlocked,size_t,"const void*, size_t, size_t, FILE*" +Function,-,gap_get_state,GapState, +Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*" +Function,-,gap_start_advertising,void, +Function,-,gap_stop_advertising,void, +Function,-,gap_thread_stop,void, +Function,-,getc,int,FILE* +Function,-,getc_unlocked,int,FILE* +Function,-,getchar,int, +Function,-,getchar_unlocked,int, +Function,-,getenv,char*,const char* +Function,-,gets,char*,char* +Function,-,getsubopt,int,"char**, char**, char**" +Function,-,getw,int,FILE* +Function,-,gmtime,tm*,const time_t* +Function,-,gmtime_r,tm*,"const time_t*, tm*" +Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" +Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer" +Function,+,gui_direct_draw_acquire,Canvas*,Gui* +Function,+,gui_direct_draw_release,void,Gui* +Function,+,gui_get_framebuffer_size,size_t,Gui* +Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" +Function,+,gui_remove_view_port,void,"Gui*, ViewPort*" +Function,+,gui_set_lockdown,void,"Gui*, _Bool" +Function,-,gui_view_port_send_to_back,void,"Gui*, ViewPort*" +Function,+,gui_view_port_send_to_front,void,"Gui*, ViewPort*" +Function,+,hal_sd_detect,_Bool, +Function,+,hal_sd_detect_init,void, +Function,+,hal_sd_detect_set_low,void, +Function,+,hmac_sha256_finish,void,"const hmac_sha256_context*, const uint8_t*, uint8_t*" +Function,+,hmac_sha256_init,void,"hmac_sha256_context*, const uint8_t*" +Function,+,hmac_sha256_update,void,"const hmac_sha256_context*, const uint8_t*, unsigned" +Function,+,icon_animation_alloc,IconAnimation*,const Icon* +Function,+,icon_animation_free,void,IconAnimation* +Function,+,icon_animation_get_height,uint8_t,IconAnimation* +Function,+,icon_animation_get_width,uint8_t,IconAnimation* +Function,+,icon_animation_is_last_frame,_Bool,IconAnimation* +Function,+,icon_animation_set_update_callback,void,"IconAnimation*, IconAnimationCallback, void*" +Function,+,icon_animation_start,void,IconAnimation* +Function,+,icon_animation_stop,void,IconAnimation* +Function,+,icon_get_data,const uint8_t*,const Icon* +Function,+,icon_get_height,uint8_t,const Icon* +Function,+,icon_get_width,uint8_t,const Icon* +Function,-,index,char*,"const char*, int" +Function,+,init_mutex,_Bool,"ValueMutex*, void*, size_t" +Function,-,initstate,char*,"unsigned, char*, size_t" +Function,+,input_get_key_name,const char*,InputKey +Function,+,input_get_type_name,const char*,InputType +Function,-,iprintf,int,"const char*, ..." +Function,-,isalnum,int,int +Function,-,isalnum_l,int,"int, locale_t" +Function,-,isalpha,int,int +Function,-,isalpha_l,int,"int, locale_t" +Function,-,isascii,int,int +Function,-,isascii_l,int,"int, locale_t" +Function,-,isblank,int,int +Function,-,isblank_l,int,"int, locale_t" +Function,-,iscanf,int,"const char*, ..." +Function,-,iscntrl,int,int +Function,-,iscntrl_l,int,"int, locale_t" +Function,-,isdigit,int,int +Function,-,isdigit_l,int,"int, locale_t" +Function,-,isgraph,int,int +Function,-,isgraph_l,int,"int, locale_t" +Function,-,islower,int,int +Function,-,islower_l,int,"int, locale_t" +Function,-,isprint,int,int +Function,-,isprint_l,int,"int, locale_t" +Function,-,ispunct,int,int +Function,-,ispunct_l,int,"int, locale_t" +Function,-,isspace,int,int +Function,-,isspace_l,int,"int, locale_t" +Function,-,isupper,int,int +Function,-,isupper_l,int,"int, locale_t" +Function,-,isxdigit,int,int +Function,-,isxdigit_l,int,"int, locale_t" +Function,-,itoa,char*,"int, char*, int" +Function,-,jrand48,long,unsigned short[3] +Function,-,l64a,char*,long +Function,-,labs,long,long +Function,-,lcong48,void,unsigned short[7] +Function,-,ldiv,ldiv_t,"long, long" +Function,-,llabs,long long,long long +Function,-,lldiv,lldiv_t,"long long, long long" +Function,+,loader_get_pubsub,FuriPubSub*,Loader* +Function,+,loader_is_locked,_Bool,Loader* +Function,+,loader_lock,_Bool,Loader* +Function,+,loader_show_menu,void, +Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" +Function,+,loader_unlock,void,Loader* +Function,+,loader_update_menu,void, +Function,+,loading_alloc,Loading*, +Function,+,loading_free,void,Loading* +Function,+,loading_get_view,View*,Loading* +Function,+,locale_celsius_to_fahrenheit,float,float +Function,+,locale_fahrenheit_to_celsius,float,float +Function,+,locale_format_date,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleDateFormat, const char*" +Function,+,locale_format_time,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleTimeFormat, const _Bool" +Function,+,locale_get_date_format,LocaleDateFormat, +Function,+,locale_get_measurement_unit,LocaleMeasurementUnits, +Function,+,locale_get_time_format,LocaleTimeFormat, +Function,+,locale_set_date_format,void,LocaleDateFormat +Function,+,locale_set_measurement_unit,void,LocaleMeasurementUnits +Function,+,locale_set_time_format,void,LocaleTimeFormat +Function,-,localtime,tm*,const time_t* +Function,-,localtime_r,tm*,"const time_t*, tm*" +Function,-,lrand48,long, +Function,+,malloc,void*,size_t +Function,+,manchester_advance,_Bool,"ManchesterState, ManchesterEvent, ManchesterState*, _Bool*" +Function,+,manchester_encoder_advance,_Bool,"ManchesterEncoderState*, const _Bool, ManchesterEncoderResult*" +Function,+,manchester_encoder_finish,ManchesterEncoderResult,ManchesterEncoderState* +Function,+,manchester_encoder_reset,void,ManchesterEncoderState* +Function,-,mbedtls_des3_crypt_cbc,int,"mbedtls_des3_context*, int, size_t, unsigned char[8], const unsigned char*, unsigned char*" +Function,-,mbedtls_des3_crypt_ecb,int,"mbedtls_des3_context*, const unsigned char[8], unsigned char[8]" +Function,-,mbedtls_des3_free,void,mbedtls_des3_context* +Function,-,mbedtls_des3_init,void,mbedtls_des3_context* +Function,-,mbedtls_des3_set2key_dec,int,"mbedtls_des3_context*, const unsigned char[8 * 2]" +Function,-,mbedtls_des3_set2key_enc,int,"mbedtls_des3_context*, const unsigned char[8 * 2]" +Function,-,mbedtls_des3_set3key_dec,int,"mbedtls_des3_context*, const unsigned char[8 * 3]" +Function,-,mbedtls_des3_set3key_enc,int,"mbedtls_des3_context*, const unsigned char[8 * 3]" +Function,-,mbedtls_des_crypt_cbc,int,"mbedtls_des_context*, int, size_t, unsigned char[8], const unsigned char*, unsigned char*" +Function,-,mbedtls_des_crypt_ecb,int,"mbedtls_des_context*, const unsigned char[8], unsigned char[8]" +Function,-,mbedtls_des_free,void,mbedtls_des_context* +Function,-,mbedtls_des_init,void,mbedtls_des_context* +Function,-,mbedtls_des_key_check_key_parity,int,const unsigned char[8] +Function,-,mbedtls_des_key_check_weak,int,const unsigned char[8] +Function,-,mbedtls_des_key_set_parity,void,unsigned char[8] +Function,-,mbedtls_des_self_test,int,int +Function,-,mbedtls_des_setkey,void,"uint32_t[32], const unsigned char[8]" +Function,-,mbedtls_des_setkey_dec,int,"mbedtls_des_context*, const unsigned char[8]" +Function,-,mbedtls_des_setkey_enc,int,"mbedtls_des_context*, const unsigned char[8]" +Function,-,mbedtls_internal_sha1_process,int,"mbedtls_sha1_context*, const unsigned char[64]" +Function,-,mbedtls_platform_gmtime_r,tm*,"const mbedtls_time_t*, tm*" +Function,-,mbedtls_platform_zeroize,void,"void*, size_t" +Function,-,mbedtls_sha1,int,"const unsigned char*, size_t, unsigned char[20]" +Function,-,mbedtls_sha1_clone,void,"mbedtls_sha1_context*, const mbedtls_sha1_context*" +Function,-,mbedtls_sha1_finish,int,"mbedtls_sha1_context*, unsigned char[20]" +Function,-,mbedtls_sha1_free,void,mbedtls_sha1_context* +Function,-,mbedtls_sha1_init,void,mbedtls_sha1_context* +Function,-,mbedtls_sha1_self_test,int,int +Function,-,mbedtls_sha1_starts,int,mbedtls_sha1_context* +Function,-,mbedtls_sha1_update,int,"mbedtls_sha1_context*, const unsigned char*, size_t" +Function,-,mblen,int,"const char*, size_t" +Function,-,mbstowcs,size_t,"wchar_t*, const char*, size_t" +Function,-,mbtowc,int,"wchar_t*, const char*, size_t" +Function,+,md5,void,"const unsigned char*, size_t, unsigned char[16]" +Function,+,md5_finish,void,"md5_context*, unsigned char[16]" +Function,+,md5_process,void,"md5_context*, const unsigned char[64]" +Function,+,md5_starts,void,md5_context* +Function,+,md5_update,void,"md5_context*, const unsigned char*, size_t" +Function,-,memccpy,void*,"void*, const void*, int, size_t" +Function,+,memchr,void*,"const void*, int, size_t" +Function,+,memcmp,int,"const void*, const void*, size_t" +Function,+,memcpy,void*,"void*, const void*, size_t" +Function,-,memmem,void*,"const void*, size_t, const void*, size_t" +Function,-,memmgr_alloc_from_pool,void*,size_t +Function,+,memmgr_get_free_heap,size_t, +Function,+,memmgr_get_minimum_free_heap,size_t, +Function,+,memmgr_get_total_heap,size_t, +Function,+,memmgr_heap_disable_thread_trace,void,FuriThreadId +Function,+,memmgr_heap_enable_thread_trace,void,FuriThreadId +Function,+,memmgr_heap_get_max_free_block,size_t, +Function,+,memmgr_heap_get_thread_memory,size_t,FuriThreadId +Function,+,memmgr_heap_printf_free_blocks,void, +Function,-,memmgr_pool_get_free,size_t, +Function,-,memmgr_pool_get_max_block,size_t, +Function,+,memmove,void*,"void*, const void*, size_t" +Function,-,mempcpy,void*,"void*, const void*, size_t" +Function,-,memrchr,void*,"const void*, int, size_t" +Function,+,memset,void*,"void*, int, size_t" +Function,+,menu_add_item,void,"Menu*, const char*, const Icon*, uint32_t, MenuItemCallback, void*" +Function,+,menu_alloc,Menu*, +Function,+,menu_free,void,Menu* +Function,+,menu_get_view,View*,Menu* +Function,+,menu_reset,void,Menu* +Function,+,menu_set_selected_item,void,"Menu*, uint32_t" +Function,-,mkdtemp,char*,char* +Function,-,mkostemp,int,"char*, int" +Function,-,mkostemps,int,"char*, int, int" +Function,-,mkstemp,int,char* +Function,-,mkstemps,int,"char*, int" +Function,-,mktemp,char*,char* +Function,-,mktime,time_t,tm* +Function,-,mrand48,long, +Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" +Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" +Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" +Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*" +Function,-,nrand48,long,unsigned short[3] +Function,-,on_exit,int,"void (*)(int, void*), void*" +Function,-,open_memstream,FILE*,"char**, size_t*" +Function,+,path_append,void,"FuriString*, const char*" +Function,+,path_concat,void,"const char*, const char*, FuriString*" +Function,+,path_contains_only_ascii,_Bool,const char* +Function,+,path_extract_basename,void,"const char*, FuriString*" +Function,+,path_extract_dirname,void,"const char*, FuriString*" +Function,+,path_extract_extension,void,"FuriString*, char*, size_t" +Function,+,path_extract_filename,void,"FuriString*, FuriString*, _Bool" +Function,+,path_extract_filename_no_ext,void,"const char*, FuriString*" +Function,-,pcTaskGetName,char*,TaskHandle_t +Function,-,pcTimerGetName,const char*,TimerHandle_t +Function,-,pclose,int,FILE* +Function,-,perror,void,const char* +Function,-,popen,FILE*,"const char*, const char*" +Function,+,popup_alloc,Popup*, +Function,+,popup_disable_timeout,void,Popup* +Function,+,popup_enable_timeout,void,Popup* +Function,+,popup_free,void,Popup* +Function,+,popup_get_view,View*,Popup* +Function,+,popup_reset,void,Popup* +Function,+,popup_set_callback,void,"Popup*, PopupCallback" +Function,+,popup_set_context,void,"Popup*, void*" +Function,+,popup_set_header,void,"Popup*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,popup_set_icon,void,"Popup*, uint8_t, uint8_t, const Icon*" +Function,+,popup_set_text,void,"Popup*, const char*, uint8_t, uint8_t, Align, Align" +Function,+,popup_set_timeout,void,"Popup*, uint32_t" +Function,-,posix_memalign,int,"void**, size_t, size_t" +Function,+,power_enable_low_battery_level_notification,void,"Power*, _Bool" +Function,+,power_get_info,void,"Power*, PowerInfo*" +Function,+,power_get_pubsub,FuriPubSub*,Power* +Function,+,power_is_battery_healthy,_Bool,Power* +Function,+,power_off,void,Power* +Function,+,power_reboot,void,PowerBootMode +Function,-,printf,int,"const char*, ..." +Function,+,property_value_out,void,"PropertyValueContext*, const char*, unsigned int, ..." +Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" +Function,+,protocol_dict_decoders_feed,ProtocolId,"ProtocolDict*, _Bool, uint32_t" +Function,+,protocol_dict_decoders_feed_by_feature,ProtocolId,"ProtocolDict*, uint32_t, _Bool, uint32_t" +Function,+,protocol_dict_decoders_feed_by_id,ProtocolId,"ProtocolDict*, size_t, _Bool, uint32_t" +Function,+,protocol_dict_decoders_start,void,ProtocolDict* +Function,+,protocol_dict_encoder_start,_Bool,"ProtocolDict*, size_t" +Function,+,protocol_dict_encoder_yield,LevelDuration,"ProtocolDict*, size_t" +Function,+,protocol_dict_free,void,ProtocolDict* +Function,+,protocol_dict_get_data,void,"ProtocolDict*, size_t, uint8_t*, size_t" +Function,+,protocol_dict_get_data_size,size_t,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_features,uint32_t,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_manufacturer,const char*,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_max_data_size,size_t,ProtocolDict* +Function,+,protocol_dict_get_name,const char*,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_protocol_by_name,ProtocolId,"ProtocolDict*, const char*" +Function,+,protocol_dict_get_validate_count,uint32_t,"ProtocolDict*, size_t" +Function,+,protocol_dict_get_write_data,_Bool,"ProtocolDict*, size_t, void*" +Function,+,protocol_dict_render_brief_data,void,"ProtocolDict*, FuriString*, size_t" +Function,+,protocol_dict_render_data,void,"ProtocolDict*, FuriString*, size_t" +Function,+,protocol_dict_set_data,void,"ProtocolDict*, size_t, const uint8_t*, size_t" +Function,-,pselect,int,"int, fd_set*, fd_set*, fd_set*, const timespec*, const sigset_t*" +Function,-,putc,int,"int, FILE*" +Function,-,putc_unlocked,int,"int, FILE*" +Function,-,putchar,int,int +Function,-,putchar_unlocked,int,int +Function,-,putenv,int,char* +Function,-,puts,int,const char* +Function,-,putw,int,"int, FILE*" +Function,-,pvPortCalloc,void*,"size_t, size_t" +Function,-,pvPortMalloc,void*,size_t +Function,-,pvTaskGetThreadLocalStoragePointer,void*,"TaskHandle_t, BaseType_t" +Function,-,pvTaskIncrementMutexHeldCount,TaskHandle_t, +Function,-,pvTimerGetTimerID,void*,const TimerHandle_t +Function,-,pxPortInitialiseStack,StackType_t*,"StackType_t*, TaskFunction_t, void*" +Function,-,qsort,void,"void*, size_t, size_t, __compar_fn_t" +Function,-,qsort_r,void,"void*, size_t, size_t, int (*)(const void*, const void*, void*), void*" +Function,-,quick_exit,void,int +Function,+,rand,int, +Function,-,rand_r,int,unsigned* +Function,+,random,long, +Function,-,rawmemchr,void*,"const void*, int" +Function,-,read_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" +Function,+,realloc,void*,"void*, size_t" +Function,-,reallocarray,void*,"void*, size_t, size_t" +Function,-,reallocf,void*,"void*, size_t" +Function,-,realpath,char*,"const char*, char*" +Function,+,release_mutex,_Bool,"ValueMutex*, const void*" +Function,-,remove,int,const char* +Function,-,rename,int,"const char*, const char*" +Function,-,renameat,int,"int, const char*, int, const char*" +Function,-,rewind,void,FILE* +Function,-,rindex,char*,"const char*, int" +Function,+,rpc_session_close,void,RpcSession* +Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" +Function,+,rpc_session_get_available_size,size_t,RpcSession* +Function,+,rpc_session_open,RpcSession*,Rpc* +Function,+,rpc_session_set_buffer_is_empty_callback,void,"RpcSession*, RpcBufferIsEmptyCallback" +Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCallback" +Function,+,rpc_session_set_context,void,"RpcSession*, void*" +Function,+,rpc_session_set_send_bytes_callback,void,"RpcSession*, RpcSendBytesCallback" +Function,+,rpc_session_set_terminated_callback,void,"RpcSession*, RpcSessionTerminatedCallback" +Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, RpcAppSystemEvent, _Bool" +Function,+,rpc_system_app_error_reset,void,RpcAppSystem* +Function,+,rpc_system_app_exchange_data,void,"RpcAppSystem*, const uint8_t*, size_t" +Function,+,rpc_system_app_get_data,const char*,RpcAppSystem* +Function,+,rpc_system_app_send_exited,void,RpcAppSystem* +Function,+,rpc_system_app_send_started,void,RpcAppSystem* +Function,+,rpc_system_app_set_callback,void,"RpcAppSystem*, RpcAppSystemCallback, void*" +Function,+,rpc_system_app_set_data_exchange_callback,void,"RpcAppSystem*, RpcAppSystemDataExchangeCallback, void*" +Function,+,rpc_system_app_set_error_code,void,"RpcAppSystem*, uint32_t" +Function,+,rpc_system_app_set_error_text,void,"RpcAppSystem*, const char*" +Function,-,rpmatch,int,const char* +Function,+,saved_struct_get_payload_size,_Bool,"const char*, uint8_t, uint8_t, size_t*" +Function,+,saved_struct_load,_Bool,"const char*, void*, size_t, uint8_t, uint8_t" +Function,+,saved_struct_save,_Bool,"const char*, void*, size_t, uint8_t, uint8_t" +Function,-,scanf,int,"const char*, ..." +Function,+,scene_manager_alloc,SceneManager*,"const SceneManagerHandlers*, void*" +Function,+,scene_manager_free,void,SceneManager* +Function,+,scene_manager_get_scene_state,uint32_t,"SceneManager*, uint32_t" +Function,+,scene_manager_handle_back_event,_Bool,SceneManager* +Function,+,scene_manager_handle_custom_event,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_handle_tick_event,void,SceneManager* +Function,+,scene_manager_has_previous_scene,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_next_scene,void,"SceneManager*, uint32_t" +Function,+,scene_manager_previous_scene,_Bool,SceneManager* +Function,+,scene_manager_search_and_switch_to_another_scene,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_search_and_switch_to_previous_scene,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_search_and_switch_to_previous_scene_one_of,_Bool,"SceneManager*, const uint32_t*, size_t" +Function,+,scene_manager_set_scene_state,void,"SceneManager*, uint32_t, uint32_t" +Function,+,scene_manager_stop,void,SceneManager* +Function,+,sd_api_get_fs_type_text,const char*,SDFsType +Function,-,secure_getenv,char*,const char* +Function,-,seed48,unsigned short*,unsigned short[3] +Function,-,select,int,"int, fd_set*, fd_set*, fd_set*, timeval*" +Function,-,serial_svc_is_started,_Bool, +Function,-,serial_svc_notify_buffer_is_empty,void, +Function,-,serial_svc_set_callbacks,void,"uint16_t, SerialServiceEventCallback, void*" +Function,-,serial_svc_set_rpc_status,void,SerialServiceRpcStatus +Function,-,serial_svc_start,void, +Function,-,serial_svc_stop,void, +Function,-,serial_svc_update_tx,_Bool,"uint8_t*, uint16_t" +Function,+,set_random_name,void,"char*, uint8_t" +Function,-,setbuf,void,"FILE*, char*" +Function,-,setbuffer,void,"FILE*, char*, int" +Function,-,setenv,int,"const char*, const char*, int" +Function,-,setkey,void,const char* +Function,-,setlinebuf,int,FILE* +Function,-,setstate,char*,char* +Function,-,setvbuf,int,"FILE*, char*, int, size_t" +Function,+,sha256,void,"const unsigned char*, unsigned int, unsigned char[32]" +Function,+,sha256_finish,void,"sha256_context*, unsigned char[32]" +Function,+,sha256_process,void,sha256_context* +Function,+,sha256_start,void,sha256_context* +Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" +Function,-,siprintf,int,"char*, const char*, ..." +Function,-,siscanf,int,"const char*, const char*, ..." +Function,-,sniprintf,int,"char*, size_t, const char*, ..." +Function,+,snprintf,int,"char*, size_t, const char*, ..." +Function,-,sprintf,int,"char*, const char*, ..." +Function,+,srand,void,unsigned +Function,-,srand48,void,long +Function,-,srandom,void,unsigned +Function,+,sscanf,int,"const char*, const char*, ..." +Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" +Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_mkdir,FS_Error,"Storage*, const char*" +Function,+,storage_common_remove,FS_Error,"Storage*, const char*" +Function,+,storage_common_rename,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_stat,FS_Error,"Storage*, const char*, FileInfo*" +Function,+,storage_common_timestamp,FS_Error,"Storage*, const char*, uint32_t*" +Function,+,storage_dir_close,_Bool,File* +Function,+,storage_dir_open,_Bool,"File*, const char*" +Function,+,storage_dir_read,_Bool,"File*, FileInfo*, char*, uint16_t" +Function,-,storage_dir_rewind,_Bool,File* +Function,+,storage_error_get_desc,const char*,FS_Error +Function,+,storage_file_alloc,File*,Storage* +Function,+,storage_file_close,_Bool,File* +Function,+,storage_file_eof,_Bool,File* +Function,+,storage_file_exists,_Bool,"Storage*, const char*" +Function,+,storage_file_free,void,File* +Function,+,storage_file_get_error,FS_Error,File* +Function,+,storage_file_get_error_desc,const char*,File* +Function,-,storage_file_get_internal_error,int32_t,File* +Function,+,storage_file_is_dir,_Bool,File* +Function,+,storage_file_is_open,_Bool,File* +Function,+,storage_file_open,_Bool,"File*, const char*, FS_AccessMode, FS_OpenMode" +Function,+,storage_file_read,uint16_t,"File*, void*, uint16_t" +Function,+,storage_file_seek,_Bool,"File*, uint32_t, _Bool" +Function,+,storage_file_size,uint64_t,File* +Function,-,storage_file_sync,_Bool,File* +Function,+,storage_file_tell,uint64_t,File* +Function,+,storage_file_truncate,_Bool,File* +Function,+,storage_file_write,uint16_t,"File*, const void*, uint16_t" +Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" +Function,+,storage_get_pubsub,FuriPubSub*,Storage* +Function,+,storage_int_backup,FS_Error,"Storage*, const char*" +Function,+,storage_int_restore,FS_Error,"Storage*, const char*, Storage_name_converter" +Function,+,storage_sd_format,FS_Error,Storage* +Function,+,storage_sd_info,FS_Error,"Storage*, SDInfo*" +Function,+,storage_sd_status,FS_Error,Storage* +Function,+,storage_sd_unmount,FS_Error,Storage* +Function,+,storage_simply_mkdir,_Bool,"Storage*, const char*" +Function,+,storage_simply_remove,_Bool,"Storage*, const char*" +Function,+,storage_simply_remove_recursive,_Bool,"Storage*, const char*" +Function,-,stpcpy,char*,"char*, const char*" +Function,-,stpncpy,char*,"char*, const char*, size_t" +Function,-,strcasecmp,int,"const char*, const char*" +Function,-,strcasecmp_l,int,"const char*, const char*, locale_t" +Function,+,strcasestr,char*,"const char*, const char*" +Function,-,strcat,char*,"char*, const char*" +Function,+,strchr,char*,"const char*, int" +Function,-,strchrnul,char*,"const char*, int" +Function,+,strcmp,int,"const char*, const char*" +Function,-,strcoll,int,"const char*, const char*" +Function,-,strcoll_l,int,"const char*, const char*, locale_t" +Function,+,strcpy,char*,"char*, const char*" +Function,+,strcspn,size_t,"const char*, const char*" +Function,+,strdup,char*,const char* +Function,+,stream_clean,void,Stream* +Function,+,stream_copy,size_t,"Stream*, Stream*, size_t" +Function,+,stream_copy_full,size_t,"Stream*, Stream*" +Function,+,stream_delete,_Bool,"Stream*, size_t" +Function,+,stream_delete_and_insert,_Bool,"Stream*, size_t, StreamWriteCB, const void*" +Function,+,stream_delete_and_insert_char,_Bool,"Stream*, size_t, char" +Function,+,stream_delete_and_insert_cstring,_Bool,"Stream*, size_t, const char*" +Function,+,stream_delete_and_insert_format,_Bool,"Stream*, size_t, const char*, ..." +Function,+,stream_delete_and_insert_string,_Bool,"Stream*, size_t, FuriString*" +Function,+,stream_delete_and_insert_vaformat,_Bool,"Stream*, size_t, const char*, va_list" +Function,+,stream_dump_data,void,Stream* +Function,+,stream_eof,_Bool,Stream* +Function,+,stream_free,void,Stream* +Function,+,stream_insert,_Bool,"Stream*, const uint8_t*, size_t" +Function,+,stream_insert_char,_Bool,"Stream*, char" +Function,+,stream_insert_cstring,_Bool,"Stream*, const char*" +Function,+,stream_insert_format,_Bool,"Stream*, const char*, ..." +Function,+,stream_insert_string,_Bool,"Stream*, FuriString*" +Function,+,stream_insert_vaformat,_Bool,"Stream*, const char*, va_list" +Function,+,stream_load_from_file,size_t,"Stream*, Storage*, const char*" +Function,+,stream_read,size_t,"Stream*, uint8_t*, size_t" +Function,+,stream_read_line,_Bool,"Stream*, FuriString*" +Function,+,stream_rewind,_Bool,Stream* +Function,+,stream_save_to_file,size_t,"Stream*, Storage*, const char*, FS_OpenMode" +Function,+,stream_seek,_Bool,"Stream*, int32_t, StreamOffset" +Function,+,stream_seek_to_char,_Bool,"Stream*, char, StreamDirection" +Function,+,stream_size,size_t,Stream* +Function,+,stream_split,_Bool,"Stream*, Stream*, Stream*" +Function,+,stream_tell,size_t,Stream* +Function,+,stream_write,size_t,"Stream*, const uint8_t*, size_t" +Function,+,stream_write_char,size_t,"Stream*, char" +Function,+,stream_write_cstring,size_t,"Stream*, const char*" +Function,+,stream_write_format,size_t,"Stream*, const char*, ..." +Function,+,stream_write_string,size_t,"Stream*, FuriString*" +Function,+,stream_write_vaformat,size_t,"Stream*, const char*, va_list" +Function,-,strerror,char*,int +Function,-,strerror_l,char*,"int, locale_t" +Function,-,strerror_r,char*,"int, char*, size_t" +Function,-,strftime,size_t,"char*, size_t, const char*, const tm*" +Function,-,strftime_l,size_t,"char*, size_t, const char*, const tm*, locale_t" +Function,+,string_stream_alloc,Stream*, +Function,-,strlcat,size_t,"char*, const char*, size_t" +Function,+,strlcpy,size_t,"char*, const char*, size_t" +Function,+,strlen,size_t,const char* +Function,-,strlwr,char*,char* +Function,+,strncasecmp,int,"const char*, const char*, size_t" +Function,-,strncasecmp_l,int,"const char*, const char*, size_t, locale_t" +Function,-,strncat,char*,"char*, const char*, size_t" +Function,+,strncmp,int,"const char*, const char*, size_t" +Function,+,strncpy,char*,"char*, const char*, size_t" +Function,-,strndup,char*,"const char*, size_t" +Function,-,strnlen,size_t,"const char*, size_t" +Function,-,strnstr,char*,"const char*, const char*, size_t" +Function,-,strpbrk,char*,"const char*, const char*" +Function,-,strptime,char*,"const char*, const char*, tm*" +Function,-,strptime_l,char*,"const char*, const char*, tm*, locale_t" +Function,+,strrchr,char*,"const char*, int" +Function,-,strsep,char*,"char**, const char*" +Function,-,strsignal,char*,int +Function,+,strspn,size_t,"const char*, const char*" +Function,+,strstr,char*,"const char*, const char*" +Function,-,strtod,double,"const char*, char**" +Function,-,strtod_l,double,"const char*, char**, locale_t" +Function,+,strtof,float,"const char*, char**" +Function,-,strtof_l,float,"const char*, char**, locale_t" +Function,-,strtok,char*,"char*, const char*" +Function,-,strtok_r,char*,"char*, const char*, char**" +Function,+,strtol,long,"const char*, char**, int" +Function,-,strtol_l,long,"const char*, char**, int, locale_t" +Function,-,strtold,long double,"const char*, char**" +Function,-,strtold_l,long double,"const char*, char**, locale_t" +Function,-,strtoll,long long,"const char*, char**, int" +Function,-,strtoll_l,long long,"const char*, char**, int, locale_t" +Function,+,strtoul,unsigned long,"const char*, char**, int" +Function,-,strtoul_l,unsigned long,"const char*, char**, int, locale_t" +Function,+,strtoull,unsigned long long,"const char*, char**, int" +Function,-,strtoull_l,unsigned long long,"const char*, char**, int, locale_t" +Function,-,strupr,char*,char* +Function,-,strverscmp,int,"const char*, const char*" +Function,-,strxfrm,size_t,"char*, const char*, size_t" +Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t" +Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*" +Function,+,submenu_alloc,Submenu*, +Function,+,submenu_free,void,Submenu* +Function,+,submenu_get_view,View*,Submenu* +Function,+,submenu_reset,void,Submenu* +Function,+,submenu_set_header,void,"Submenu*, const char*" +Function,+,submenu_set_selected_item,void,"Submenu*, uint32_t" +Function,-,system,int,const char* +Function,+,tar_archive_add_dir,_Bool,"TarArchive*, const char*, const char*" +Function,+,tar_archive_add_file,_Bool,"TarArchive*, const char*, const char*, const int32_t" +Function,+,tar_archive_alloc,TarArchive*,Storage* +Function,+,tar_archive_dir_add_element,_Bool,"TarArchive*, const char*" +Function,+,tar_archive_file_add_data_block,_Bool,"TarArchive*, const uint8_t*, const int32_t" +Function,+,tar_archive_file_add_header,_Bool,"TarArchive*, const char*, const int32_t" +Function,+,tar_archive_file_finalize,_Bool,TarArchive* +Function,+,tar_archive_finalize,_Bool,TarArchive* +Function,+,tar_archive_free,void,TarArchive* +Function,+,tar_archive_get_entries_count,int32_t,TarArchive* +Function,+,tar_archive_open,_Bool,"TarArchive*, const char*, TarOpenMode" +Function,+,tar_archive_set_file_callback,void,"TarArchive*, tar_unpack_file_cb, void*" +Function,+,tar_archive_store_data,_Bool,"TarArchive*, const char*, const uint8_t*, const int32_t" +Function,+,tar_archive_unpack_file,_Bool,"TarArchive*, const char*, const char*" +Function,+,tar_archive_unpack_to,_Bool,"TarArchive*, const char*, Storage_name_converter" +Function,-,tempnam,char*,"const char*, const char*" +Function,+,text_box_alloc,TextBox*, +Function,+,text_box_free,void,TextBox* +Function,+,text_box_get_view,View*,TextBox* +Function,+,text_box_reset,void,TextBox* +Function,+,text_box_set_focus,void,"TextBox*, TextBoxFocus" +Function,+,text_box_set_font,void,"TextBox*, TextBoxFont" +Function,+,text_box_set_text,void,"TextBox*, const char*" +Function,+,text_input_alloc,TextInput*, +Function,+,text_input_free,void,TextInput* +Function,+,text_input_get_validator_callback,TextInputValidatorCallback,TextInput* +Function,+,text_input_get_validator_callback_context,void*,TextInput* +Function,+,text_input_get_view,View*,TextInput* +Function,+,text_input_reset,void,TextInput* +Function,+,text_input_set_header_text,void,"TextInput*, const char*" +Function,+,text_input_set_result_callback,void,"TextInput*, TextInputCallback, void*, char*, size_t, _Bool" +Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback, void*" +Function,-,time,time_t,time_t* +Function,-,timingsafe_bcmp,int,"const void*, const void*, size_t" +Function,-,timingsafe_memcmp,int,"const void*, const void*, size_t" +Function,-,tmpfile,FILE*, +Function,-,tmpnam,char*,char* +Function,-,toascii,int,int +Function,-,toascii_l,int,"int, locale_t" +Function,-,tolower,int,int +Function,-,tolower_l,int,"int, locale_t" +Function,-,toupper,int,int +Function,-,toupper_l,int,"int, locale_t" +Function,-,tzset,void, +Function,-,uECC_compress,void,"const uint8_t*, uint8_t*, uECC_Curve" +Function,+,uECC_compute_public_key,int,"const uint8_t*, uint8_t*, uECC_Curve" +Function,-,uECC_curve_private_key_size,int,uECC_Curve +Function,-,uECC_curve_public_key_size,int,uECC_Curve +Function,-,uECC_decompress,void,"const uint8_t*, uint8_t*, uECC_Curve" +Function,-,uECC_get_rng,uECC_RNG_Function, +Function,-,uECC_make_key,int,"uint8_t*, uint8_t*, uECC_Curve" +Function,-,uECC_secp160r1,uECC_Curve, +Function,-,uECC_secp192r1,uECC_Curve, +Function,-,uECC_secp224r1,uECC_Curve, +Function,-,uECC_secp256k1,uECC_Curve, +Function,+,uECC_secp256r1,uECC_Curve, +Function,+,uECC_set_rng,void,uECC_RNG_Function +Function,-,uECC_shared_secret,int,"const uint8_t*, const uint8_t*, uint8_t*, uECC_Curve" +Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uECC_Curve" +Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve" +Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" +Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" +Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t" +Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t" +Function,-,ulTaskGetIdleRunTimeCounter,uint32_t, +Function,-,ulTaskGetIdleRunTimePercent,uint32_t, +Function,-,ungetc,int,"int, FILE*" +Function,-,unsetenv,int,const char* +Function,-,usbd_poll,void,usbd_device* +Function,-,utoa,char*,"unsigned, char*, int" +Function,-,uxListRemove,UBaseType_t,ListItem_t* +Function,-,uxTaskGetNumberOfTasks,UBaseType_t, +Function,-,uxTaskGetStackHighWaterMark,UBaseType_t,TaskHandle_t +Function,-,uxTaskGetStackHighWaterMark2,uint16_t,TaskHandle_t +Function,-,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, uint32_t*" +Function,-,uxTaskGetTaskNumber,UBaseType_t,TaskHandle_t +Function,-,uxTaskPriorityGet,UBaseType_t,const TaskHandle_t +Function,-,uxTaskPriorityGetFromISR,UBaseType_t,const TaskHandle_t +Function,-,uxTaskResetEventItemValue,TickType_t, +Function,-,uxTimerGetReloadMode,UBaseType_t,TimerHandle_t +Function,-,uxTimerGetTimerNumber,UBaseType_t,TimerHandle_t +Function,-,vApplicationGetIdleTaskMemory,void,"StaticTask_t**, StackType_t**, uint32_t*" +Function,-,vApplicationGetTimerTaskMemory,void,"StaticTask_t**, StackType_t**, uint32_t*" +Function,-,vListInitialise,void,List_t* +Function,-,vListInitialiseItem,void,ListItem_t* +Function,-,vListInsert,void,"List_t*, ListItem_t*" +Function,-,vListInsertEnd,void,"List_t*, ListItem_t*" +Function,-,vPortDefineHeapRegions,void,const HeapRegion_t* +Function,-,vPortEndScheduler,void, +Function,+,vPortEnterCritical,void, +Function,+,vPortExitCritical,void, +Function,-,vPortFree,void,void* +Function,-,vPortGetHeapStats,void,HeapStats_t* +Function,-,vPortInitialiseBlocks,void, +Function,-,vPortSuppressTicksAndSleep,void,TickType_t +Function,-,vTaskAllocateMPURegions,void,"TaskHandle_t, const MemoryRegion_t*" +Function,-,vTaskDelay,void,const TickType_t +Function,-,vTaskDelete,void,TaskHandle_t +Function,-,vTaskEndScheduler,void, +Function,-,vTaskGenericNotifyGiveFromISR,void,"TaskHandle_t, UBaseType_t, BaseType_t*" +Function,-,vTaskGetInfo,void,"TaskHandle_t, TaskStatus_t*, BaseType_t, eTaskState" +Function,-,vTaskGetRunTimeStats,void,char* +Function,-,vTaskInternalSetTimeOutState,void,TimeOut_t* +Function,-,vTaskList,void,char* +Function,-,vTaskMissedYield,void, +Function,-,vTaskPlaceOnEventList,void,"List_t*, const TickType_t" +Function,-,vTaskPlaceOnEventListRestricted,void,"List_t*, TickType_t, const BaseType_t" +Function,-,vTaskPlaceOnUnorderedEventList,void,"List_t*, const TickType_t, const TickType_t" +Function,-,vTaskPriorityDisinheritAfterTimeout,void,"const TaskHandle_t, UBaseType_t" +Function,+,vTaskPrioritySet,void,"TaskHandle_t, UBaseType_t" +Function,-,vTaskRemoveFromUnorderedEventList,void,"ListItem_t*, const TickType_t" +Function,-,vTaskResume,void,TaskHandle_t +Function,-,vTaskSetTaskNumber,void,"TaskHandle_t, const UBaseType_t" +Function,-,vTaskSetThreadLocalStoragePointer,void,"TaskHandle_t, BaseType_t, void*" +Function,-,vTaskSetTimeOutState,void,TimeOut_t* +Function,-,vTaskStartScheduler,void, +Function,-,vTaskStepTick,void,TickType_t +Function,-,vTaskSuspend,void,TaskHandle_t +Function,-,vTaskSuspendAll,void, +Function,-,vTaskSwitchContext,void, +Function,-,vTimerSetReloadMode,void,"TimerHandle_t, const BaseType_t" +Function,-,vTimerSetTimerID,void,"TimerHandle_t, void*" +Function,-,vTimerSetTimerNumber,void,"TimerHandle_t, UBaseType_t" +Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*" +Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*" +Function,+,validator_is_file_free,void,ValidatorIsFile* +Function,+,value_index_bool,uint8_t,"const _Bool, const _Bool[], uint8_t" +Function,+,value_index_float,uint8_t,"const float, const float[], uint8_t" +Function,+,value_index_uint32,uint8_t,"const uint32_t, const uint32_t[], uint8_t" +Function,+,variable_item_get_context,void*,VariableItem* +Function,+,variable_item_get_current_value_index,uint8_t,VariableItem* +Function,+,variable_item_list_add,VariableItem*,"VariableItemList*, const char*, uint8_t, VariableItemChangeCallback, void*" +Function,+,variable_item_list_alloc,VariableItemList*, +Function,+,variable_item_list_free,void,VariableItemList* +Function,+,variable_item_list_get_selected_item_index,uint8_t,VariableItemList* +Function,+,variable_item_list_get_view,View*,VariableItemList* +Function,+,variable_item_list_reset,void,VariableItemList* +Function,+,variable_item_list_set_enter_callback,void,"VariableItemList*, VariableItemListEnterCallback, void*" +Function,+,variable_item_list_set_selected_item,void,"VariableItemList*, uint8_t" +Function,+,variable_item_set_current_value_index,void,"VariableItem*, uint8_t" +Function,+,variable_item_set_current_value_text,void,"VariableItem*, const char*" +Function,+,variable_item_set_values_count,void,"VariableItem*, uint8_t" +Function,-,vasiprintf,int,"char**, const char*, __gnuc_va_list" +Function,-,vasniprintf,char*,"char*, size_t*, const char*, __gnuc_va_list" +Function,-,vasnprintf,char*,"char*, size_t*, const char*, __gnuc_va_list" +Function,-,vasprintf,int,"char**, const char*, __gnuc_va_list" +Function,-,vdiprintf,int,"int, const char*, __gnuc_va_list" +Function,-,vdprintf,int,"int, const char*, __gnuc_va_list" +Function,+,version_get,const Version*, +Function,+,version_get_builddate,const char*,const Version* +Function,+,version_get_dirty_flag,_Bool,const Version* +Function,+,version_get_gitbranch,const char*,const Version* +Function,+,version_get_gitbranchnum,const char*,const Version* +Function,+,version_get_githash,const char*,const Version* +Function,+,version_get_target,uint8_t,const Version* +Function,+,version_get_version,const char*,const Version* +Function,-,vfiprintf,int,"FILE*, const char*, __gnuc_va_list" +Function,-,vfiscanf,int,"FILE*, const char*, __gnuc_va_list" +Function,-,vfprintf,int,"FILE*, const char*, __gnuc_va_list" +Function,-,vfscanf,int,"FILE*, const char*, __gnuc_va_list" +Function,+,view_alloc,View*, +Function,+,view_allocate_model,void,"View*, ViewModelType, size_t" +Function,+,view_commit_model,void,"View*, _Bool" +Function,+,view_dispatcher_add_view,void,"ViewDispatcher*, uint32_t, View*" +Function,+,view_dispatcher_alloc,ViewDispatcher*, +Function,+,view_dispatcher_attach_to_gui,void,"ViewDispatcher*, Gui*, ViewDispatcherType" +Function,+,view_dispatcher_enable_queue,void,ViewDispatcher* +Function,+,view_dispatcher_free,void,ViewDispatcher* +Function,+,view_dispatcher_remove_view,void,"ViewDispatcher*, uint32_t" +Function,+,view_dispatcher_run,void,ViewDispatcher* +Function,+,view_dispatcher_send_custom_event,void,"ViewDispatcher*, uint32_t" +Function,+,view_dispatcher_send_to_back,void,ViewDispatcher* +Function,+,view_dispatcher_send_to_front,void,ViewDispatcher* +Function,+,view_dispatcher_set_custom_event_callback,void,"ViewDispatcher*, ViewDispatcherCustomEventCallback" +Function,+,view_dispatcher_set_event_callback_context,void,"ViewDispatcher*, void*" +Function,+,view_dispatcher_set_navigation_event_callback,void,"ViewDispatcher*, ViewDispatcherNavigationEventCallback" +Function,+,view_dispatcher_set_tick_event_callback,void,"ViewDispatcher*, ViewDispatcherTickEventCallback, uint32_t" +Function,+,view_dispatcher_stop,void,ViewDispatcher* +Function,+,view_dispatcher_switch_to_view,void,"ViewDispatcher*, uint32_t" +Function,+,view_free,void,View* +Function,+,view_free_model,void,View* +Function,+,view_get_model,void*,View* +Function,+,view_port_alloc,ViewPort*, +Function,+,view_port_draw_callback_set,void,"ViewPort*, ViewPortDrawCallback, void*" +Function,+,view_port_enabled_set,void,"ViewPort*, _Bool" +Function,+,view_port_free,void,ViewPort* +Function,+,view_port_get_height,uint8_t,ViewPort* +Function,+,view_port_get_orientation,ViewPortOrientation,const ViewPort* +Function,+,view_port_get_width,uint8_t,ViewPort* +Function,+,view_port_input_callback_set,void,"ViewPort*, ViewPortInputCallback, void*" +Function,+,view_port_is_enabled,_Bool,ViewPort* +Function,+,view_port_set_height,void,"ViewPort*, uint8_t" +Function,+,view_port_set_orientation,void,"ViewPort*, ViewPortOrientation" +Function,+,view_port_set_width,void,"ViewPort*, uint8_t" +Function,+,view_port_update,void,ViewPort* +Function,+,view_set_context,void,"View*, void*" +Function,+,view_set_custom_callback,void,"View*, ViewCustomCallback" +Function,+,view_set_draw_callback,void,"View*, ViewDrawCallback" +Function,+,view_set_enter_callback,void,"View*, ViewCallback" +Function,+,view_set_exit_callback,void,"View*, ViewCallback" +Function,+,view_set_input_callback,void,"View*, ViewInputCallback" +Function,+,view_set_orientation,void,"View*, ViewOrientation" +Function,+,view_set_previous_callback,void,"View*, ViewNavigationCallback" +Function,+,view_set_update_callback,void,"View*, ViewUpdateCallback" +Function,+,view_set_update_callback_context,void,"View*, void*" +Function,+,view_stack_add_view,void,"ViewStack*, View*" +Function,+,view_stack_alloc,ViewStack*, +Function,+,view_stack_free,void,ViewStack* +Function,+,view_stack_get_view,View*,ViewStack* +Function,+,view_stack_remove_view,void,"ViewStack*, View*" +Function,+,view_tie_icon_animation,void,"View*, IconAnimation*" +Function,-,viprintf,int,"const char*, __gnuc_va_list" +Function,-,viscanf,int,"const char*, __gnuc_va_list" +Function,-,vprintf,int,"const char*, __gnuc_va_list" +Function,-,vscanf,int,"const char*, __gnuc_va_list" +Function,-,vsiprintf,int,"char*, const char*, __gnuc_va_list" +Function,-,vsiscanf,int,"const char*, const char*, __gnuc_va_list" +Function,-,vsniprintf,int,"char*, size_t, const char*, __gnuc_va_list" +Function,-,vsnprintf,int,"char*, size_t, const char*, __gnuc_va_list" +Function,-,vsprintf,int,"char*, const char*, __gnuc_va_list" +Function,-,vsscanf,int,"const char*, const char*, __gnuc_va_list" +Function,-,wcstombs,size_t,"char*, const wchar_t*, size_t" +Function,-,wctomb,int,"char*, wchar_t" +Function,+,widget_add_button_element,void,"Widget*, GuiButtonType, const char*, ButtonCallback, void*" +Function,+,widget_add_frame_element,void,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" +Function,+,widget_add_icon_element,void,"Widget*, uint8_t, uint8_t, const Icon*" +Function,+,widget_add_string_element,void,"Widget*, uint8_t, uint8_t, Align, Align, Font, const char*" +Function,+,widget_add_string_multiline_element,void,"Widget*, uint8_t, uint8_t, Align, Align, Font, const char*" +Function,+,widget_add_text_box_element,void,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool" +Function,+,widget_add_text_scroll_element,void,"Widget*, uint8_t, uint8_t, uint8_t, uint8_t, const char*" +Function,+,widget_alloc,Widget*, +Function,+,widget_free,void,Widget* +Function,+,widget_get_view,View*,Widget* +Function,+,widget_reset,void,Widget* +Function,-,write_mutex,_Bool,"ValueMutex*, void*, size_t, uint32_t" +Function,-,xPortGetFreeHeapSize,size_t, +Function,-,xPortGetMinimumEverFreeHeapSize,size_t, +Function,-,xPortStartScheduler,BaseType_t, +Function,-,xTaskAbortDelay,BaseType_t,TaskHandle_t +Function,-,xTaskCallApplicationTaskHook,BaseType_t,"TaskHandle_t, void*" +Function,-,xTaskCatchUpTicks,BaseType_t,TickType_t +Function,-,xTaskCheckForTimeOut,BaseType_t,"TimeOut_t*, TickType_t*" +Function,-,xTaskCreate,BaseType_t,"TaskFunction_t, const char*, const uint16_t, void*, UBaseType_t, TaskHandle_t*" +Function,-,xTaskCreateStatic,TaskHandle_t,"TaskFunction_t, const char*, const uint32_t, void*, UBaseType_t, StackType_t*, StaticTask_t*" +Function,-,xTaskDelayUntil,BaseType_t,"TickType_t*, const TickType_t" +Function,-,xTaskGenericNotify,BaseType_t,"TaskHandle_t, UBaseType_t, uint32_t, eNotifyAction, uint32_t*" +Function,-,xTaskGenericNotifyFromISR,BaseType_t,"TaskHandle_t, UBaseType_t, uint32_t, eNotifyAction, uint32_t*, BaseType_t*" +Function,-,xTaskGenericNotifyStateClear,BaseType_t,"TaskHandle_t, UBaseType_t" +Function,-,xTaskGenericNotifyWait,BaseType_t,"UBaseType_t, uint32_t, uint32_t, uint32_t*, TickType_t" +Function,-,xTaskGetCurrentTaskHandle,TaskHandle_t, +Function,+,xTaskGetHandle,TaskHandle_t,const char* +Function,-,xTaskGetIdleTaskHandle,TaskHandle_t, +Function,+,xTaskGetSchedulerState,BaseType_t, +Function,+,xTaskGetTickCount,TickType_t, +Function,-,xTaskGetTickCountFromISR,TickType_t, +Function,-,xTaskIncrementTick,BaseType_t, +Function,-,xTaskPriorityDisinherit,BaseType_t,const TaskHandle_t +Function,-,xTaskPriorityInherit,BaseType_t,const TaskHandle_t +Function,-,xTaskRemoveFromEventList,BaseType_t,const List_t* +Function,-,xTaskResumeAll,BaseType_t, +Function,-,xTaskResumeFromISR,BaseType_t,TaskHandle_t +Function,-,xTimerCreate,TimerHandle_t,"const char*, const TickType_t, const BaseType_t, void*, TimerCallbackFunction_t" +Function,-,xTimerCreateStatic,TimerHandle_t,"const char*, const TickType_t, const BaseType_t, void*, TimerCallbackFunction_t, StaticTimer_t*" +Function,-,xTimerCreateTimerTask,BaseType_t, +Function,-,xTimerGenericCommand,BaseType_t,"TimerHandle_t, const BaseType_t, const TickType_t, BaseType_t*, const TickType_t" +Function,-,xTimerGetExpiryTime,TickType_t,TimerHandle_t +Function,-,xTimerGetPeriod,TickType_t,TimerHandle_t +Function,-,xTimerGetReloadMode,BaseType_t,TimerHandle_t +Function,-,xTimerGetTimerDaemonTaskHandle,TaskHandle_t, +Function,-,xTimerIsTimerActive,BaseType_t,TimerHandle_t +Function,-,xTimerPendFunctionCall,BaseType_t,"PendedFunction_t, void*, uint32_t, TickType_t" +Function,-,xTimerPendFunctionCallFromISR,BaseType_t,"PendedFunction_t, void*, uint32_t, BaseType_t*" +Variable,-,AHBPrescTable,const uint32_t[16], +Variable,-,APBPrescTable,const uint32_t[8], +Variable,-,ITM_RxBuffer,volatile int32_t, +Variable,-,MSIRangeTable,const uint32_t[16], +Variable,-,SmpsPrescalerTable,const uint32_t[4][6], +Variable,+,SystemCoreClock,uint32_t, +Variable,+,_ctype_,const char[], +Variable,-,_daylight,int, +Variable,+,_global_impure_ptr,_reent*, +Variable,+,_impure_ptr,_reent*, +Variable,-,_sys_errlist,const char*[], +Variable,-,_sys_nerr,int, +Variable,-,_timezone,long, +Variable,-,_tzname,char*[2], +Variable,+,cli_vcp,CliSession, +Variable,+,furi_hal_i2c_bus_external,FuriHalI2cBus, +Variable,+,furi_hal_i2c_bus_power,FuriHalI2cBus, +Variable,+,furi_hal_i2c_handle_external,FuriHalI2cBusHandle, +Variable,+,furi_hal_i2c_handle_power,FuriHalI2cBusHandle, +Variable,+,furi_hal_sd_spi_handle,FuriHalSpiBusHandle*, +Variable,+,furi_hal_spi_bus_d,FuriHalSpiBus, +Variable,+,furi_hal_spi_bus_handle_display,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_external,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_sd_fast,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_sd_slow,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_r,FuriHalSpiBus, +Variable,+,furi_hal_spi_preset_1edge_low_16m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_spi_preset_1edge_low_2m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_spi_preset_1edge_low_4m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_spi_preset_1edge_low_8m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_spi_preset_2edge_low_8m,const LL_SPI_InitTypeDef, +Variable,+,gpio_button_back,const GpioPin, +Variable,+,gpio_button_down,const GpioPin, +Variable,+,gpio_button_left,const GpioPin, +Variable,+,gpio_button_ok,const GpioPin, +Variable,+,gpio_button_right,const GpioPin, +Variable,+,gpio_button_up,const GpioPin, +Variable,+,gpio_display_cs,const GpioPin, +Variable,+,gpio_display_di,const GpioPin, +Variable,+,gpio_display_rst_n,const GpioPin, +Variable,+,gpio_ext_pa0,const GpioPin, +Variable,+,gpio_ext_pa1,const GpioPin, +Variable,+,gpio_ext_pa15,const GpioPin, +Variable,+,gpio_ext_pa2,const GpioPin, +Variable,+,gpio_ext_pa4,const GpioPin, +Variable,+,gpio_ext_pa5,const GpioPin, +Variable,+,gpio_ext_pa6,const GpioPin, +Variable,+,gpio_ext_pa7,const GpioPin, +Variable,+,gpio_ext_pb13,const GpioPin, +Variable,+,gpio_ext_pb2,const GpioPin, +Variable,+,gpio_ext_pb3,const GpioPin, +Variable,+,gpio_ext_pb4,const GpioPin, +Variable,+,gpio_ext_pb5,const GpioPin, +Variable,+,gpio_ext_pb9,const GpioPin, +Variable,+,gpio_ext_pc0,const GpioPin, +Variable,+,gpio_ext_pc1,const GpioPin, +Variable,+,gpio_ext_pc3,const GpioPin, +Variable,+,gpio_ext_pc4,const GpioPin, +Variable,+,gpio_ext_pc5,const GpioPin, +Variable,+,gpio_ext_pd0,const GpioPin, +Variable,+,gpio_ext_pe4,const GpioPin, +Variable,+,gpio_i2c_power_scl,const GpioPin, +Variable,+,gpio_i2c_power_sda,const GpioPin, +Variable,+,gpio_pins,const GpioPinRecord[], +Variable,+,gpio_pins_count,const size_t, +Variable,+,gpio_sdcard_cd,const GpioPin, +Variable,+,gpio_sdcard_cs,const GpioPin, +Variable,+,gpio_speaker,const GpioPin, +Variable,+,gpio_spi_d_miso,const GpioPin, +Variable,+,gpio_spi_d_mosi,const GpioPin, +Variable,+,gpio_spi_d_sck,const GpioPin, +Variable,+,gpio_usart_rx,const GpioPin, +Variable,+,gpio_usart_tx,const GpioPin, +Variable,+,gpio_usb_dm,const GpioPin, +Variable,+,gpio_usb_dp,const GpioPin, +Variable,+,ibutton_gpio,const GpioPin, +Variable,+,input_pins,const InputPin[], +Variable,+,input_pins_count,const size_t, +Variable,+,message_blink_set_color_blue,const NotificationMessage, +Variable,+,message_blink_set_color_cyan,const NotificationMessage, +Variable,+,message_blink_set_color_green,const NotificationMessage, +Variable,+,message_blink_set_color_magenta,const NotificationMessage, +Variable,+,message_blink_set_color_red,const NotificationMessage, +Variable,+,message_blink_set_color_white,const NotificationMessage, +Variable,+,message_blink_set_color_yellow,const NotificationMessage, +Variable,+,message_blink_start_10,const NotificationMessage, +Variable,+,message_blink_start_100,const NotificationMessage, +Variable,+,message_blink_stop,const NotificationMessage, +Variable,+,message_blue_0,const NotificationMessage, +Variable,+,message_blue_255,const NotificationMessage, +Variable,+,message_click,const NotificationMessage, +Variable,+,message_delay_1,const NotificationMessage, +Variable,+,message_delay_10,const NotificationMessage, +Variable,+,message_delay_100,const NotificationMessage, +Variable,+,message_delay_1000,const NotificationMessage, +Variable,+,message_delay_25,const NotificationMessage, +Variable,+,message_delay_250,const NotificationMessage, +Variable,+,message_delay_50,const NotificationMessage, +Variable,+,message_delay_500,const NotificationMessage, +Variable,+,message_display_backlight_enforce_auto,const NotificationMessage, +Variable,+,message_display_backlight_enforce_on,const NotificationMessage, +Variable,+,message_display_backlight_off,const NotificationMessage, +Variable,+,message_display_backlight_on,const NotificationMessage, +Variable,+,message_do_not_reset,const NotificationMessage, +Variable,+,message_force_display_brightness_setting_1f,const NotificationMessage, +Variable,+,message_force_speaker_volume_setting_1f,const NotificationMessage, +Variable,+,message_force_vibro_setting_off,const NotificationMessage, +Variable,+,message_force_vibro_setting_on,const NotificationMessage, +Variable,+,message_green_0,const NotificationMessage, +Variable,+,message_green_255,const NotificationMessage, +Variable,+,message_note_a0,const NotificationMessage, +Variable,+,message_note_a1,const NotificationMessage, +Variable,+,message_note_a2,const NotificationMessage, +Variable,+,message_note_a3,const NotificationMessage, +Variable,+,message_note_a4,const NotificationMessage, +Variable,+,message_note_a5,const NotificationMessage, +Variable,+,message_note_a6,const NotificationMessage, +Variable,+,message_note_a7,const NotificationMessage, +Variable,+,message_note_a8,const NotificationMessage, +Variable,+,message_note_as0,const NotificationMessage, +Variable,+,message_note_as1,const NotificationMessage, +Variable,+,message_note_as2,const NotificationMessage, +Variable,+,message_note_as3,const NotificationMessage, +Variable,+,message_note_as4,const NotificationMessage, +Variable,+,message_note_as5,const NotificationMessage, +Variable,+,message_note_as6,const NotificationMessage, +Variable,+,message_note_as7,const NotificationMessage, +Variable,+,message_note_as8,const NotificationMessage, +Variable,+,message_note_b0,const NotificationMessage, +Variable,+,message_note_b1,const NotificationMessage, +Variable,+,message_note_b2,const NotificationMessage, +Variable,+,message_note_b3,const NotificationMessage, +Variable,+,message_note_b4,const NotificationMessage, +Variable,+,message_note_b5,const NotificationMessage, +Variable,+,message_note_b6,const NotificationMessage, +Variable,+,message_note_b7,const NotificationMessage, +Variable,+,message_note_b8,const NotificationMessage, +Variable,+,message_note_c0,const NotificationMessage, +Variable,+,message_note_c1,const NotificationMessage, +Variable,+,message_note_c2,const NotificationMessage, +Variable,+,message_note_c3,const NotificationMessage, +Variable,+,message_note_c4,const NotificationMessage, +Variable,+,message_note_c5,const NotificationMessage, +Variable,+,message_note_c6,const NotificationMessage, +Variable,+,message_note_c7,const NotificationMessage, +Variable,+,message_note_c8,const NotificationMessage, +Variable,+,message_note_cs0,const NotificationMessage, +Variable,+,message_note_cs1,const NotificationMessage, +Variable,+,message_note_cs2,const NotificationMessage, +Variable,+,message_note_cs3,const NotificationMessage, +Variable,+,message_note_cs4,const NotificationMessage, +Variable,+,message_note_cs5,const NotificationMessage, +Variable,+,message_note_cs6,const NotificationMessage, +Variable,+,message_note_cs7,const NotificationMessage, +Variable,+,message_note_cs8,const NotificationMessage, +Variable,+,message_note_d0,const NotificationMessage, +Variable,+,message_note_d1,const NotificationMessage, +Variable,+,message_note_d2,const NotificationMessage, +Variable,+,message_note_d3,const NotificationMessage, +Variable,+,message_note_d4,const NotificationMessage, +Variable,+,message_note_d5,const NotificationMessage, +Variable,+,message_note_d6,const NotificationMessage, +Variable,+,message_note_d7,const NotificationMessage, +Variable,+,message_note_d8,const NotificationMessage, +Variable,+,message_note_ds0,const NotificationMessage, +Variable,+,message_note_ds1,const NotificationMessage, +Variable,+,message_note_ds2,const NotificationMessage, +Variable,+,message_note_ds3,const NotificationMessage, +Variable,+,message_note_ds4,const NotificationMessage, +Variable,+,message_note_ds5,const NotificationMessage, +Variable,+,message_note_ds6,const NotificationMessage, +Variable,+,message_note_ds7,const NotificationMessage, +Variable,+,message_note_ds8,const NotificationMessage, +Variable,+,message_note_e0,const NotificationMessage, +Variable,+,message_note_e1,const NotificationMessage, +Variable,+,message_note_e2,const NotificationMessage, +Variable,+,message_note_e3,const NotificationMessage, +Variable,+,message_note_e4,const NotificationMessage, +Variable,+,message_note_e5,const NotificationMessage, +Variable,+,message_note_e6,const NotificationMessage, +Variable,+,message_note_e7,const NotificationMessage, +Variable,+,message_note_e8,const NotificationMessage, +Variable,+,message_note_f0,const NotificationMessage, +Variable,+,message_note_f1,const NotificationMessage, +Variable,+,message_note_f2,const NotificationMessage, +Variable,+,message_note_f3,const NotificationMessage, +Variable,+,message_note_f4,const NotificationMessage, +Variable,+,message_note_f5,const NotificationMessage, +Variable,+,message_note_f6,const NotificationMessage, +Variable,+,message_note_f7,const NotificationMessage, +Variable,+,message_note_f8,const NotificationMessage, +Variable,+,message_note_fs0,const NotificationMessage, +Variable,+,message_note_fs1,const NotificationMessage, +Variable,+,message_note_fs2,const NotificationMessage, +Variable,+,message_note_fs3,const NotificationMessage, +Variable,+,message_note_fs4,const NotificationMessage, +Variable,+,message_note_fs5,const NotificationMessage, +Variable,+,message_note_fs6,const NotificationMessage, +Variable,+,message_note_fs7,const NotificationMessage, +Variable,+,message_note_fs8,const NotificationMessage, +Variable,+,message_note_g0,const NotificationMessage, +Variable,+,message_note_g1,const NotificationMessage, +Variable,+,message_note_g2,const NotificationMessage, +Variable,+,message_note_g3,const NotificationMessage, +Variable,+,message_note_g4,const NotificationMessage, +Variable,+,message_note_g5,const NotificationMessage, +Variable,+,message_note_g6,const NotificationMessage, +Variable,+,message_note_g7,const NotificationMessage, +Variable,+,message_note_g8,const NotificationMessage, +Variable,+,message_note_gs0,const NotificationMessage, +Variable,+,message_note_gs1,const NotificationMessage, +Variable,+,message_note_gs2,const NotificationMessage, +Variable,+,message_note_gs3,const NotificationMessage, +Variable,+,message_note_gs4,const NotificationMessage, +Variable,+,message_note_gs5,const NotificationMessage, +Variable,+,message_note_gs6,const NotificationMessage, +Variable,+,message_note_gs7,const NotificationMessage, +Variable,+,message_note_gs8,const NotificationMessage, +Variable,+,message_red_0,const NotificationMessage, +Variable,+,message_red_255,const NotificationMessage, +Variable,+,message_sound_off,const NotificationMessage, +Variable,+,message_vibro_off,const NotificationMessage, +Variable,+,message_vibro_on,const NotificationMessage, +Variable,+,periph_power,const GpioPin, +Variable,+,sequence_audiovisual_alert,const NotificationSequence, +Variable,+,sequence_blink_blue_10,const NotificationSequence, +Variable,+,sequence_blink_blue_100,const NotificationSequence, +Variable,+,sequence_blink_cyan_10,const NotificationSequence, +Variable,+,sequence_blink_cyan_100,const NotificationSequence, +Variable,+,sequence_blink_green_10,const NotificationSequence, +Variable,+,sequence_blink_green_100,const NotificationSequence, +Variable,+,sequence_blink_magenta_10,const NotificationSequence, +Variable,+,sequence_blink_magenta_100,const NotificationSequence, +Variable,+,sequence_blink_red_10,const NotificationSequence, +Variable,+,sequence_blink_red_100,const NotificationSequence, +Variable,+,sequence_blink_start_blue,const NotificationSequence, +Variable,+,sequence_blink_start_cyan,const NotificationSequence, +Variable,+,sequence_blink_start_green,const NotificationSequence, +Variable,+,sequence_blink_start_magenta,const NotificationSequence, +Variable,+,sequence_blink_start_red,const NotificationSequence, +Variable,+,sequence_blink_start_yellow,const NotificationSequence, +Variable,+,sequence_blink_stop,const NotificationSequence, +Variable,+,sequence_blink_white_100,const NotificationSequence, +Variable,+,sequence_blink_yellow_10,const NotificationSequence, +Variable,+,sequence_blink_yellow_100,const NotificationSequence, +Variable,+,sequence_charged,const NotificationSequence, +Variable,+,sequence_charging,const NotificationSequence, +Variable,+,sequence_display_backlight_enforce_auto,const NotificationSequence, +Variable,+,sequence_display_backlight_enforce_on,const NotificationSequence, +Variable,+,sequence_display_backlight_off,const NotificationSequence, +Variable,+,sequence_display_backlight_off_delay_1000,const NotificationSequence, +Variable,+,sequence_display_backlight_on,const NotificationSequence, +Variable,+,sequence_double_vibro,const NotificationSequence, +Variable,+,sequence_error,const NotificationSequence, +Variable,+,sequence_not_charging,const NotificationSequence, +Variable,+,sequence_reset_blue,const NotificationSequence, +Variable,+,sequence_reset_display,const NotificationSequence, +Variable,+,sequence_reset_green,const NotificationSequence, +Variable,+,sequence_reset_red,const NotificationSequence, +Variable,+,sequence_reset_rgb,const NotificationSequence, +Variable,+,sequence_reset_sound,const NotificationSequence, +Variable,+,sequence_reset_vibro,const NotificationSequence, +Variable,+,sequence_set_blue_255,const NotificationSequence, +Variable,+,sequence_set_green_255,const NotificationSequence, +Variable,+,sequence_set_only_blue_255,const NotificationSequence, +Variable,+,sequence_set_only_green_255,const NotificationSequence, +Variable,+,sequence_set_only_red_255,const NotificationSequence, +Variable,+,sequence_set_red_255,const NotificationSequence, +Variable,+,sequence_set_vibro_on,const NotificationSequence, +Variable,+,sequence_single_vibro,const NotificationSequence, +Variable,+,sequence_solid_yellow,const NotificationSequence, +Variable,+,sequence_success,const NotificationSequence, +Variable,-,suboptarg,char*, +Variable,+,usb_cdc_dual,FuriHalUsbInterface, +Variable,+,usb_cdc_single,FuriHalUsbInterface, +Variable,+,usb_hid,FuriHalUsbInterface, +Variable,+,usb_hid_u2f,FuriHalUsbInterface, +Variable,+,usbd_devfs,const usbd_driver, +Variable,+,vibro_gpio,const GpioPin, diff --git a/firmware/targets/f18/furi_hal/furi_hal.c b/firmware/targets/f18/furi_hal/furi_hal.c new file mode 100644 index 000000000..ad35a0074 --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal.c @@ -0,0 +1,91 @@ +#include +#include + +#include + +#include + +#define TAG "FuriHal" + +void furi_hal_init_early() { + furi_hal_cortex_init_early(); + + furi_hal_clock_init_early(); + + furi_hal_resources_init_early(); + + furi_hal_os_init(); + + furi_hal_spi_config_init_early(); + + furi_hal_i2c_init_early(); + furi_hal_light_init(); + + furi_hal_rtc_init_early(); +} + +void furi_hal_deinit_early() { + furi_hal_rtc_deinit_early(); + + furi_hal_i2c_deinit_early(); + furi_hal_spi_config_deinit_early(); + + furi_hal_resources_deinit_early(); + + furi_hal_clock_deinit_early(); +} + +void furi_hal_init() { + furi_hal_mpu_init(); + furi_hal_clock_init(); + furi_hal_console_init(); + furi_hal_rtc_init(); + + furi_hal_interrupt_init(); + + furi_hal_flash_init(); + + furi_hal_resources_init(); + FURI_LOG_I(TAG, "GPIO OK"); + + furi_hal_version_init(); + + furi_hal_spi_config_init(); + + furi_hal_speaker_init(); + FURI_LOG_I(TAG, "Speaker OK"); + + furi_hal_crypto_init(); + + // USB +#ifndef FURI_RAM_EXEC + furi_hal_usb_init(); + FURI_LOG_I(TAG, "USB OK"); +#endif + + furi_hal_i2c_init(); + + // High Level + furi_hal_power_init(); + furi_hal_light_init(); +#ifndef FURI_RAM_EXEC + furi_hal_vibro_init(); +#endif + furi_hal_bt_init(); + furi_hal_compress_icon_init(); + + // FatFS driver initialization + MX_FATFS_Init(); + FURI_LOG_I(TAG, "FATFS OK"); +} + +void furi_hal_switch(void* address) { + __set_BASEPRI(0); + asm volatile("ldr r3, [%0] \n" + "msr msp, r3 \n" + "ldr r3, [%1] \n" + "mov pc, r3 \n" + : + : "r"(address), "r"(address + 0x4) + : "r3"); +} diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.c b/firmware/targets/f18/furi_hal/furi_hal_resources.c new file mode 100644 index 000000000..dafeefdd0 --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal_resources.c @@ -0,0 +1,201 @@ +#include +#include + +#include +#include + +const GpioPin vibro_gpio = {.port = GPIOA, .pin = LL_GPIO_PIN_8}; +const GpioPin ibutton_gpio = {.port = GPIOB, .pin = LL_GPIO_PIN_14}; + +const GpioPin gpio_display_cs = {.port = GPIOC, .pin = LL_GPIO_PIN_11}; +const GpioPin gpio_display_rst_n = {.port = GPIOB, .pin = LL_GPIO_PIN_0}; +const GpioPin gpio_display_di = {.port = GPIOB, .pin = LL_GPIO_PIN_1}; +const GpioPin gpio_sdcard_cs = {.port = GPIOC, .pin = LL_GPIO_PIN_12}; +const GpioPin gpio_sdcard_cd = {.port = GPIOC, .pin = LL_GPIO_PIN_10}; + +const GpioPin gpio_button_up = {.port = GPIOB, .pin = LL_GPIO_PIN_10}; +const GpioPin gpio_button_down = {.port = GPIOC, .pin = LL_GPIO_PIN_6}; +const GpioPin gpio_button_right = {.port = GPIOB, .pin = LL_GPIO_PIN_12}; +const GpioPin gpio_button_left = {.port = GPIOB, .pin = LL_GPIO_PIN_11}; +const GpioPin gpio_button_ok = {.port = GPIOH, .pin = LL_GPIO_PIN_3}; +const GpioPin gpio_button_back = {.port = GPIOC, .pin = LL_GPIO_PIN_13}; + +const GpioPin gpio_spi_d_miso = {.port = GPIOC, .pin = LL_GPIO_PIN_2}; +const GpioPin gpio_spi_d_mosi = {.port = GPIOB, .pin = LL_GPIO_PIN_15}; +const GpioPin gpio_spi_d_sck = {.port = GPIOD, .pin = LL_GPIO_PIN_1}; + +const GpioPin gpio_ext_pc0 = {.port = GPIOC, .pin = LL_GPIO_PIN_0}; +const GpioPin gpio_ext_pc1 = {.port = GPIOC, .pin = LL_GPIO_PIN_1}; +const GpioPin gpio_ext_pc3 = {.port = GPIOC, .pin = LL_GPIO_PIN_3}; +const GpioPin gpio_ext_pb2 = {.port = GPIOB, .pin = LL_GPIO_PIN_2}; +const GpioPin gpio_ext_pb3 = {.port = GPIOB, .pin = LL_GPIO_PIN_3}; +const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = LL_GPIO_PIN_4}; +const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = LL_GPIO_PIN_6}; +const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = LL_GPIO_PIN_7}; + +const GpioPin gpio_ext_pc5 = {.port = GPIOC, .pin = LL_GPIO_PIN_5}; +const GpioPin gpio_ext_pc4 = {.port = GPIOC, .pin = LL_GPIO_PIN_4}; +const GpioPin gpio_ext_pa5 = {.port = GPIOA, .pin = LL_GPIO_PIN_5}; +const GpioPin gpio_ext_pb9 = {.port = GPIOB, .pin = LL_GPIO_PIN_9}; +const GpioPin gpio_ext_pa0 = {.port = GPIOA, .pin = LL_GPIO_PIN_0}; +const GpioPin gpio_ext_pa1 = {.port = GPIOA, .pin = LL_GPIO_PIN_1}; +const GpioPin gpio_ext_pa15 = {.port = GPIOA, .pin = LL_GPIO_PIN_15}; +const GpioPin gpio_ext_pe4 = {.port = GPIOE, .pin = LL_GPIO_PIN_4}; +const GpioPin gpio_ext_pa2 = {.port = GPIOA, .pin = LL_GPIO_PIN_2}; +const GpioPin gpio_ext_pb4 = {.port = GPIOB, .pin = LL_GPIO_PIN_4}; +const GpioPin gpio_ext_pb5 = {.port = GPIOB, .pin = LL_GPIO_PIN_5}; +const GpioPin gpio_ext_pd0 = {.port = GPIOD, .pin = LL_GPIO_PIN_0}; +const GpioPin gpio_ext_pb13 = {.port = GPIOB, .pin = LL_GPIO_PIN_13}; + +const GpioPin gpio_usart_tx = {.port = GPIOB, .pin = LL_GPIO_PIN_6}; +const GpioPin gpio_usart_rx = {.port = GPIOB, .pin = LL_GPIO_PIN_7}; + +const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10}; +const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9}; + +const GpioPin gpio_speaker = {.port = GPIOB, .pin = LL_GPIO_PIN_8}; + +const GpioPin periph_power = {.port = GPIOA, .pin = LL_GPIO_PIN_3}; + +const GpioPin gpio_usb_dm = {.port = GPIOA, .pin = LL_GPIO_PIN_11}; +const GpioPin gpio_usb_dp = {.port = GPIOA, .pin = LL_GPIO_PIN_12}; + +const GpioPinRecord gpio_pins[] = { + {.pin = &gpio_ext_pa7, .name = "PA7", .debug = false}, + {.pin = &gpio_ext_pa6, .name = "PA6", .debug = false}, + {.pin = &gpio_ext_pa4, .name = "PA4", .debug = false}, + {.pin = &gpio_ext_pb3, .name = "PB3", .debug = false}, + {.pin = &gpio_ext_pb2, .name = "PB2", .debug = false}, + {.pin = &gpio_ext_pc3, .name = "PC3", .debug = false}, + {.pin = &gpio_ext_pc1, .name = "PC1", .debug = false}, + {.pin = &gpio_ext_pc0, .name = "PC0", .debug = false}, + + {.pin = &gpio_ext_pc5, .name = "PC5", .debug = false}, + {.pin = &gpio_ext_pc4, .name = "PC4", .debug = false}, + {.pin = &gpio_ext_pa5, .name = "PA5", .debug = false}, + {.pin = &gpio_ext_pb9, .name = "PB9", .debug = false}, + {.pin = &gpio_ext_pa0, .name = "PA0", .debug = false}, + {.pin = &gpio_ext_pa1, .name = "PA1", .debug = false}, + {.pin = &gpio_ext_pa15, .name = "PA15", .debug = false}, + {.pin = &gpio_ext_pe4, .name = "PE4", .debug = false}, + {.pin = &gpio_ext_pa2, .name = "PA2", .debug = false}, + {.pin = &gpio_ext_pb4, .name = "PB4", .debug = false}, + {.pin = &gpio_ext_pb5, .name = "PB5", .debug = false}, + {.pin = &gpio_ext_pd0, .name = "PD0", .debug = false}, + {.pin = &gpio_ext_pb13, .name = "PB13", .debug = false}, + + /* Dangerous pins, may damage hardware */ + {.pin = &gpio_usart_rx, .name = "PB7", .debug = true}, + {.pin = &gpio_speaker, .name = "PB8", .debug = true}, +}; + +const size_t gpio_pins_count = sizeof(gpio_pins) / sizeof(GpioPinRecord); + +const InputPin input_pins[] = { + {.gpio = &gpio_button_up, .key = InputKeyUp, .inverted = true, .name = "Up"}, + {.gpio = &gpio_button_down, .key = InputKeyDown, .inverted = true, .name = "Down"}, + {.gpio = &gpio_button_right, .key = InputKeyRight, .inverted = true, .name = "Right"}, + {.gpio = &gpio_button_left, .key = InputKeyLeft, .inverted = true, .name = "Left"}, + {.gpio = &gpio_button_ok, .key = InputKeyOk, .inverted = false, .name = "OK"}, + {.gpio = &gpio_button_back, .key = InputKeyBack, .inverted = true, .name = "Back"}, +}; + +const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); + +static void furi_hal_resources_init_input_pins(GpioMode mode) { + for(size_t i = 0; i < input_pins_count; i++) { + furi_hal_gpio_init( + input_pins[i].gpio, + mode, + (input_pins[i].inverted) ? GpioPullUp : GpioPullDown, + GpioSpeedLow); + } +} + +void furi_hal_resources_init_early() { + furi_hal_resources_init_input_pins(GpioModeInput); + + // SD Card stepdown control + furi_hal_gpio_write(&periph_power, 1); + furi_hal_gpio_init(&periph_power, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); + + // Display pins + furi_hal_gpio_write(&gpio_display_rst_n, 1); + furi_hal_gpio_init_simple(&gpio_display_rst_n, GpioModeOutputPushPull); + furi_hal_gpio_init(&gpio_display_di, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + + // Pullup display reset pin for shutdown + SET_BIT(PWR->PUCRB, gpio_display_rst_n.pin); + CLEAR_BIT(PWR->PDCRB, gpio_display_rst_n.pin); + SET_BIT(PWR->CR3, PWR_CR3_APC); + + // Hard reset USB + furi_hal_gpio_write(&gpio_usb_dm, 1); + furi_hal_gpio_write(&gpio_usb_dp, 1); + furi_hal_gpio_init_simple(&gpio_usb_dm, GpioModeOutputOpenDrain); + furi_hal_gpio_init_simple(&gpio_usb_dp, GpioModeOutputOpenDrain); + furi_hal_gpio_write(&gpio_usb_dm, 0); + furi_hal_gpio_write(&gpio_usb_dp, 0); + furi_delay_us(5); // Device Driven disconnect: 2.5us + extra to compensate cables + furi_hal_gpio_write(&gpio_usb_dm, 1); + furi_hal_gpio_write(&gpio_usb_dp, 1); + furi_hal_gpio_init_simple(&gpio_usb_dm, GpioModeAnalog); + furi_hal_gpio_init_simple(&gpio_usb_dp, GpioModeAnalog); + furi_hal_gpio_write(&gpio_usb_dm, 0); + furi_hal_gpio_write(&gpio_usb_dp, 0); + + // External header pins + furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(&gpio_ext_pc3, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(&gpio_ext_pb2, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(&gpio_ext_pb3, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(&gpio_ext_pa4, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(&gpio_ext_pa6, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullNo, GpioSpeedLow); +} + +void furi_hal_resources_deinit_early() { + furi_hal_resources_init_input_pins(GpioModeAnalog); +} + +void furi_hal_resources_init() { + // Button pins + furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); + + // Display pins + furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_display_rst_n, 0); + + furi_hal_gpio_init(&gpio_display_di, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_display_di, 0); + + // SD pins + furi_hal_gpio_init(&gpio_sdcard_cd, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_sdcard_cd, 0); + + furi_hal_gpio_init(&vibro_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + NVIC_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(EXTI0_IRQn); + + NVIC_SetPriority(EXTI1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(EXTI1_IRQn); + + NVIC_SetPriority(EXTI2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(EXTI2_IRQn); + + NVIC_SetPriority(EXTI3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(EXTI3_IRQn); + + NVIC_SetPriority(EXTI4_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(EXTI4_IRQn); + + NVIC_SetPriority(EXTI9_5_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(EXTI9_5_IRQn); + + NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(EXTI15_10_IRQn); +} diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.h b/firmware/targets/f18/furi_hal/furi_hal_resources.h new file mode 100644 index 000000000..ef2cdae7f --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal_resources.h @@ -0,0 +1,116 @@ +#pragma once + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Input Related Constants */ +#define INPUT_DEBOUNCE_TICKS 4 + +/* Input Keys */ +typedef enum { + InputKeyUp, + InputKeyDown, + InputKeyRight, + InputKeyLeft, + InputKeyOk, + InputKeyBack, + InputKeyMAX, /**< Special value */ +} InputKey; + +/* Light */ +typedef enum { + LightRed = (1 << 0), + LightGreen = (1 << 1), + LightBlue = (1 << 2), + LightBacklight = (1 << 3), +} Light; + +typedef struct { + const GpioPin* gpio; + const InputKey key; + const bool inverted; + const char* name; +} InputPin; + +typedef struct { + const GpioPin* pin; + const char* name; + const bool debug; +} GpioPinRecord; + +extern const InputPin input_pins[]; +extern const size_t input_pins_count; + +extern const GpioPinRecord gpio_pins[]; +extern const size_t gpio_pins_count; + +extern const GpioPin vibro_gpio; +extern const GpioPin ibutton_gpio; + +extern const GpioPin gpio_display_cs; +extern const GpioPin gpio_display_rst_n; +extern const GpioPin gpio_display_di; +extern const GpioPin gpio_sdcard_cs; +extern const GpioPin gpio_sdcard_cd; + +extern const GpioPin gpio_button_up; +extern const GpioPin gpio_button_down; +extern const GpioPin gpio_button_right; +extern const GpioPin gpio_button_left; +extern const GpioPin gpio_button_ok; +extern const GpioPin gpio_button_back; + +extern const GpioPin gpio_spi_d_miso; +extern const GpioPin gpio_spi_d_mosi; +extern const GpioPin gpio_spi_d_sck; + +extern const GpioPin gpio_ext_pc0; +extern const GpioPin gpio_ext_pc1; +extern const GpioPin gpio_ext_pc3; +extern const GpioPin gpio_ext_pb2; +extern const GpioPin gpio_ext_pb3; +extern const GpioPin gpio_ext_pa4; +extern const GpioPin gpio_ext_pa6; +extern const GpioPin gpio_ext_pa7; + +extern const GpioPin gpio_ext_pc5; +extern const GpioPin gpio_ext_pc4; +extern const GpioPin gpio_ext_pa5; +extern const GpioPin gpio_ext_pb9; +extern const GpioPin gpio_ext_pa0; +extern const GpioPin gpio_ext_pa1; +extern const GpioPin gpio_ext_pa15; +extern const GpioPin gpio_ext_pe4; +extern const GpioPin gpio_ext_pa2; +extern const GpioPin gpio_ext_pb4; +extern const GpioPin gpio_ext_pb5; +extern const GpioPin gpio_ext_pd0; +extern const GpioPin gpio_ext_pb13; + +extern const GpioPin gpio_usart_tx; +extern const GpioPin gpio_usart_rx; +extern const GpioPin gpio_i2c_power_sda; +extern const GpioPin gpio_i2c_power_scl; + +extern const GpioPin gpio_speaker; + +extern const GpioPin periph_power; + +extern const GpioPin gpio_usb_dm; +extern const GpioPin gpio_usb_dp; + +void furi_hal_resources_init_early(); + +void furi_hal_resources_deinit_early(); + +void furi_hal_resources_init(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f18/furi_hal/furi_hal_spi_config.c b/firmware/targets/f18/furi_hal/furi_hal_spi_config.c new file mode 100644 index 000000000..0fbe55e2a --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal_spi_config.c @@ -0,0 +1,377 @@ +#include +#include +#include +#include + +#define TAG "FuriHalSpiConfig" + +/* SPI Presets */ + +const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_2EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV16, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = { + .Mode = LL_SPI_MODE_MASTER, + .TransferDirection = LL_SPI_FULL_DUPLEX, + .DataWidth = LL_SPI_DATAWIDTH_8BIT, + .ClockPolarity = LL_SPI_POLARITY_LOW, + .ClockPhase = LL_SPI_PHASE_1EDGE, + .NSS = LL_SPI_NSS_SOFT, + .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV32, + .BitOrder = LL_SPI_MSB_FIRST, + .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, + .CRCPoly = 7, +}; + +/* SPI Buses */ + +FuriMutex* furi_hal_spi_bus_r_mutex = NULL; + +void furi_hal_spi_config_init_early() { + furi_hal_spi_bus_init(&furi_hal_spi_bus_d); + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display); +} + +void furi_hal_spi_config_deinit_early() { + furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_display); + furi_hal_spi_bus_deinit(&furi_hal_spi_bus_d); +} + +void furi_hal_spi_config_init() { + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast); + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow); + + FURI_LOG_I(TAG, "Init OK"); +} + +static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { + if(event == FuriHalSpiBusEventInit) { + furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + FURI_CRITICAL_ENTER(); + LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); + FURI_CRITICAL_EXIT(); + bus->current_handle = NULL; + } else if(event == FuriHalSpiBusEventDeinit) { + furi_mutex_free(furi_hal_spi_bus_r_mutex); + FURI_CRITICAL_ENTER(); + LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); + LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); + FURI_CRITICAL_EXIT(); + } else if(event == FuriHalSpiBusEventLock) { + furi_check(furi_mutex_acquire(furi_hal_spi_bus_r_mutex, FuriWaitForever) == FuriStatusOk); + } else if(event == FuriHalSpiBusEventUnlock) { + furi_check(furi_mutex_release(furi_hal_spi_bus_r_mutex) == FuriStatusOk); + } else if(event == FuriHalSpiBusEventActivate) { + FURI_CRITICAL_ENTER(); + LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); + FURI_CRITICAL_EXIT(); + } else if(event == FuriHalSpiBusEventDeactivate) { + FURI_CRITICAL_ENTER(); + LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); + FURI_CRITICAL_EXIT(); + } +} + +FuriHalSpiBus furi_hal_spi_bus_r = { + .spi = SPI1, + .callback = furi_hal_spi_bus_r_event_callback, +}; + +FuriMutex* furi_hal_spi_bus_d_mutex = NULL; + +static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { + if(event == FuriHalSpiBusEventInit) { + furi_hal_spi_bus_d_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + FURI_CRITICAL_ENTER(); + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); + FURI_CRITICAL_EXIT(); + bus->current_handle = NULL; + } else if(event == FuriHalSpiBusEventDeinit) { + furi_mutex_free(furi_hal_spi_bus_d_mutex); + FURI_CRITICAL_ENTER(); + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); + FURI_CRITICAL_EXIT(); + } else if(event == FuriHalSpiBusEventLock) { + furi_check(furi_mutex_acquire(furi_hal_spi_bus_d_mutex, FuriWaitForever) == FuriStatusOk); + } else if(event == FuriHalSpiBusEventUnlock) { + furi_check(furi_mutex_release(furi_hal_spi_bus_d_mutex) == FuriStatusOk); + } else if(event == FuriHalSpiBusEventActivate) { + FURI_CRITICAL_ENTER(); + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); + FURI_CRITICAL_EXIT(); + } else if(event == FuriHalSpiBusEventDeactivate) { + FURI_CRITICAL_ENTER(); + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); + FURI_CRITICAL_EXIT(); + } +} + +FuriHalSpiBus furi_hal_spi_bus_d = { + .spi = SPI2, + .callback = furi_hal_spi_bus_d_event_callback, +}; + +/* SPI Bus Handles */ + +inline static void furi_hal_spi_bus_r_handle_event_callback( + FuriHalSpiBusHandle* handle, + FuriHalSpiBusHandleEvent event, + const LL_SPI_InitTypeDef* preset) { + if(event == FuriHalSpiBusHandleEventInit) { + furi_hal_gpio_write(handle->cs, true); + furi_hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + } else if(event == FuriHalSpiBusHandleEventDeinit) { + furi_hal_gpio_write(handle->cs, true); + furi_hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + } else if(event == FuriHalSpiBusHandleEventActivate) { + LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset); + LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER); + LL_SPI_Enable(handle->bus->spi); + + furi_hal_gpio_init_ex( + handle->miso, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_init_ex( + handle->mosi, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_init_ex( + handle->sck, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + + furi_hal_gpio_write(handle->cs, false); + } else if(event == FuriHalSpiBusHandleEventDeactivate) { + furi_hal_gpio_write(handle->cs, true); + + furi_hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + LL_SPI_Disable(handle->bus->spi); + } +} + +inline static void furi_hal_spi_bus_nfc_handle_event_callback( + FuriHalSpiBusHandle* handle, + FuriHalSpiBusHandleEvent event, + const LL_SPI_InitTypeDef* preset) { + if(event == FuriHalSpiBusHandleEventInit) { + // Configure GPIOs in normal SPI mode + furi_hal_gpio_init_ex( + handle->miso, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_init_ex( + handle->mosi, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_init_ex( + handle->sck, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_write(handle->cs, true); + furi_hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + } else if(event == FuriHalSpiBusHandleEventDeinit) { + // Configure GPIOs for st25r3916 Transparent mode + furi_hal_gpio_init(handle->sck, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_init(handle->miso, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_init(handle->cs, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_write(handle->mosi, false); + furi_hal_gpio_init(handle->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + } else if(event == FuriHalSpiBusHandleEventActivate) { + LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset); + LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER); + LL_SPI_Enable(handle->bus->spi); + + furi_hal_gpio_init_ex( + handle->miso, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_init_ex( + handle->mosi, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_init_ex( + handle->sck, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + + } else if(event == FuriHalSpiBusHandleEventDeactivate) { + furi_hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + LL_SPI_Disable(handle->bus->spi); + } +} + +static void furi_hal_spi_bus_handle_external_event_callback( + FuriHalSpiBusHandle* handle, + FuriHalSpiBusHandleEvent event) { + furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m); +} + +FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = { + .bus = &furi_hal_spi_bus_r, + .callback = furi_hal_spi_bus_handle_external_event_callback, + .miso = &gpio_ext_pa6, + .mosi = &gpio_ext_pa7, + .sck = &gpio_ext_pb3, + .cs = &gpio_ext_pa4, +}; + +inline static void furi_hal_spi_bus_d_handle_event_callback( + FuriHalSpiBusHandle* handle, + FuriHalSpiBusHandleEvent event, + const LL_SPI_InitTypeDef* preset) { + if(event == FuriHalSpiBusHandleEventInit) { + furi_hal_gpio_write(handle->cs, true); + furi_hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh); + + furi_hal_gpio_init_ex( + handle->miso, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); + furi_hal_gpio_init_ex( + handle->mosi, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); + furi_hal_gpio_init_ex( + handle->sck, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); + + } else if(event == FuriHalSpiBusHandleEventDeinit) { + furi_hal_gpio_write(handle->cs, true); + furi_hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullUp, GpioSpeedLow); + } else if(event == FuriHalSpiBusHandleEventActivate) { + LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset); + LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER); + LL_SPI_Enable(handle->bus->spi); + furi_hal_gpio_write(handle->cs, false); + } else if(event == FuriHalSpiBusHandleEventDeactivate) { + furi_hal_gpio_write(handle->cs, true); + LL_SPI_Disable(handle->bus->spi); + } +} + +static void furi_hal_spi_bus_handle_display_event_callback( + FuriHalSpiBusHandle* handle, + FuriHalSpiBusHandleEvent event) { + furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_4m); +} + +FuriHalSpiBusHandle furi_hal_spi_bus_handle_display = { + .bus = &furi_hal_spi_bus_d, + .callback = furi_hal_spi_bus_handle_display_event_callback, + .miso = &gpio_spi_d_miso, + .mosi = &gpio_spi_d_mosi, + .sck = &gpio_spi_d_sck, + .cs = &gpio_display_cs, +}; + +static void furi_hal_spi_bus_handle_sd_fast_event_callback( + FuriHalSpiBusHandle* handle, + FuriHalSpiBusHandleEvent event) { + furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_16m); +} + +FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast = { + .bus = &furi_hal_spi_bus_d, + .callback = furi_hal_spi_bus_handle_sd_fast_event_callback, + .miso = &gpio_spi_d_miso, + .mosi = &gpio_spi_d_mosi, + .sck = &gpio_spi_d_sck, + .cs = &gpio_sdcard_cs, +}; + +static void furi_hal_spi_bus_handle_sd_slow_event_callback( + FuriHalSpiBusHandle* handle, + FuriHalSpiBusHandleEvent event) { + furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m); +} + +FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow = { + .bus = &furi_hal_spi_bus_d, + .callback = furi_hal_spi_bus_handle_sd_slow_event_callback, + .miso = &gpio_spi_d_miso, + .mosi = &gpio_spi_d_mosi, + .sck = &gpio_spi_d_sck, + .cs = &gpio_sdcard_cs, +}; diff --git a/firmware/targets/f18/furi_hal/furi_hal_spi_config.h b/firmware/targets/f18/furi_hal/furi_hal_spi_config.h new file mode 100644 index 000000000..da39fbfa6 --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal_spi_config.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Preset for ST25R916 */ +extern const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m; + +/** Preset for CC1101 */ +extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m; + +/** Preset for ST7567 (Display) */ +extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m; + +/** Preset for SdCard in fast mode */ +extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m; + +/** Preset for SdCard in slow mode */ +extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m; + +/** Furi Hal Spi Bus R (External) */ +extern FuriHalSpiBus furi_hal_spi_bus_r; + +/** Furi Hal Spi Bus D (Display, SdCard) */ +extern FuriHalSpiBus furi_hal_spi_bus_d; + +/** External on `furi_hal_spi_bus_r` + * Preset: `furi_hal_spi_preset_1edge_low_2m` + * + * miso: pa6 + * mosi: pa7 + * sck: pb3 + * cs: pa4 (software controlled) + * + * @warning not initialized by default, call `furi_hal_spi_bus_handle_init` to initialize + * Bus pins are floating on inactive state, CS high after initialization + * + */ +extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_external; + +/** ST7567(Display) on `furi_hal_spi_bus_d` */ +extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_display; + +/** SdCard in fast mode on `furi_hal_spi_bus_d` */ +extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast; + +/** SdCard in slow mode on `furi_hal_spi_bus_d` */ +extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow; + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f18/furi_hal/furi_hal_target_hw.h b/firmware/targets/f18/furi_hal/furi_hal_target_hw.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal_target_hw.h @@ -0,0 +1 @@ +#pragma once diff --git a/firmware/targets/f18/furi_hal/furi_hal_version_device.c b/firmware/targets/f18/furi_hal/furi_hal_version_device.c new file mode 100644 index 000000000..1b5090b93 --- /dev/null +++ b/firmware/targets/f18/furi_hal/furi_hal_version_device.c @@ -0,0 +1,21 @@ +#include + +bool furi_hal_version_do_i_belong_here() { + return (furi_hal_version_get_hw_target() == 18) || (furi_hal_version_get_hw_target() == 0); +} + +const char* furi_hal_version_get_model_name() { + return "Komi"; +} + +const char* furi_hal_version_get_model_code() { + return "N/A"; +} + +const char* furi_hal_version_get_fcc_id() { + return "N/A"; +} + +const char* furi_hal_version_get_ic_id() { + return "N/A"; +} diff --git a/firmware/targets/f18/target.json b/firmware/targets/f18/target.json new file mode 100644 index 000000000..2c3b27ab1 --- /dev/null +++ b/firmware/targets/f18/target.json @@ -0,0 +1,55 @@ +{ + "inherit": "7", + "include_paths": [ + "furi_hal" + ], + "sdk_header_paths": [ + "../furi_hal_include", + "furi_hal", + "platform_specific" + ], + "sdk_symbols": "api_symbols.csv", + "linker_dependencies": [ + "print", + "flipper18", + "furi", + "freertos", + "stm32cubewb", + "hwdrivers", + "fatfs", + "littlefs", + "flipperformat", + "toolbox", + "microtar", + "usb_stm32", + "appframe", + "assets", + "misc", + "flipper_application", + "flipperformat", + "toolbox", + "flipper18" + ], + "excluded_sources": [ + "furi_hal_infrared.c", + "furi_hal_nfc.c", + "furi_hal_rfid.c", + "furi_hal_subghz.c" + ], + "excluded_headers": [ + "furi_hal_infrared.h", + "furi_hal_nfc.h", + "furi_hal_rfid.h", + "furi_hal_subghz.h", + "furi_hal_ibutton.h", + "furi_hal_subghz_configs.h" + ], + "excluded_modules": [ + "one_wire", + "nfc", + "lfrfid", + "subghz", + "infrared", + "st25rfal002" + ] +} \ No newline at end of file diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 42ea150df..adca3b714 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,12.3,, +Version,+,14.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -42,14 +42,19 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_types.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_ibutton.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_nfc.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_config.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_types.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_subghz.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_target_hw.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_uart.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h,, Header,+,firmware/targets/f7/platform_specific/intrinsic_export.h,, @@ -62,22 +67,18 @@ Header,+,firmware/targets/furi_hal_include/furi_hal_cortex.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_crypto.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_debug.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_i2c.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_ibutton.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_info.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_infrared.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_light.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_memory.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_mpu.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_nfc.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_power.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_random.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_region.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_rfid.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_rtc.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_sd.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_subghz.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, @@ -153,6 +154,16 @@ Header,+,lib/libusb_stm32/inc/usbd_core.h,, Header,+,lib/mbedtls/include/mbedtls/des.h,, Header,+,lib/mbedtls/include/mbedtls/sha1.h,, Header,+,lib/micro-ecc/uECC.h,, +Header,+,lib/mlib/m-algo.h,, +Header,+,lib/mlib/m-array.h,, +Header,+,lib/mlib/m-bptree.h,, +Header,+,lib/mlib/m-core.h,, +Header,+,lib/mlib/m-deque.h,, +Header,+,lib/mlib/m-dict.h,, +Header,+,lib/mlib/m-list.h,, +Header,+,lib/mlib/m-rbtree.h,, +Header,+,lib/mlib/m-tuple.h,, +Header,+,lib/mlib/m-variant.h,, Header,+,lib/nfc/nfc_device.h,, Header,+,lib/one_wire/ibutton/ibutton_worker.h,, Header,+,lib/one_wire/maxim_crc.h,, @@ -194,7 +205,6 @@ Header,+,lib/toolbox/stream/string_stream.h,, Header,+,lib/toolbox/tar/tar_archive.h,, Header,+,lib/toolbox/value_index.h,, Header,+,lib/toolbox/version.h,, -Header,+,lib/u8g2/u8g2.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, LL_ADC_CommonInitTypeDef*" Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* @@ -569,11 +579,20 @@ Function,+,ble_glue_start,_Bool, Function,+,ble_glue_thread_stop,void, Function,+,ble_glue_wait_for_c2_start,_Bool,int32_t Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_t" +Function,+,bt_disable_peer_key_update,void,Bt* Function,+,bt_disconnect,void,Bt* +Function,+,bt_enable_peer_key_update,void,Bt* Function,+,bt_forget_bonded_devices,void,Bt* +Function,+,bt_get_profile_adv_name,const char*,Bt* +Function,+,bt_get_profile_mac_address,const uint8_t*,Bt* +Function,+,bt_get_profile_pairing_method,GapPairing,Bt* Function,+,bt_keys_storage_set_default_path,void,Bt* Function,+,bt_keys_storage_set_storage_path,void,"Bt*, const char*" +Function,+,bt_remote_rssi,_Bool,"Bt*, BtRssi*" Function,+,bt_set_profile,_Bool,"Bt*, BtProfile" +Function,+,bt_set_profile_adv_name,void,"Bt*, const char*, ..." +Function,+,bt_set_profile_mac_address,void,"Bt*, const uint8_t[6]" +Function,+,bt_set_profile_pairing_method,void,"Bt*, GapPairing" Function,+,bt_set_status_changed_callback,void,"Bt*, BtStatusChangedCallback, void*" Function,+,buffered_file_stream_alloc,Stream*,Storage* Function,+,buffered_file_stream_close,_Bool,Stream* @@ -635,6 +654,7 @@ Function,+,canvas_invert_color,void,Canvas* Function,+,canvas_reset,void,Canvas* Function,+,canvas_set_bitmap_mode,void,"Canvas*, _Bool" Function,+,canvas_set_color,void,"Canvas*, Color" +Function,+,canvas_set_custom_u8g2_font,void,"Canvas*, const uint8_t*" Function,+,canvas_set_font,void,"Canvas*, Font" Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" Function,-,canvas_set_orientation,void,"Canvas*, CanvasOrientation" @@ -877,6 +897,7 @@ Function,+,flipper_application_free,void,FlipperApplication* Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,FlipperApplication* Function,+,flipper_application_load_status_to_string,const char*,FlipperApplicationLoadStatus Function,+,flipper_application_manifest_is_compatible,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*" +Function,+,flipper_application_manifest_is_target_compatible,_Bool,const FlipperApplicationManifest* Function,+,flipper_application_manifest_is_valid,_Bool,const FlipperApplicationManifest* Function,+,flipper_application_map_to_memory,FlipperApplicationLoadStatus,FlipperApplication* Function,+,flipper_application_preload,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" @@ -995,13 +1016,18 @@ Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, voi Function,+,furi_hal_bt_clear_white_list,_Bool, Function,+,furi_hal_bt_dump_state,void,FuriString* Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode +Function,+,furi_hal_bt_get_conn_rssi,uint32_t,uint8_t* Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" +Function,+,furi_hal_bt_get_profile_adv_name,const char*,FuriHalBtProfile +Function,+,furi_hal_bt_get_profile_mac_addr,const uint8_t*,FuriHalBtProfile +Function,+,furi_hal_bt_get_profile_pairing_method,GapPairing,FuriHalBtProfile Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, Function,+,furi_hal_bt_get_rssi,float, Function,+,furi_hal_bt_get_transmitted_packets,uint32_t, Function,+,furi_hal_bt_hid_consumer_key_press,_Bool,uint16_t Function,+,furi_hal_bt_hid_consumer_key_release,_Bool,uint16_t Function,+,furi_hal_bt_hid_consumer_key_release_all,_Bool, +Function,+,furi_hal_bt_hid_get_led_state,uint8_t, Function,+,furi_hal_bt_hid_kb_press,_Bool,uint16_t Function,+,furi_hal_bt_hid_kb_release,_Bool,uint16_t Function,+,furi_hal_bt_hid_kb_release_all,_Bool, @@ -1016,6 +1042,7 @@ Function,-,furi_hal_bt_init,void, Function,+,furi_hal_bt_is_active,_Bool, Function,+,furi_hal_bt_is_alive,_Bool, Function,+,furi_hal_bt_is_ble_gatt_gap_supported,_Bool, +Function,+,furi_hal_bt_is_connected,_Bool, Function,+,furi_hal_bt_is_testing_supported,_Bool, Function,+,furi_hal_bt_lock_core2,void, Function,+,furi_hal_bt_nvm_sram_sem_acquire,void, @@ -1028,6 +1055,9 @@ Function,+,furi_hal_bt_serial_start,void, Function,+,furi_hal_bt_serial_stop,void, Function,+,furi_hal_bt_serial_tx,_Bool,"uint8_t*, uint16_t" Function,+,furi_hal_bt_set_key_storage_change_callback,void,"BleGlueKeyStorageChangedCallback, void*" +Function,+,furi_hal_bt_set_profile_adv_name,void,"FuriHalBtProfile, const char[( 1 + ( 8 + 1 ) ) + 9 - 1]" +Function,+,furi_hal_bt_set_profile_mac_addr,void,"FuriHalBtProfile, const uint8_t[( 6 )]" +Function,+,furi_hal_bt_set_profile_pairing_method,void,"FuriHalBtProfile, GapPairing" Function,+,furi_hal_bt_start_advertising,void, Function,+,furi_hal_bt_start_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*" Function,+,furi_hal_bt_start_packet_rx,void,"uint8_t, uint8_t" @@ -1047,7 +1077,7 @@ Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" Function,+,furi_hal_cdc_send,void,"uint8_t, uint8_t*, uint16_t" Function,+,furi_hal_cdc_set_callbacks,void,"uint8_t, CdcCallbacks*, void*" -Function,+,furi_hal_clock_deinit_early,void, +Function,-,furi_hal_clock_deinit_early,void, Function,-,furi_hal_clock_init,void, Function,-,furi_hal_clock_init_early,void, Function,+,furi_hal_clock_mco_disable,void, @@ -1128,7 +1158,7 @@ Function,+,furi_hal_hid_u2f_is_connected,_Bool, Function,+,furi_hal_hid_u2f_send_response,void,"uint8_t*, uint8_t" Function,+,furi_hal_hid_u2f_set_callback,void,"HidU2fCallback, void*" Function,+,furi_hal_i2c_acquire,void,FuriHalI2cBusHandle* -Function,+,furi_hal_i2c_deinit_early,void, +Function,-,furi_hal_i2c_deinit_early,void, Function,-,furi_hal_i2c_init,void, Function,-,furi_hal_i2c_init_early,void, Function,+,furi_hal_i2c_is_device_ready,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint32_t" @@ -1266,7 +1296,8 @@ Function,+,furi_hal_region_init,void, Function,+,furi_hal_region_is_frequency_allowed,_Bool,uint32_t Function,+,furi_hal_region_is_provisioned,_Bool, Function,+,furi_hal_region_set,void,FuriHalRegion* -Function,+,furi_hal_resources_deinit_early,void, +Function,-,furi_hal_resources_deinit_early,void, +Function,+,furi_hal_resources_get_ext_pin_number,int32_t,const GpioPin* Function,-,furi_hal_resources_init,void, Function,-,furi_hal_resources_init_early,void, Function,+,furi_hal_rfid_change_read_config,void,"float, float" @@ -1295,7 +1326,7 @@ Function,+,furi_hal_rfid_tim_read_start,void, Function,+,furi_hal_rfid_tim_read_stop,void, Function,+,furi_hal_rfid_tim_reset,void, Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* -Function,+,furi_hal_rtc_deinit_early,void, +Function,-,furi_hal_rtc_deinit_early,void, Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime* Function,+,furi_hal_rtc_get_fault_data,uint32_t, @@ -1337,19 +1368,26 @@ Function,+,furi_hal_spi_bus_handle_deinit,void,FuriHalSpiBusHandle* Function,+,furi_hal_spi_bus_handle_init,void,FuriHalSpiBusHandle* Function,+,furi_hal_spi_bus_init,void,FuriHalSpiBus* Function,+,furi_hal_spi_bus_rx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, uint32_t" -Function,+,furi_hal_spi_bus_trx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, uint8_t*, size_t, uint32_t" -Function,+,furi_hal_spi_bus_tx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, uint32_t" -Function,+,furi_hal_spi_deinit_early,void, -Function,-,furi_hal_spi_init,void, -Function,+,furi_hal_spi_init_early,void, +Function,+,furi_hal_spi_bus_trx,_Bool,"FuriHalSpiBusHandle*, const uint8_t*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_trx_dma,_Bool,"FuriHalSpiBusHandle*, uint8_t*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_tx,_Bool,"FuriHalSpiBusHandle*, const uint8_t*, size_t, uint32_t" +Function,-,furi_hal_spi_config_deinit_early,void, +Function,-,furi_hal_spi_config_init,void, +Function,-,furi_hal_spi_config_init_early,void, +Function,+,furi_hal_spi_dma_init,void, Function,+,furi_hal_spi_release,void,FuriHalSpiBusHandle* +Function,+,furi_hal_subghz_check_radio,_Bool, +Function,+,furi_hal_subghz_disable_ext_power,void, Function,-,furi_hal_subghz_dump_state,void, +Function,+,furi_hal_subghz_enable_ext_power,void, Function,+,furi_hal_subghz_flush_rx,void, Function,+,furi_hal_subghz_flush_tx,void, Function,+,furi_hal_subghz_get_lqi,uint8_t, +Function,+,furi_hal_subghz_get_radio_type,SubGhzRadioType, Function,+,furi_hal_subghz_get_rssi,float, Function,+,furi_hal_subghz_idle,void, Function,-,furi_hal_subghz_init,void, +Function,+,furi_hal_subghz_init_check,_Bool, Function,+,furi_hal_subghz_is_async_tx_complete,_Bool, Function,+,furi_hal_subghz_is_frequency_valid,_Bool,uint32_t Function,+,furi_hal_subghz_is_rx_data_crc_valid,_Bool, @@ -1366,6 +1404,7 @@ Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin* Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath +Function,+,furi_hal_subghz_set_radio_type,_Bool,SubGhzRadioType Function,-,furi_hal_subghz_shutdown,void, Function,+,furi_hal_subghz_sleep,void, Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" @@ -1396,6 +1435,7 @@ Function,+,furi_hal_version_do_i_belong_here,_Bool, Function,+,furi_hal_version_get_ble_local_device_name_ptr,const char*, Function,+,furi_hal_version_get_ble_mac,const uint8_t*, Function,+,furi_hal_version_get_device_name_ptr,const char*, +Function,+,furi_hal_version_get_fcc_id,const char*, Function,+,furi_hal_version_get_firmware_version,const Version*, Function,+,furi_hal_version_get_hw_body,uint8_t, Function,+,furi_hal_version_get_hw_color,FuriHalVersionColor, @@ -1406,6 +1446,8 @@ Function,+,furi_hal_version_get_hw_region_name,const char*, Function,+,furi_hal_version_get_hw_target,uint8_t, Function,+,furi_hal_version_get_hw_timestamp,uint32_t, Function,+,furi_hal_version_get_hw_version,uint8_t, +Function,+,furi_hal_version_get_ic_id,const char*, +Function,+,furi_hal_version_get_model_code,const char*, Function,+,furi_hal_version_get_model_name,const char*, Function,+,furi_hal_version_get_name_ptr,const char*, Function,+,furi_hal_version_get_otp_version,FuriHalVersionOtpVersion, @@ -1417,6 +1459,7 @@ Function,-,furi_hal_vibro_init,void, Function,+,furi_hal_vibro_on,void,_Bool Function,-,furi_init,void, Function,+,furi_kernel_get_tick_frequency,uint32_t, +Function,+,furi_kernel_is_irq_or_masked,_Bool, Function,+,furi_kernel_lock,int32_t, Function,+,furi_kernel_restore_lock,int32_t,int32_t Function,+,furi_kernel_unlock,int32_t, @@ -1541,6 +1584,7 @@ Function,+,furi_thread_get_name,const char*,FuriThreadId Function,+,furi_thread_get_return_code,int32_t,FuriThread* Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId Function,+,furi_thread_get_state,FuriThreadState,FuriThread* +Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback, Function,+,furi_thread_is_suspended,_Bool,FuriThreadId Function,+,furi_thread_join,_Bool,FuriThread* Function,+,furi_thread_mark_as_service,void,FuriThread* @@ -1569,6 +1613,7 @@ Function,-,gamma,double,double Function,-,gamma_r,double,"double, int*" Function,-,gammaf,float,float Function,-,gammaf_r,float,"float, int*" +Function,+,gap_get_remote_conn_rssi,uint32_t,int8_t* Function,-,gap_get_state,GapState, Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*" Function,-,gap_start_advertising,void, @@ -1893,8 +1938,10 @@ Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, MfClassicAuthContext*, uint64_t" Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" +Function,-,mf_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" Function,-,mf_classic_authenticate_skip_activate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey, _Bool, uint32_t" +Function,-,mf_classic_block_to_value,_Bool,"const uint8_t*, int32_t*, uint8_t*" Function,-,mf_classic_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" Function,-,mf_classic_dict_add_key,_Bool,"MfClassicDict*, uint8_t*" Function,-,mf_classic_dict_add_key_str,_Bool,"MfClassicDict*, FuriString*" @@ -1921,6 +1968,7 @@ Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfCl Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType Function,-,mf_classic_get_type_str,const char*,MfClassicType +Function,-,mf_classic_halt,void,"FuriHalNfcTxRxContext*, Crypto1*" Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" Function,-,mf_classic_is_allowed_access_sector_trailer,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" Function,-,mf_classic_is_block_read,_Bool,"MfClassicData*, uint8_t" @@ -1929,6 +1977,8 @@ Function,-,mf_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKey" Function,-,mf_classic_is_sector_data_read,_Bool,"MfClassicData*, uint8_t" Function,-,mf_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t" Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t +Function,-,mf_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" +Function,-,mf_classic_read_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" Function,-,mf_classic_read_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicReader*, MfClassicData*" Function,-,mf_classic_read_sector,void,"FuriHalNfcTxRxContext*, MfClassicData*, uint8_t" Function,-,mf_classic_reader_add_sector,void,"MfClassicReader*, uint8_t, uint64_t, uint64_t" @@ -1936,8 +1986,12 @@ Function,-,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlo Function,-,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKey, uint64_t" Function,-,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKey" Function,-,mf_classic_set_sector_data_not_read,void,MfClassicData* +Function,-,mf_classic_transfer,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t" Function,-,mf_classic_update_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicData*" -Function,-,mf_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" +Function,-,mf_classic_value_cmd,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, uint8_t, int32_t" +Function,-,mf_classic_value_cmd_full,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t, int32_t" +Function,-,mf_classic_value_to_block,void,"int32_t, uint8_t, uint8_t*" +Function,-,mf_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" Function,-,mf_classic_write_sector,_Bool,"FuriHalNfcTxRxContext*, MfClassicData*, MfClassicData*, uint8_t" Function,-,mf_df_cat_application,void,"MifareDesfireApplication*, FuriString*" Function,-,mf_df_cat_application_info,void,"MifareDesfireApplication*, FuriString*" @@ -2051,9 +2105,10 @@ Function,+,nfc_device_save_shadow,_Bool,"NfcDevice*, const char*" Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*" Function,+,nfc_device_set_name,void,"NfcDevice*, const char*" Function,+,nfc_file_select,_Bool,NfcDevice* -Function,-,nfc_util_bytes2num,uint64_t,"uint8_t*, uint8_t" +Function,-,nfc_util_bytes2num,uint64_t,"const uint8_t*, uint8_t" Function,-,nfc_util_even_parity32,uint8_t,uint32_t Function,-,nfc_util_num2bytes,void,"uint64_t, uint8_t, uint8_t*" +Function,-,nfc_util_odd_parity,void,"const uint8_t*, uint8_t*, uint8_t" Function,-,nfc_util_odd_parity8,uint8_t,uint8_t Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" @@ -2138,7 +2193,7 @@ Function,-,posix_memalign,int,"void**, size_t, size_t" Function,-,pow,double,"double, double" Function,-,pow10,double,double Function,-,pow10f,float,float -Function,-,power_enable_low_battery_level_notification,void,"Power*, _Bool" +Function,+,power_enable_low_battery_level_notification,void,"Power*, _Bool" Function,+,power_get_info,void,"Power*, PowerInfo*" Function,+,power_get_pubsub,FuriPubSub*,Power* Function,+,power_get_settings_events_pubsub,FuriPubSub*,Power* @@ -2625,12 +2680,14 @@ Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*" Function,+,subghz_block_generic_serialize,_Bool,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*" Function,+,subghz_environment_alloc,SubGhzEnvironment*, Function,+,subghz_environment_free,void,SubGhzEnvironment* +Function,+,subghz_environment_get_alutech_at_4n_rainbow_table_file_name,const char*,SubGhzEnvironment* Function,+,subghz_environment_get_came_atomo_rainbow_table_file_name,const char*,SubGhzEnvironment* Function,+,subghz_environment_get_keystore,SubGhzKeystore*,SubGhzEnvironment* Function,+,subghz_environment_get_nice_flor_s_rainbow_table_file_name,const char*,SubGhzEnvironment* Function,+,subghz_environment_get_protocol_name_registry,const char*,"SubGhzEnvironment*, size_t" Function,+,subghz_environment_get_protocol_registry,void*,SubGhzEnvironment* Function,+,subghz_environment_load_keystore,_Bool,"SubGhzEnvironment*, const char*" +Function,+,subghz_environment_set_alutech_at_4n_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" Function,+,subghz_environment_set_came_atomo_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" Function,+,subghz_environment_set_nice_flor_s_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" Function,+,subghz_environment_set_protocol_registry,void,"SubGhzEnvironment*, void*" @@ -2641,6 +2698,7 @@ Function,-,subghz_keystore_load,_Bool,"SubGhzKeystore*, const char*" Function,-,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, uint8_t*" Function,-,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" Function,-,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" +Function,-,subghz_protocol_alutech_at_4n_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" Function,+,subghz_protocol_blocks_add_bytes,uint8_t,"const uint8_t[], size_t" Function,+,subghz_protocol_blocks_add_to_128_bit,void,"SubGhzBlockDecoder*, uint8_t, uint64_t*" @@ -2653,7 +2711,7 @@ Function,+,subghz_protocol_blocks_crc8le,uint8_t,"const uint8_t[], size_t, uint8 Function,+,subghz_protocol_blocks_get_bit_array,_Bool,"uint8_t[], size_t" Function,+,subghz_protocol_blocks_get_hash_data,uint8_t,"SubGhzBlockDecoder*, size_t" Function,+,subghz_protocol_blocks_get_parity,uint8_t,"uint64_t, uint8_t" -Function,+,subghz_protocol_blocks_get_upload,size_t,"uint8_t[], size_t, LevelDuration*, size_t, uint32_t" +Function,+,subghz_protocol_blocks_get_upload_from_bit_array,size_t,"uint8_t[], size_t, LevelDuration*, size_t, uint32_t, SubGhzProtocolBlockAlignBit" Function,+,subghz_protocol_blocks_lfsr_digest16,uint16_t,"const uint8_t[], size_t, uint16_t, uint16_t" Function,+,subghz_protocol_blocks_lfsr_digest8,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" Function,+,subghz_protocol_blocks_lfsr_digest8_reflect,uint8_t,"const uint8_t[], size_t, uint8_t, uint8_t" @@ -2662,6 +2720,14 @@ Function,+,subghz_protocol_blocks_parity_bytes,uint8_t,"const uint8_t[], size_t" Function,+,subghz_protocol_blocks_reverse_key,uint64_t,"uint64_t, uint8_t" Function,+,subghz_protocol_blocks_set_bit_array,void,"_Bool, uint8_t[], size_t, size_t" Function,+,subghz_protocol_blocks_xor_bytes,uint8_t,"const uint8_t[], size_t" +Function,-,subghz_protocol_decoder_alutech_at_4n_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_decoder_alutech_at_4n_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_decoder_alutech_at_4n_feed,void,"void*, _Bool, uint32_t" +Function,-,subghz_protocol_decoder_alutech_at_4n_free,void,void* +Function,-,subghz_protocol_decoder_alutech_at_4n_get_hash_data,uint8_t,void* +Function,-,subghz_protocol_decoder_alutech_at_4n_get_string,void,"void*, FuriString*" +Function,-,subghz_protocol_decoder_alutech_at_4n_reset,void,void* +Function,-,subghz_protocol_decoder_alutech_at_4n_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_decoder_ansonic_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_decoder_ansonic_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_decoder_ansonic_feed,void,"void*, _Bool, uint32_t" @@ -2670,7 +2736,7 @@ Function,-,subghz_protocol_decoder_ansonic_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_ansonic_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_ansonic_reset,void,void* Function,-,subghz_protocol_decoder_ansonic_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" -Function,+,subghz_protocol_decoder_base_deserialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*" +Function,-,subghz_protocol_decoder_base_deserialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*" Function,+,subghz_protocol_decoder_base_get_hash_data,uint8_t,SubGhzProtocolDecoderBase* Function,+,subghz_protocol_decoder_base_get_string,_Bool,"SubGhzProtocolDecoderBase*, FuriString*" Function,+,subghz_protocol_decoder_base_serialize,_Bool,"SubGhzProtocolDecoderBase*, FlipperFormat*, SubGhzRadioPreset*" @@ -2683,6 +2749,15 @@ Function,-,subghz_protocol_decoder_bett_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_bett_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_bett_reset,void,void* Function,-,subghz_protocol_decoder_bett_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" +Function,-,subghz_protocol_decoder_bin_raw_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_decoder_bin_raw_data_input_rssi,void,"SubGhzProtocolDecoderBinRAW*, float" +Function,-,subghz_protocol_decoder_bin_raw_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_decoder_bin_raw_feed,void,"void*, _Bool, uint32_t" +Function,-,subghz_protocol_decoder_bin_raw_free,void,void* +Function,-,subghz_protocol_decoder_bin_raw_get_hash_data,uint8_t,void* +Function,-,subghz_protocol_decoder_bin_raw_get_string,void,"void*, FuriString*" +Function,-,subghz_protocol_decoder_bin_raw_reset,void,void* +Function,-,subghz_protocol_decoder_bin_raw_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_decoder_came_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_decoder_came_atomo_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_decoder_came_atomo_deserialize,_Bool,"void*, FlipperFormat*" @@ -2731,6 +2806,14 @@ Function,-,subghz_protocol_decoder_doitrand_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_doitrand_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_doitrand_reset,void,void* Function,-,subghz_protocol_decoder_doitrand_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" +Function,-,subghz_protocol_decoder_dooya_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_decoder_dooya_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_decoder_dooya_feed,void,"void*, _Bool, uint32_t" +Function,-,subghz_protocol_decoder_dooya_free,void,void* +Function,-,subghz_protocol_decoder_dooya_get_hash_data,uint8_t,void* +Function,-,subghz_protocol_decoder_dooya_get_string,void,"void*, FuriString*" +Function,-,subghz_protocol_decoder_dooya_reset,void,void* +Function,-,subghz_protocol_decoder_dooya_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_decoder_faac_slh_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_decoder_faac_slh_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_decoder_faac_slh_feed,void,"void*, _Bool, uint32_t" @@ -2811,7 +2894,23 @@ Function,-,subghz_protocol_decoder_kia_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_kia_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_kia_reset,void,void* Function,-,subghz_protocol_decoder_kia_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" +Function,-,subghz_protocol_decoder_kinggates_stylo_4k_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_decoder_kinggates_stylo_4k_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_decoder_kinggates_stylo_4k_feed,void,"void*, _Bool, uint32_t" +Function,-,subghz_protocol_decoder_kinggates_stylo_4k_free,void,void* +Function,-,subghz_protocol_decoder_kinggates_stylo_4k_get_hash_data,uint8_t,void* +Function,-,subghz_protocol_decoder_kinggates_stylo_4k_get_string,void,"void*, FuriString*" +Function,-,subghz_protocol_decoder_kinggates_stylo_4k_reset,void,void* +Function,-,subghz_protocol_decoder_kinggates_stylo_4k_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_decoder_linear_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_decoder_linear_delta3_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_decoder_linear_delta3_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_decoder_linear_delta3_feed,void,"void*, _Bool, uint32_t" +Function,-,subghz_protocol_decoder_linear_delta3_free,void,void* +Function,-,subghz_protocol_decoder_linear_delta3_get_hash_data,uint8_t,void* +Function,-,subghz_protocol_decoder_linear_delta3_get_string,void,"void*, FuriString*" +Function,-,subghz_protocol_decoder_linear_delta3_reset,void,void* +Function,-,subghz_protocol_decoder_linear_delta3_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_decoder_linear_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_decoder_linear_feed,void,"void*, _Bool, uint32_t" Function,-,subghz_protocol_decoder_linear_free,void,void* @@ -2903,13 +3002,8 @@ Function,+,subghz_protocol_decoder_raw_alloc,void*,SubGhzEnvironment* Function,+,subghz_protocol_decoder_raw_deserialize,_Bool,"void*, FlipperFormat*" Function,+,subghz_protocol_decoder_raw_feed,void,"void*, _Bool, uint32_t" Function,+,subghz_protocol_decoder_raw_free,void,void* -Function,+,subghz_protocol_decoder_raw_get_hash_data,uint8_t,void* Function,+,subghz_protocol_decoder_raw_get_string,void,"void*, FuriString*" Function,+,subghz_protocol_decoder_raw_reset,void,void* -Function,+,subghz_protocol_decoder_raw_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" -Function,+,subghz_protocol_decoder_raw_set_auto_mode,void,"void*, _Bool" -Function,+,subghz_protocol_decoder_raw_set_rssi_threshold,void,"void*, int" -Function,+,subghz_protocol_decoder_raw_write_data,_Bool,"void*, _Bool, uint32_t" Function,-,subghz_protocol_decoder_scher_khan_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_decoder_scher_khan_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_decoder_scher_khan_feed,void,"void*, _Bool, uint32_t" @@ -2966,6 +3060,11 @@ Function,-,subghz_protocol_decoder_star_line_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_star_line_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_star_line_reset,void,void* Function,-,subghz_protocol_decoder_star_line_serialize,_Bool,"void*, FlipperFormat*, SubGhzRadioPreset*" +Function,-,subghz_protocol_encoder_alutech_at_4n_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_alutech_at_4n_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_encoder_alutech_at_4n_free,void,void* +Function,-,subghz_protocol_encoder_alutech_at_4n_stop,void,void* +Function,-,subghz_protocol_encoder_alutech_at_4n_yield,LevelDuration,void* Function,-,subghz_protocol_encoder_ansonic_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_ansonic_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_encoder_ansonic_free,void,void* @@ -2976,6 +3075,11 @@ Function,-,subghz_protocol_encoder_bett_deserialize,_Bool,"void*, FlipperFormat* Function,-,subghz_protocol_encoder_bett_free,void,void* Function,-,subghz_protocol_encoder_bett_stop,void,void* Function,-,subghz_protocol_encoder_bett_yield,LevelDuration,void* +Function,-,subghz_protocol_encoder_bin_raw_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_bin_raw_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_encoder_bin_raw_free,void,void* +Function,-,subghz_protocol_encoder_bin_raw_stop,void,void* +Function,-,subghz_protocol_encoder_bin_raw_yield,LevelDuration,void* Function,-,subghz_protocol_encoder_came_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_came_atomo_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_came_atomo_deserialize,_Bool,"void*, FlipperFormat*" @@ -3006,6 +3110,11 @@ Function,-,subghz_protocol_encoder_doitrand_deserialize,_Bool,"void*, FlipperFor Function,-,subghz_protocol_encoder_doitrand_free,void,void* Function,-,subghz_protocol_encoder_doitrand_stop,void,void* Function,-,subghz_protocol_encoder_doitrand_yield,LevelDuration,void* +Function,-,subghz_protocol_encoder_dooya_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_dooya_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_encoder_dooya_free,void,void* +Function,-,subghz_protocol_encoder_dooya_stop,void,void* +Function,-,subghz_protocol_encoder_dooya_yield,LevelDuration,void* Function,-,subghz_protocol_encoder_faac_slh_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_faac_slh_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_encoder_faac_slh_free,void,void* @@ -3016,7 +3125,6 @@ Function,-,subghz_protocol_encoder_gate_tx_deserialize,_Bool,"void*, FlipperForm Function,-,subghz_protocol_encoder_gate_tx_free,void,void* Function,-,subghz_protocol_encoder_gate_tx_stop,void,void* Function,-,subghz_protocol_encoder_gate_tx_yield,LevelDuration,void* -Function,-,subghz_protocol_encoder_get_rssi_threshold,int,void* Function,-,subghz_protocol_encoder_holtek_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_holtek_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_encoder_holtek_free,void,void* @@ -3047,7 +3155,17 @@ Function,-,subghz_protocol_encoder_keeloq_deserialize,_Bool,"void*, FlipperForma Function,-,subghz_protocol_encoder_keeloq_free,void,void* Function,-,subghz_protocol_encoder_keeloq_stop,void,void* Function,-,subghz_protocol_encoder_keeloq_yield,LevelDuration,void* +Function,-,subghz_protocol_encoder_kinggates_stylo_4k_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_kinggates_stylo_4k_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_encoder_kinggates_stylo_4k_free,void,void* +Function,-,subghz_protocol_encoder_kinggates_stylo_4k_stop,void,void* +Function,-,subghz_protocol_encoder_kinggates_stylo_4k_yield,LevelDuration,void* Function,-,subghz_protocol_encoder_linear_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_linear_delta3_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_linear_delta3_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_encoder_linear_delta3_free,void,void* +Function,-,subghz_protocol_encoder_linear_delta3_stop,void,void* +Function,-,subghz_protocol_encoder_linear_delta3_yield,LevelDuration,void* Function,-,subghz_protocol_encoder_linear_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_encoder_linear_free,void,void* Function,-,subghz_protocol_encoder_linear_stop,void,void* @@ -3122,6 +3240,16 @@ Function,-,subghz_protocol_encoder_smc5326_deserialize,_Bool,"void*, FlipperForm Function,-,subghz_protocol_encoder_smc5326_free,void,void* Function,-,subghz_protocol_encoder_smc5326_stop,void,void* Function,-,subghz_protocol_encoder_smc5326_yield,LevelDuration,void* +Function,-,subghz_protocol_encoder_somfy_keytis_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_somfy_keytis_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_encoder_somfy_keytis_free,void,void* +Function,-,subghz_protocol_encoder_somfy_keytis_stop,void,void* +Function,-,subghz_protocol_encoder_somfy_keytis_yield,LevelDuration,void* +Function,-,subghz_protocol_encoder_somfy_telis_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_somfy_telis_deserialize,_Bool,"void*, FlipperFormat*" +Function,-,subghz_protocol_encoder_somfy_telis_free,void,void* +Function,-,subghz_protocol_encoder_somfy_telis_stop,void,void* +Function,-,subghz_protocol_encoder_somfy_telis_yield,LevelDuration,void* Function,-,subghz_protocol_encoder_star_line_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_star_line_deserialize,_Bool,"void*, FlipperFormat*" Function,-,subghz_protocol_encoder_star_line_free,void,void* @@ -3143,11 +3271,12 @@ Function,+,subghz_protocol_registry_get_by_index,const SubGhzProtocol*,"const Su Function,+,subghz_protocol_registry_get_by_name,const SubGhzProtocol*,"const SubGhzProtocolRegistry*, const char*" Function,-,subghz_protocol_secplus_v1_check_fixed,_Bool,uint32_t Function,-,subghz_protocol_secplus_v2_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, SubGhzRadioPreset*" +Function,-,subghz_protocol_somfy_keytis_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" +Function,-,subghz_protocol_somfy_telis_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" Function,-,subghz_protocol_star_line_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*" Function,+,subghz_receiver_alloc_init,SubGhzReceiver*,SubGhzEnvironment* Function,+,subghz_receiver_decode,void,"SubGhzReceiver*, _Bool, uint32_t" Function,+,subghz_receiver_free,void,SubGhzReceiver* -Function,+,subghz_receiver_get_filter,SubGhzProtocolFlag,SubGhzReceiver* Function,+,subghz_receiver_reset,void,SubGhzReceiver* Function,+,subghz_receiver_search_decoder_base_by_name,SubGhzProtocolDecoderBase*,"SubGhzReceiver*, const char*" Function,+,subghz_receiver_set_filter,void,"SubGhzReceiver*, SubGhzProtocolFlag" @@ -4342,8 +4471,8 @@ Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint Function,-,ucStreamBufferGetStreamBufferType,uint8_t,StreamBufferHandle_t Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t" Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t" -Function,-,ulTaskGetIdleRunTimeCounter,configRUN_TIME_COUNTER_TYPE, -Function,-,ulTaskGetIdleRunTimePercent,configRUN_TIME_COUNTER_TYPE, +Function,-,ulTaskGetIdleRunTimeCounter,uint32_t, +Function,-,ulTaskGetIdleRunTimePercent,uint32_t, Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* Function,-,usbd_poll,void,usbd_device* @@ -4354,7 +4483,7 @@ Function,-,uxStreamBufferGetStreamBufferNumber,UBaseType_t,StreamBufferHandle_t Function,-,uxTaskGetNumberOfTasks,UBaseType_t, Function,-,uxTaskGetStackHighWaterMark,UBaseType_t,TaskHandle_t Function,-,uxTaskGetStackHighWaterMark2,uint16_t,TaskHandle_t -Function,-,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, configRUN_TIME_COUNTER_TYPE*" +Function,+,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, uint32_t*" Function,-,uxTaskGetTaskNumber,UBaseType_t,TaskHandle_t Function,+,uxTaskPriorityGet,UBaseType_t,const TaskHandle_t Function,-,uxTaskPriorityGetFromISR,UBaseType_t,const TaskHandle_t @@ -4605,12 +4734,15 @@ Variable,+,furi_hal_spi_bus_handle_nfc,FuriHalSpiBusHandle, Variable,+,furi_hal_spi_bus_handle_sd_fast,FuriHalSpiBusHandle, Variable,+,furi_hal_spi_bus_handle_sd_slow,FuriHalSpiBusHandle, Variable,+,furi_hal_spi_bus_handle_subghz,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_subghz_ext,FuriHalSpiBusHandle, +Variable,+,furi_hal_spi_bus_handle_subghz_int,FuriHalSpiBusHandle, Variable,+,furi_hal_spi_bus_r,FuriHalSpiBus, Variable,+,furi_hal_spi_preset_1edge_low_16m,const LL_SPI_InitTypeDef, Variable,+,furi_hal_spi_preset_1edge_low_2m,const LL_SPI_InitTypeDef, Variable,+,furi_hal_spi_preset_1edge_low_4m,const LL_SPI_InitTypeDef, Variable,+,furi_hal_spi_preset_1edge_low_8m,const LL_SPI_InitTypeDef, Variable,+,furi_hal_spi_preset_2edge_low_8m,const LL_SPI_InitTypeDef, +Variable,+,furi_hal_subghz,volatile FuriHalSubGhz, Variable,+,gpio_button_back,const GpioPin, Variable,+,gpio_button_down,const GpioPin, Variable,+,gpio_button_left,const GpioPin, @@ -4618,6 +4750,7 @@ Variable,+,gpio_button_ok,const GpioPin, Variable,+,gpio_button_right,const GpioPin, Variable,+,gpio_button_up,const GpioPin, Variable,+,gpio_cc1101_g0,const GpioPin, +Variable,+,gpio_cc1101_g0_ext,const GpioPin, Variable,+,gpio_display_cs,const GpioPin, Variable,+,gpio_display_di,const GpioPin, Variable,+,gpio_display_rst_n,const GpioPin, @@ -4635,6 +4768,8 @@ Variable,+,gpio_infrared_rx,const GpioPin, Variable,+,gpio_infrared_tx,const GpioPin, Variable,+,gpio_nfc_cs,const GpioPin, Variable,+,gpio_nfc_irq_rfid_pull,const GpioPin, +Variable,+,gpio_pins,const GpioPinRecord[], +Variable,+,gpio_pins_count,const size_t, Variable,+,gpio_rf_sw_0,const GpioPin, Variable,+,gpio_rfid_carrier,const GpioPin, Variable,+,gpio_rfid_carrier_out,const GpioPin, @@ -4646,9 +4781,13 @@ Variable,+,gpio_spi_d_miso,const GpioPin, Variable,+,gpio_spi_d_mosi,const GpioPin, Variable,+,gpio_spi_d_sck,const GpioPin, Variable,+,gpio_spi_r_miso,const GpioPin, +Variable,+,gpio_spi_r_miso_ext,const GpioPin, Variable,+,gpio_spi_r_mosi,const GpioPin, +Variable,+,gpio_spi_r_mosi_ext,const GpioPin, Variable,+,gpio_spi_r_sck,const GpioPin, +Variable,+,gpio_spi_r_sck_ext,const GpioPin, Variable,+,gpio_subghz_cs,const GpioPin, +Variable,+,gpio_subghz_cs_ext,const GpioPin, Variable,+,gpio_usart_rx,const GpioPin, Variable,+,gpio_usart_tx,const GpioPin, Variable,+,gpio_usb_dm,const GpioPin, @@ -4851,12 +4990,18 @@ Variable,+,sequence_set_vibro_on,const NotificationSequence, Variable,+,sequence_single_vibro,const NotificationSequence, Variable,+,sequence_solid_yellow,const NotificationSequence, Variable,+,sequence_success,const NotificationSequence, +Variable,-,subghz_protocol_alutech_at_4n,const SubGhzProtocol, +Variable,-,subghz_protocol_alutech_at_4n_decoder,const SubGhzProtocolDecoder, +Variable,-,subghz_protocol_alutech_at_4n_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_ansonic,const SubGhzProtocol, Variable,-,subghz_protocol_ansonic_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_ansonic_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_bett,const SubGhzProtocol, Variable,-,subghz_protocol_bett_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_bett_encoder,const SubGhzProtocolEncoder, +Variable,-,subghz_protocol_bin_raw,const SubGhzProtocol, +Variable,-,subghz_protocol_bin_raw_decoder,const SubGhzProtocolDecoder, +Variable,-,subghz_protocol_bin_raw_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_came,const SubGhzProtocol, Variable,-,subghz_protocol_came_atomo,const SubGhzProtocol, Variable,-,subghz_protocol_came_atomo_decoder,const SubGhzProtocolDecoder, @@ -4875,6 +5020,9 @@ Variable,-,subghz_protocol_clemsa_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_doitrand,const SubGhzProtocol, Variable,-,subghz_protocol_doitrand_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_doitrand_encoder,const SubGhzProtocolEncoder, +Variable,-,subghz_protocol_dooya,const SubGhzProtocol, +Variable,-,subghz_protocol_dooya_decoder,const SubGhzProtocolDecoder, +Variable,-,subghz_protocol_dooya_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_faac_slh,const SubGhzProtocol, Variable,-,subghz_protocol_faac_slh_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_faac_slh_encoder,const SubGhzProtocolEncoder, @@ -4905,8 +5053,14 @@ Variable,-,subghz_protocol_keeloq_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_kia,const SubGhzProtocol, Variable,-,subghz_protocol_kia_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_kia_encoder,const SubGhzProtocolEncoder, +Variable,-,subghz_protocol_kinggates_stylo_4k,const SubGhzProtocol, +Variable,-,subghz_protocol_kinggates_stylo_4k_decoder,const SubGhzProtocolDecoder, +Variable,-,subghz_protocol_kinggates_stylo_4k_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_linear,const SubGhzProtocol, Variable,-,subghz_protocol_linear_decoder,const SubGhzProtocolDecoder, +Variable,-,subghz_protocol_linear_delta3,const SubGhzProtocol, +Variable,-,subghz_protocol_linear_delta3_decoder,const SubGhzProtocolDecoder, +Variable,-,subghz_protocol_linear_delta3_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_linear_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_magellan,const SubGhzProtocol, Variable,-,subghz_protocol_magellan_decoder,const SubGhzProtocolDecoder, @@ -4932,7 +5086,6 @@ Variable,-,subghz_protocol_nice_flor_s_encoder,const SubGhzProtocolEncoder, Variable,-,subghz_protocol_phoenix_v2,const SubGhzProtocol, Variable,-,subghz_protocol_phoenix_v2_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_phoenix_v2_encoder,const SubGhzProtocolEncoder, -Variable,-,subghz_protocol_pocsag,const SubGhzProtocol, Variable,-,subghz_protocol_power_smart,const SubGhzProtocol, Variable,-,subghz_protocol_power_smart_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_power_smart_encoder,const SubGhzProtocolEncoder, diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c index 8ef037d6b..83944b4b5 100644 --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -27,6 +27,8 @@ typedef struct { GapConfig* config; GapConnectionParams connection_params; GapState state; + int8_t conn_rssi; + uint32_t time_rssi_sample; FuriMutex* state_mutex; GapEventCallback on_event_cb; void* context; @@ -52,6 +54,19 @@ static const uint8_t gap_erk[16] = static Gap* gap = NULL; +/** function for updating rssi informations in global Gap object + * +*/ +static inline void fetch_rssi() { + uint8_t ret_rssi = 127; + if(hci_read_rssi(gap->service.connection_handle, &ret_rssi) == BLE_STATUS_SUCCESS) { + gap->conn_rssi = (int8_t)ret_rssi; + gap->time_rssi_sample = furi_get_tick(); + return; + } + FURI_LOG_D(TAG, "Failed to read RSSI"); +} + static void gap_advertise_start(GapState new_state); static int32_t gap_app(void* context); @@ -125,6 +140,9 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { gap->connection_params.supervisor_timeout = event->Supervision_Timeout; FURI_LOG_I(TAG, "Connection parameters event complete"); gap_verify_connection_parameters(gap); + + // save rssi for current connection + fetch_rssi(); break; } @@ -159,6 +177,9 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { gap->service.connection_handle = event->Connection_Handle; gap_verify_connection_parameters(gap); + + fetch_rssi(); + // Start pairing by sending security request aci_gap_slave_security_req(event->Connection_Handle); } break; @@ -243,6 +264,8 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) { pairing_complete->Status); aci_gap_terminate(gap->service.connection_handle, 5); } else { + fetch_rssi(); + FURI_LOG_I(TAG, "Pairing complete"); GapEvent event = {.type = GapEventTypeConnected}; gap->on_event_cb(event, gap->context); //-V595 @@ -313,7 +336,7 @@ static void gap_init_svc(Gap* gap) { // Initialize GATT interface aci_gatt_init(); // Initialize GAP interface - // Skip fist symbol AD_TYPE_COMPLETE_LOCAL_NAME + // Skip first symbol AD_TYPE_COMPLETE_LOCAL_NAME char* name = gap->service.adv_name + 1; aci_gap_init( GAP_PERIPHERAL_ROLE, @@ -348,21 +371,31 @@ static void gap_init_svc(Gap* gap) { hci_le_set_default_phy(ALL_PHYS_PREFERENCE, TX_2M_PREFERRED, RX_2M_PREFERRED); // Set I/O capability bool keypress_supported = false; + uint8_t conf_mitm = CFG_MITM_PROTECTION; + uint8_t conf_used_fixed_pin = CFG_USED_FIXED_PIN; if(gap->config->pairing_method == GapPairingPinCodeShow) { aci_gap_set_io_capability(IO_CAP_DISPLAY_ONLY); } else if(gap->config->pairing_method == GapPairingPinCodeVerifyYesNo) { aci_gap_set_io_capability(IO_CAP_DISPLAY_YES_NO); keypress_supported = true; + } else if(gap->config->pairing_method == GapPairingNone) { + // Just works pairing method (IOS accept it, it seems android and linux doesn't) + conf_mitm = 0; + conf_used_fixed_pin = 0; + // if just works isn't supported, we want the numeric comparaison method + aci_gap_set_io_capability(IO_CAP_DISPLAY_YES_NO); + keypress_supported = true; } + // Setup authentication aci_gap_set_authentication_requirement( gap->config->bonding_mode, - CFG_MITM_PROTECTION, + conf_mitm, CFG_SC_SUPPORT, keypress_supported, CFG_ENCRYPTION_KEY_SIZE_MIN, CFG_ENCRYPTION_KEY_SIZE_MAX, - CFG_USED_FIXED_PIN, + conf_used_fixed_pin, // 0x0 for no pin 0, PUBLIC_ADDR); // Configure whitelist @@ -482,6 +515,16 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { gap->advertise_timer = furi_timer_alloc(gap_advetise_timer_callback, FuriTimerTypeOnce, NULL); // Initialization of GATT & GAP layer gap->service.adv_name = config->adv_name; + FURI_LOG_I(TAG, "Advertising name: %s", &(gap->service.adv_name[1])); + FURI_LOG_I( + TAG, + "MAC @ : %02X:%02X:%02X:%02X:%02X:%02X", + config->mac_address[0], + config->mac_address[1], + config->mac_address[2], + config->mac_address[3], + config->mac_address[4], + config->mac_address[5]); gap_init_svc(gap); // Initialization of the BLE Services SVCCTL_Init(); @@ -491,6 +534,9 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { gap->service.connection_handle = 0xFFFF; gap->enable_adv = true; + gap->conn_rssi = 127; + gap->time_rssi_sample = 0; + // Thread configuration gap->thread = furi_thread_alloc_ex("BleGapDriver", 1024, gap_app, gap); furi_thread_start(gap->thread); @@ -510,6 +556,16 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { return true; } +uint32_t gap_get_remote_conn_rssi(int8_t* rssi) { + if(gap && gap->state == GapStateConnected) { + fetch_rssi(); + *rssi = gap->conn_rssi; + + if(gap->time_rssi_sample) return furi_get_tick() - gap->time_rssi_sample; + } + return 0; +} + GapState gap_get_state() { GapState state; if(gap) { diff --git a/firmware/targets/f7/ble_glue/gap.h b/firmware/targets/f7/ble_glue/gap.h index 1e207299f..7b317e06c 100644 --- a/firmware/targets/f7/ble_glue/gap.h +++ b/firmware/targets/f7/ble_glue/gap.h @@ -81,6 +81,8 @@ GapState gap_get_state(); void gap_thread_stop(); +uint32_t gap_get_remote_conn_rssi(int8_t* rssi); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c index 47d242d4d..cc1a2fbc5 100644 --- a/firmware/targets/f7/ble_glue/hid_service.c +++ b/firmware/targets/f7/ble_glue/hid_service.c @@ -14,6 +14,11 @@ typedef struct { uint16_t report_map_char_handle; uint16_t info_char_handle; uint16_t ctrl_point_char_handle; + // led state + uint16_t led_state_char_handle; + uint16_t led_state_desc_handle; + HidLedStateEventCallback led_state_event_callback; + void* led_state_ctx; } HIDSvc; static HIDSvc* hid_svc = NULL; @@ -30,6 +35,32 @@ static SVCCTL_EvtAckStatus_t hid_svc_event_handler(void* event) { } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { // Process notification confirmation ret = SVCCTL_EvtAckFlowEnable; + } else if(blecore_evt->ecode == ACI_GATT_WRITE_PERMIT_REQ_VSEVT_CODE) { + // Process write request + aci_gatt_write_permit_req_event_rp0* req = + (aci_gatt_write_permit_req_event_rp0*)blecore_evt->data; + + furi_check(hid_svc->led_state_event_callback && hid_svc->led_state_ctx); + + // this check is likely to be incorrect, it will actually work in our case + // but we need to investigate gatt api to see what is the rules + // that specify attibute handle value from char handle (or the reverse) + if(req->Attribute_Handle == (hid_svc->led_state_char_handle + 1)) { + hid_svc->led_state_event_callback(req->Data[0], hid_svc->led_state_ctx); + aci_gatt_write_resp( + req->Connection_Handle, + req->Attribute_Handle, + 0x00, /* write_status = 0 (no error))*/ + 0x00, /* err_code */ + req->Data_Length, + req->Data); + aci_gatt_write_char_value( + req->Connection_Handle, + hid_svc->led_state_char_handle, + req->Data_Length, + req->Data); + ret = SVCCTL_EvtAckFlowEnable; + } } } return ret; @@ -55,8 +86,8 @@ void hid_svc_start() { PRIMARY_SERVICE, 2 + /* protocol mode */ (4 * HID_SVC_INPUT_REPORT_COUNT) + (3 * HID_SVC_OUTPUT_REPORT_COUNT) + - (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + - 2, /* Service + Report Map + HID Information + HID Control Point */ + (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + 2 + + 4, /* Service + Report Map + HID Information + HID Control Point + LED state */ &hid_svc->svc_handle); if(status) { FURI_LOG_E(TAG, "Failed to add HID service: %d", status); @@ -198,6 +229,44 @@ void hid_svc_start() { } } #endif + // add led state output report + char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; + status = aci_gatt_add_char( + hid_svc->svc_handle, + UUID_TYPE_16, + &char_uuid, + 1, + CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE, + ATTR_PERMISSION_NONE, + GATT_NOTIFY_ATTRIBUTE_WRITE | GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP, + 10, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->led_state_char_handle)); + if(status) { + FURI_LOG_E(TAG, "Failed to add led state characteristic: %d", status); + } + + // add led state char descriptor specifying it is an output report + uint8_t buf[2] = {HID_SVC_REPORT_COUNT + 1, 2}; + desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; + status = aci_gatt_add_char_desc( + hid_svc->svc_handle, + hid_svc->led_state_char_handle, + UUID_TYPE_16, + &desc_uuid, + HID_SVC_REPORT_REF_LEN, + HID_SVC_REPORT_REF_LEN, + buf, + ATTR_PERMISSION_NONE, + ATTR_ACCESS_READ_WRITE, + GATT_DONT_NOTIFY_EVENTS, + MIN_ENCRY_KEY_SIZE, + CHAR_VALUE_LEN_CONSTANT, + &(hid_svc->led_state_desc_handle)); + if(status) { + FURI_LOG_E(TAG, "Failed to add led state descriptor: %d", status); + } + // Add Report Map characteristic char_uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID; status = aci_gatt_add_char( @@ -247,6 +316,9 @@ void hid_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add control point characteristic: %d", status); } + + hid_svc->led_state_event_callback = NULL; + hid_svc->led_state_ctx = NULL; } bool hid_svc_update_report_map(const uint8_t* data, uint16_t len) { @@ -288,6 +360,15 @@ bool hid_svc_update_info(uint8_t* data, uint16_t len) { return true; } +void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context) { + furi_assert(hid_svc); + furi_assert(callback); + furi_assert(context); + + hid_svc->led_state_event_callback = callback; + hid_svc->led_state_ctx = context; +} + bool hid_svc_is_started() { return hid_svc != NULL; } @@ -320,6 +401,10 @@ void hid_svc_stop() { if(status) { FURI_LOG_E(TAG, "Failed to delete Control Point characteristic: %d", status); } + status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->led_state_char_handle); + if(status) { + FURI_LOG_E(TAG, "Failed to delete led state characteristic: %d", status); + } // Delete service status = aci_gatt_del_service(hid_svc->svc_handle); if(status) { diff --git a/firmware/targets/f7/ble_glue/hid_service.h b/firmware/targets/f7/ble_glue/hid_service.h index 723460d49..40d973340 100644 --- a/firmware/targets/f7/ble_glue/hid_service.h +++ b/firmware/targets/f7/ble_glue/hid_service.h @@ -15,6 +15,8 @@ #define HID_SVC_REPORT_COUNT \ (HID_SVC_INPUT_REPORT_COUNT + HID_SVC_OUTPUT_REPORT_COUNT + HID_SVC_FEATURE_REPORT_COUNT) +typedef uint16_t (*HidLedStateEventCallback)(uint8_t state, void* ctx); + void hid_svc_start(); void hid_svc_stop(); @@ -26,3 +28,5 @@ bool hid_svc_update_report_map(const uint8_t* data, uint16_t len); bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len); bool hid_svc_update_info(uint8_t* data, uint16_t len); + +void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context); \ No newline at end of file diff --git a/firmware/targets/f7/fatfs/sd_spi_io.c b/firmware/targets/f7/fatfs/sd_spi_io.c new file mode 100644 index 000000000..93b837e85 --- /dev/null +++ b/firmware/targets/f7/fatfs/sd_spi_io.c @@ -0,0 +1,877 @@ +#include "sd_spi_io.h" +#include "sector_cache.h" +#include +#include +#include + +// #define SD_SPI_DEBUG 1 +#define TAG "SdSpi" + +#ifdef SD_SPI_DEBUG +#define sd_spi_debug(...) FURI_LOG_I(TAG, __VA_ARGS__) +#else +#define sd_spi_debug(...) +#endif + +#define SD_CMD_LENGTH 6 +#define SD_DUMMY_BYTE 0xFF +#define SD_ANSWER_RETRY_COUNT 8 +#define SD_IDLE_RETRY_COUNT 100 +#define SD_BLOCK_SIZE 512 + +#define FLAG_SET(x, y) (((x) & (y)) == (y)) + +static bool sd_high_capacity = false; + +typedef enum { + SdSpiDataResponceOK = 0x05, + SdSpiDataResponceCRCError = 0x0B, + SdSpiDataResponceWriteError = 0x0D, + SdSpiDataResponceOtherError = 0xFF, +} SdSpiDataResponce; + +typedef struct { + uint8_t r1; + uint8_t r2; + uint8_t r3; + uint8_t r4; + uint8_t r5; +} SdSpiCmdAnswer; + +typedef enum { + SdSpiCmdAnswerTypeR1, + SdSpiCmdAnswerTypeR1B, + SdSpiCmdAnswerTypeR2, + SdSpiCmdAnswerTypeR3, + SdSpiCmdAnswerTypeR4R5, + SdSpiCmdAnswerTypeR7, +} SdSpiCmdAnswerType; + +/* + SdSpiCmd and SdSpiToken use non-standard enum value names convention, + because it is more convenient to look for documentation on a specific command. + For example, to find out what the SD_CMD23_SET_BLOCK_COUNT command does, you need to look for + SET_BLOCK_COUNT or CMD23 in the "Part 1 Physical Layer Simplified Specification". + + Do not use that naming convention in other places. +*/ + +typedef enum { + SD_CMD0_GO_IDLE_STATE = 0, + SD_CMD1_SEND_OP_COND = 1, + SD_CMD8_SEND_IF_COND = 8, + SD_CMD9_SEND_CSD = 9, + SD_CMD10_SEND_CID = 10, + SD_CMD12_STOP_TRANSMISSION = 12, + SD_CMD13_SEND_STATUS = 13, + SD_CMD16_SET_BLOCKLEN = 16, + SD_CMD17_READ_SINGLE_BLOCK = 17, + SD_CMD18_READ_MULT_BLOCK = 18, + SD_CMD23_SET_BLOCK_COUNT = 23, + SD_CMD24_WRITE_SINGLE_BLOCK = 24, + SD_CMD25_WRITE_MULT_BLOCK = 25, + SD_CMD27_PROG_CSD = 27, + SD_CMD28_SET_WRITE_PROT = 28, + SD_CMD29_CLR_WRITE_PROT = 29, + SD_CMD30_SEND_WRITE_PROT = 30, + SD_CMD32_SD_ERASE_GRP_START = 32, + SD_CMD33_SD_ERASE_GRP_END = 33, + SD_CMD34_UNTAG_SECTOR = 34, + SD_CMD35_ERASE_GRP_START = 35, + SD_CMD36_ERASE_GRP_END = 36, + SD_CMD37_UNTAG_ERASE_GROUP = 37, + SD_CMD38_ERASE = 38, + SD_CMD41_SD_APP_OP_COND = 41, + SD_CMD55_APP_CMD = 55, + SD_CMD58_READ_OCR = 58, +} SdSpiCmd; + +/** Data tokens */ +typedef enum { + SD_TOKEN_START_DATA_SINGLE_BLOCK_READ = 0xFE, + SD_TOKEN_START_DATA_MULTIPLE_BLOCK_READ = 0xFE, + SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE = 0xFE, + SD_TOKEN_START_DATA_MULTIPLE_BLOCK_WRITE = 0xFC, + SD_TOKEN_STOP_DATA_MULTIPLE_BLOCK_WRITE = 0xFD, +} SdSpiToken; + +/** R1 answer value */ +typedef enum { + SdSpi_R1_NO_ERROR = 0x00, + SdSpi_R1_IN_IDLE_STATE = 0x01, + SdSpi_R1_ERASE_RESET = 0x02, + SdSpi_R1_ILLEGAL_COMMAND = 0x04, + SdSpi_R1_COM_CRC_ERROR = 0x08, + SdSpi_R1_ERASE_SEQUENCE_ERROR = 0x10, + SdSpi_R1_ADDRESS_ERROR = 0x20, + SdSpi_R1_PARAMETER_ERROR = 0x40, +} SdSpiR1; + +/** R2 answer value */ +typedef enum { + /* R2 answer value */ + SdSpi_R2_NO_ERROR = 0x00, + SdSpi_R2_CARD_LOCKED = 0x01, + SdSpi_R2_LOCKUNLOCK_ERROR = 0x02, + SdSpi_R2_ERROR = 0x04, + SdSpi_R2_CC_ERROR = 0x08, + SdSpi_R2_CARD_ECC_FAILED = 0x10, + SdSpi_R2_WP_VIOLATION = 0x20, + SdSpi_R2_ERASE_PARAM = 0x40, + SdSpi_R2_OUTOFRANGE = 0x80, +} SdSpiR2; + +static inline void sd_spi_select_card() { + furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, false); + furi_delay_us(10); // Entry guard time for some SD cards +} + +static inline void sd_spi_deselect_card() { + furi_delay_us(10); // Exit guard time for some SD cards + furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, true); +} + +static void sd_spi_bus_to_ground() { + furi_hal_gpio_init_ex( + furi_hal_sd_spi_handle->miso, + GpioModeOutputPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFnUnused); + furi_hal_gpio_init_ex( + furi_hal_sd_spi_handle->mosi, + GpioModeOutputPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFnUnused); + furi_hal_gpio_init_ex( + furi_hal_sd_spi_handle->sck, + GpioModeOutputPushPull, + GpioPullNo, + GpioSpeedVeryHigh, + GpioAltFnUnused); + + sd_spi_select_card(); + furi_hal_gpio_write(furi_hal_sd_spi_handle->miso, false); + furi_hal_gpio_write(furi_hal_sd_spi_handle->mosi, false); + furi_hal_gpio_write(furi_hal_sd_spi_handle->sck, false); +} + +static void sd_spi_bus_rise_up() { + sd_spi_deselect_card(); + + furi_hal_gpio_init_ex( + furi_hal_sd_spi_handle->miso, + GpioModeAltFunctionPushPull, + GpioPullUp, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); + furi_hal_gpio_init_ex( + furi_hal_sd_spi_handle->mosi, + GpioModeAltFunctionPushPull, + GpioPullUp, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); + furi_hal_gpio_init_ex( + furi_hal_sd_spi_handle->sck, + GpioModeAltFunctionPushPull, + GpioPullUp, + GpioSpeedVeryHigh, + GpioAltFn5SPI2); +} + +static inline uint8_t sd_spi_read_byte(void) { + uint8_t responce; + furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, NULL, &responce, 1, SD_TIMEOUT_MS)); + return responce; +} + +static inline void sd_spi_write_byte(uint8_t data) { + furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, &data, NULL, 1, SD_TIMEOUT_MS)); +} + +static inline uint8_t sd_spi_write_and_read_byte(uint8_t data) { + uint8_t responce; + furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, &data, &responce, 1, SD_TIMEOUT_MS)); + return responce; +} + +static inline void sd_spi_write_bytes(uint8_t* data, uint32_t size) { + furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, data, NULL, size, SD_TIMEOUT_MS)); +} + +static inline void sd_spi_read_bytes(uint8_t* data, uint32_t size) { + furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, NULL, data, size, SD_TIMEOUT_MS)); +} + +static inline void sd_spi_write_bytes_dma(uint8_t* data, uint32_t size) { + uint32_t timeout_mul = (size / 512) + 1; + furi_check(furi_hal_spi_bus_trx_dma( + furi_hal_sd_spi_handle, data, NULL, size, SD_TIMEOUT_MS * timeout_mul)); +} + +static inline void sd_spi_read_bytes_dma(uint8_t* data, uint32_t size) { + uint32_t timeout_mul = (size / 512) + 1; + furi_check(furi_hal_spi_bus_trx_dma( + furi_hal_sd_spi_handle, NULL, data, size, SD_TIMEOUT_MS * timeout_mul)); +} + +static uint8_t sd_spi_wait_for_data_and_read(void) { + uint8_t retry_count = SD_ANSWER_RETRY_COUNT; + uint8_t responce; + + // Wait until we get a valid data + do { + responce = sd_spi_read_byte(); + retry_count--; + + } while((responce == SD_DUMMY_BYTE) && retry_count); + + return responce; +} + +static SdSpiStatus sd_spi_wait_for_data(uint8_t data, uint32_t timeout_ms) { + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(timeout_ms * 1000); + uint8_t byte; + + do { + byte = sd_spi_read_byte(); + if(furi_hal_cortex_timer_is_expired(timer)) { + return SdSpiStatusTimeout; + } + } while((byte != data)); + + return SdSpiStatusOK; +} + +static inline void sd_spi_deselect_card_and_purge() { + sd_spi_deselect_card(); + sd_spi_read_byte(); +} + +static inline void sd_spi_purge_crc() { + sd_spi_read_byte(); + sd_spi_read_byte(); +} + +static SdSpiCmdAnswer + sd_spi_send_cmd(SdSpiCmd cmd, uint32_t arg, uint8_t crc, SdSpiCmdAnswerType answer_type) { + uint8_t frame[SD_CMD_LENGTH]; + SdSpiCmdAnswer cmd_answer = { + .r1 = SD_DUMMY_BYTE, + .r2 = SD_DUMMY_BYTE, + .r3 = SD_DUMMY_BYTE, + .r4 = SD_DUMMY_BYTE, + .r5 = SD_DUMMY_BYTE, + }; + + // R1 Length = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 1 Bytes answer + NEC(0) = 15bytes + // R1b identical to R1 + Busy information + // R2 Length = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 2 Bytes answer + NEC(0) = 16bytes + + frame[0] = ((uint8_t)cmd | 0x40); + frame[1] = (uint8_t)(arg >> 24); + frame[2] = (uint8_t)(arg >> 16); + frame[3] = (uint8_t)(arg >> 8); + frame[4] = (uint8_t)(arg); + frame[5] = (crc | 0x01); + + sd_spi_select_card(); + sd_spi_write_bytes(frame, sizeof(frame)); + + switch(answer_type) { + case SdSpiCmdAnswerTypeR1: + cmd_answer.r1 = sd_spi_wait_for_data_and_read(); + break; + case SdSpiCmdAnswerTypeR1B: + // TODO: can be wrong, at least for SD_CMD12_STOP_TRANSMISSION you need to purge one byte before reading R1 + cmd_answer.r1 = sd_spi_wait_for_data_and_read(); + + // In general this shenenigans seems suspicious, please double check SD specs if you are using SdSpiCmdAnswerTypeR1B + // reassert card + sd_spi_deselect_card(); + furi_delay_us(1000); + sd_spi_deselect_card(); + + // and wait for it to be ready + while(sd_spi_read_byte() != 0xFF) { + }; + + break; + case SdSpiCmdAnswerTypeR2: + cmd_answer.r1 = sd_spi_wait_for_data_and_read(); + cmd_answer.r2 = sd_spi_read_byte(); + break; + case SdSpiCmdAnswerTypeR3: + case SdSpiCmdAnswerTypeR7: + cmd_answer.r1 = sd_spi_wait_for_data_and_read(); + cmd_answer.r2 = sd_spi_read_byte(); + cmd_answer.r3 = sd_spi_read_byte(); + cmd_answer.r4 = sd_spi_read_byte(); + cmd_answer.r5 = sd_spi_read_byte(); + break; + default: + break; + } + return cmd_answer; +} + +static SdSpiDataResponce sd_spi_get_data_response(uint32_t timeout_ms) { + SdSpiDataResponce responce = sd_spi_read_byte(); + // read busy response byte + sd_spi_read_byte(); + + switch(responce & 0x1F) { + case SdSpiDataResponceOK: + // TODO: check timings + sd_spi_deselect_card(); + sd_spi_select_card(); + + // wait for 0xFF + if(sd_spi_wait_for_data(0xFF, timeout_ms) == SdSpiStatusOK) { + return SdSpiDataResponceOK; + } else { + return SdSpiDataResponceOtherError; + } + case SdSpiDataResponceCRCError: + return SdSpiDataResponceCRCError; + case SdSpiDataResponceWriteError: + return SdSpiDataResponceWriteError; + default: + return SdSpiDataResponceOtherError; + } +} + +static SdSpiStatus sd_spi_init_spi_mode_v1(void) { + SdSpiCmdAnswer response; + uint8_t retry_count = 0; + + sd_spi_debug("Init SD card in SPI mode v1"); + + do { + retry_count++; + + // CMD55 (APP_CMD) before any ACMD command: R1 response (0x00: no errors) + sd_spi_send_cmd(SD_CMD55_APP_CMD, 0, 0xFF, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + // ACMD41 (SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) + response = sd_spi_send_cmd(SD_CMD41_SD_APP_OP_COND, 0, 0xFF, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + if(retry_count >= SD_IDLE_RETRY_COUNT) { + return SdSpiStatusError; + } + } while(response.r1 == SdSpi_R1_IN_IDLE_STATE); + + sd_spi_debug("Init SD card in SPI mode v1 done"); + + return SdSpiStatusOK; +} + +static SdSpiStatus sd_spi_init_spi_mode_v2(void) { + SdSpiCmdAnswer response; + uint8_t retry_count = 0; + + sd_spi_debug("Init SD card in SPI mode v2"); + + do { + retry_count++; + // CMD55 (APP_CMD) before any ACMD command: R1 response (0x00: no errors) + sd_spi_send_cmd(SD_CMD55_APP_CMD, 0, 0xFF, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + // ACMD41 (APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) + response = + sd_spi_send_cmd(SD_CMD41_SD_APP_OP_COND, 0x40000000, 0xFF, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + if(retry_count >= SD_IDLE_RETRY_COUNT) { + sd_spi_debug("ACMD41 failed"); + return SdSpiStatusError; + } + } while(response.r1 == SdSpi_R1_IN_IDLE_STATE); + + if(FLAG_SET(response.r1, SdSpi_R1_ILLEGAL_COMMAND)) { + sd_spi_debug("ACMD41 is illegal command"); + retry_count = 0; + do { + retry_count++; + // CMD55 (APP_CMD) before any ACMD command: R1 response (0x00: no errors) + response = sd_spi_send_cmd(SD_CMD55_APP_CMD, 0, 0xFF, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + if(response.r1 != SdSpi_R1_IN_IDLE_STATE) { + sd_spi_debug("CMD55 failed"); + return SdSpiStatusError; + } + // ACMD41 (SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) + response = sd_spi_send_cmd(SD_CMD41_SD_APP_OP_COND, 0, 0xFF, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + if(retry_count >= SD_IDLE_RETRY_COUNT) { + sd_spi_debug("ACMD41 failed"); + return SdSpiStatusError; + } + } while(response.r1 == SdSpi_R1_IN_IDLE_STATE); + } + + sd_spi_debug("Init SD card in SPI mode v2 done"); + + return SdSpiStatusOK; +} + +static SdSpiStatus sd_spi_init_spi_mode(void) { + SdSpiCmdAnswer response; + uint8_t retry_count; + + // CMD0 (GO_IDLE_STATE) to put SD in SPI mode and + // wait for In Idle State Response (R1 Format) equal to 0x01 + retry_count = 0; + do { + retry_count++; + response = sd_spi_send_cmd(SD_CMD0_GO_IDLE_STATE, 0, 0x95, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + if(retry_count >= SD_IDLE_RETRY_COUNT) { + sd_spi_debug("CMD0 failed"); + return SdSpiStatusError; + } + } while(response.r1 != SdSpi_R1_IN_IDLE_STATE); + + // CMD8 (SEND_IF_COND) to check the power supply status + // and wait until response (R7 Format) equal to 0xAA and + response = sd_spi_send_cmd(SD_CMD8_SEND_IF_COND, 0x1AA, 0x87, SdSpiCmdAnswerTypeR7); + sd_spi_deselect_card_and_purge(); + + if(FLAG_SET(response.r1, SdSpi_R1_ILLEGAL_COMMAND)) { + if(sd_spi_init_spi_mode_v1() != SdSpiStatusOK) { + sd_spi_debug("Init mode v1 failed"); + return SdSpiStatusError; + } + sd_high_capacity = 0; + } else if(response.r1 == SdSpi_R1_IN_IDLE_STATE) { + if(sd_spi_init_spi_mode_v2() != SdSpiStatusOK) { + sd_spi_debug("Init mode v2 failed"); + return SdSpiStatusError; + } + + // CMD58 (READ_OCR) to initialize SDHC or SDXC cards: R3 response + response = sd_spi_send_cmd(SD_CMD58_READ_OCR, 0, 0xFF, SdSpiCmdAnswerTypeR3); + sd_spi_deselect_card_and_purge(); + + if(response.r1 != SdSpi_R1_NO_ERROR) { + sd_spi_debug("CMD58 failed"); + return SdSpiStatusError; + } + sd_high_capacity = (response.r2 & 0x40) >> 6; + } else { + return SdSpiStatusError; + } + + sd_spi_debug("SD card is %s", sd_high_capacity ? "SDHC or SDXC" : "SDSC"); + return SdSpiStatusOK; +} + +static SdSpiStatus sd_spi_get_csd(SD_CSD* csd) { + uint16_t counter = 0; + uint8_t csd_data[16]; + SdSpiStatus ret = SdSpiStatusError; + SdSpiCmdAnswer response; + + // CMD9 (SEND_CSD): R1 format (0x00 is no errors) + response = sd_spi_send_cmd(SD_CMD9_SEND_CSD, 0, 0xFF, SdSpiCmdAnswerTypeR1); + + if(response.r1 == SdSpi_R1_NO_ERROR) { + if(sd_spi_wait_for_data(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ, SD_TIMEOUT_MS) == + SdSpiStatusOK) { + // read CSD data + for(counter = 0; counter < 16; counter++) { + csd_data[counter] = sd_spi_read_byte(); + } + + sd_spi_purge_crc(); + + /************************************************************************* + CSD header decoding + *************************************************************************/ + + csd->CSDStruct = (csd_data[0] & 0xC0) >> 6; + csd->Reserved1 = csd_data[0] & 0x3F; + csd->TAAC = csd_data[1]; + csd->NSAC = csd_data[2]; + csd->MaxBusClkFrec = csd_data[3]; + csd->CardComdClasses = (csd_data[4] << 4) | ((csd_data[5] & 0xF0) >> 4); + csd->RdBlockLen = csd_data[5] & 0x0F; + csd->PartBlockRead = (csd_data[6] & 0x80) >> 7; + csd->WrBlockMisalign = (csd_data[6] & 0x40) >> 6; + csd->RdBlockMisalign = (csd_data[6] & 0x20) >> 5; + csd->DSRImpl = (csd_data[6] & 0x10) >> 4; + + /************************************************************************* + CSD v1/v2 decoding + *************************************************************************/ + + if(sd_high_capacity == 0) { + csd->version.v1.Reserved1 = ((csd_data[6] & 0x0C) >> 2); + csd->version.v1.DeviceSize = ((csd_data[6] & 0x03) << 10) | (csd_data[7] << 2) | + ((csd_data[8] & 0xC0) >> 6); + csd->version.v1.MaxRdCurrentVDDMin = (csd_data[8] & 0x38) >> 3; + csd->version.v1.MaxRdCurrentVDDMax = (csd_data[8] & 0x07); + csd->version.v1.MaxWrCurrentVDDMin = (csd_data[9] & 0xE0) >> 5; + csd->version.v1.MaxWrCurrentVDDMax = (csd_data[9] & 0x1C) >> 2; + csd->version.v1.DeviceSizeMul = ((csd_data[9] & 0x03) << 1) | + ((csd_data[10] & 0x80) >> 7); + } else { + csd->version.v2.Reserved1 = ((csd_data[6] & 0x0F) << 2) | + ((csd_data[7] & 0xC0) >> 6); + csd->version.v2.DeviceSize = ((csd_data[7] & 0x3F) << 16) | (csd_data[8] << 8) | + csd_data[9]; + csd->version.v2.Reserved2 = ((csd_data[10] & 0x80) >> 8); + } + + csd->EraseSingleBlockEnable = (csd_data[10] & 0x40) >> 6; + csd->EraseSectorSize = ((csd_data[10] & 0x3F) << 1) | ((csd_data[11] & 0x80) >> 7); + csd->WrProtectGrSize = (csd_data[11] & 0x7F); + csd->WrProtectGrEnable = (csd_data[12] & 0x80) >> 7; + csd->Reserved2 = (csd_data[12] & 0x60) >> 5; + csd->WrSpeedFact = (csd_data[12] & 0x1C) >> 2; + csd->MaxWrBlockLen = ((csd_data[12] & 0x03) << 2) | ((csd_data[13] & 0xC0) >> 6); + csd->WriteBlockPartial = (csd_data[13] & 0x20) >> 5; + csd->Reserved3 = (csd_data[13] & 0x1F); + csd->FileFormatGrouop = (csd_data[14] & 0x80) >> 7; + csd->CopyFlag = (csd_data[14] & 0x40) >> 6; + csd->PermWrProtect = (csd_data[14] & 0x20) >> 5; + csd->TempWrProtect = (csd_data[14] & 0x10) >> 4; + csd->FileFormat = (csd_data[14] & 0x0C) >> 2; + csd->Reserved4 = (csd_data[14] & 0x03); + csd->crc = (csd_data[15] & 0xFE) >> 1; + csd->Reserved5 = (csd_data[15] & 0x01); + + ret = SdSpiStatusOK; + } + } + + sd_spi_deselect_card_and_purge(); + + return ret; +} + +static SdSpiStatus sd_spi_get_cid(SD_CID* Cid) { + uint16_t counter = 0; + uint8_t cid_data[16]; + SdSpiStatus ret = SdSpiStatusError; + SdSpiCmdAnswer response; + + // CMD10 (SEND_CID): R1 format (0x00 is no errors) + response = sd_spi_send_cmd(SD_CMD10_SEND_CID, 0, 0xFF, SdSpiCmdAnswerTypeR1); + + if(response.r1 == SdSpi_R1_NO_ERROR) { + if(sd_spi_wait_for_data(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ, SD_TIMEOUT_MS) == + SdSpiStatusOK) { + // read CID data + for(counter = 0; counter < 16; counter++) { + cid_data[counter] = sd_spi_read_byte(); + } + + sd_spi_purge_crc(); + + Cid->ManufacturerID = cid_data[0]; + memcpy(Cid->OEM_AppliID, cid_data + 1, 2); + memcpy(Cid->ProdName, cid_data + 3, 5); + Cid->ProdRev = cid_data[8]; + Cid->ProdSN = cid_data[9] << 24; + Cid->ProdSN |= cid_data[10] << 16; + Cid->ProdSN |= cid_data[11] << 8; + Cid->ProdSN |= cid_data[12]; + Cid->Reserved1 = (cid_data[13] & 0xF0) >> 4; + Cid->ManufactYear = (cid_data[13] & 0x0F) << 4; + Cid->CID_CRC = (cid_data[15] & 0xFE) >> 1; + Cid->Reserved2 = 1; + + ret = SdSpiStatusOK; + } + } + + sd_spi_deselect_card_and_purge(); + + return ret; +} + +static inline bool sd_cache_get(uint32_t address, uint32_t* data) { + uint8_t* cached_data = sector_cache_get(address); + if(cached_data) { + memcpy(data, cached_data, SD_BLOCK_SIZE); + return true; + } + return false; +} + +static inline void sd_cache_put(uint32_t address, uint32_t* data) { + sector_cache_put(address, (uint8_t*)data); +} + +static inline void sd_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) { + sector_cache_invalidate_range(start_sector, end_sector); +} + +static SdSpiStatus + sd_spi_cmd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { + uint32_t block_address = address; + uint32_t offset = 0; + + // CMD16 (SET_BLOCKLEN): R1 response (0x00: no errors) + SdSpiCmdAnswer response = + sd_spi_send_cmd(SD_CMD16_SET_BLOCKLEN, SD_BLOCK_SIZE, 0xFF, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + if(response.r1 != SdSpi_R1_NO_ERROR) { + return SdSpiStatusError; + } + + if(!sd_high_capacity) { + block_address = address * SD_BLOCK_SIZE; + } + + while(blocks--) { + // CMD17 (READ_SINGLE_BLOCK): R1 response (0x00: no errors) + response = + sd_spi_send_cmd(SD_CMD17_READ_SINGLE_BLOCK, block_address, 0xFF, SdSpiCmdAnswerTypeR1); + if(response.r1 != SdSpi_R1_NO_ERROR) { + sd_spi_deselect_card_and_purge(); + return SdSpiStatusError; + } + + // Wait for the data start token + if(sd_spi_wait_for_data(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ, timeout_ms) == + SdSpiStatusOK) { + // Read the data block + sd_spi_read_bytes_dma((uint8_t*)data + offset, SD_BLOCK_SIZE); + sd_spi_purge_crc(); + + // increase offset + offset += SD_BLOCK_SIZE; + + // increase block address + if(sd_high_capacity) { + block_address += 1; + } else { + block_address += SD_BLOCK_SIZE; + } + } else { + sd_spi_deselect_card_and_purge(); + return SdSpiStatusError; + } + + sd_spi_deselect_card_and_purge(); + } + + return SdSpiStatusOK; +} + +static SdSpiStatus sd_spi_cmd_write_blocks( + uint32_t* data, + uint32_t address, + uint32_t blocks, + uint32_t timeout_ms) { + uint32_t block_address = address; + uint32_t offset = 0; + + // CMD16 (SET_BLOCKLEN): R1 response (0x00: no errors) + SdSpiCmdAnswer response = + sd_spi_send_cmd(SD_CMD16_SET_BLOCKLEN, SD_BLOCK_SIZE, 0xFF, SdSpiCmdAnswerTypeR1); + sd_spi_deselect_card_and_purge(); + + if(response.r1 != SdSpi_R1_NO_ERROR) { + return SdSpiStatusError; + } + + if(!sd_high_capacity) { + block_address = address * SD_BLOCK_SIZE; + } + + while(blocks--) { + // CMD24 (WRITE_SINGLE_BLOCK): R1 response (0x00: no errors) + response = sd_spi_send_cmd( + SD_CMD24_WRITE_SINGLE_BLOCK, block_address, 0xFF, SdSpiCmdAnswerTypeR1); + if(response.r1 != SdSpi_R1_NO_ERROR) { + sd_spi_deselect_card_and_purge(); + return SdSpiStatusError; + } + + // Send dummy byte for NWR timing : one byte between CMD_WRITE and TOKEN + // TODO: check bytes count + sd_spi_write_byte(SD_DUMMY_BYTE); + sd_spi_write_byte(SD_DUMMY_BYTE); + + // Send the data start token + sd_spi_write_byte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE); + sd_spi_write_bytes_dma((uint8_t*)data + offset, SD_BLOCK_SIZE); + sd_spi_purge_crc(); + + // Read data response + SdSpiDataResponce data_responce = sd_spi_get_data_response(timeout_ms); + sd_spi_deselect_card_and_purge(); + + if(data_responce != SdSpiDataResponceOK) { + return SdSpiStatusError; + } + + // increase offset + offset += SD_BLOCK_SIZE; + + // increase block address + if(sd_high_capacity) { + block_address += 1; + } else { + block_address += SD_BLOCK_SIZE; + } + } + + return SdSpiStatusOK; +} + +uint8_t sd_max_mount_retry_count() { + return 10; +} + +SdSpiStatus sd_init(bool power_reset) { + // Slow speed init + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_slow); + furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_slow; + + // We reset card in spi_lock context, so it is safe to disturb spi bus + if(power_reset) { + sd_spi_debug("Power reset"); + + // disable power and set low on all bus pins + furi_hal_power_disable_external_3_3v(); + sd_spi_bus_to_ground(); + hal_sd_detect_set_low(); + furi_delay_ms(250); + + // reinit bus and enable power + sd_spi_bus_rise_up(); + hal_sd_detect_init(); + furi_hal_power_enable_external_3_3v(); + furi_delay_ms(100); + } + + SdSpiStatus status = SdSpiStatusError; + + // Send 80 dummy clocks with CS high + sd_spi_deselect_card(); + for(uint8_t i = 0; i < 80; i++) { + sd_spi_write_byte(SD_DUMMY_BYTE); + } + + for(uint8_t i = 0; i < 128; i++) { + status = sd_spi_init_spi_mode(); + if(status == SdSpiStatusOK) { + // SD initialized and init to SPI mode properly + sd_spi_debug("SD init OK after %d retries", i); + break; + } + } + + furi_hal_sd_spi_handle = NULL; + furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); + + // Init sector cache + sector_cache_init(); + + return status; +} + +SdSpiStatus sd_get_card_state(void) { + SdSpiCmdAnswer response; + + // Send CMD13 (SEND_STATUS) to get SD status + response = sd_spi_send_cmd(SD_CMD13_SEND_STATUS, 0, 0xFF, SdSpiCmdAnswerTypeR2); + sd_spi_deselect_card_and_purge(); + + // Return status OK if response is valid + if((response.r1 == SdSpi_R1_NO_ERROR) && (response.r2 == SdSpi_R2_NO_ERROR)) { + return SdSpiStatusOK; + } + + return SdSpiStatusError; +} + +SdSpiStatus sd_get_card_info(SD_CardInfo* card_info) { + SdSpiStatus status; + + status = sd_spi_get_csd(&(card_info->Csd)); + + if(status != SdSpiStatusOK) { + return status; + } + + status = sd_spi_get_cid(&(card_info->Cid)); + + if(status != SdSpiStatusOK) { + return status; + } + + if(sd_high_capacity == 1) { + card_info->LogBlockSize = 512; + card_info->CardBlockSize = 512; + card_info->CardCapacity = ((uint64_t)card_info->Csd.version.v2.DeviceSize + 1UL) * 1024UL * + (uint64_t)card_info->LogBlockSize; + card_info->LogBlockNbr = (card_info->CardCapacity) / (card_info->LogBlockSize); + } else { + card_info->CardCapacity = (card_info->Csd.version.v1.DeviceSize + 1); + card_info->CardCapacity *= (1UL << (card_info->Csd.version.v1.DeviceSizeMul + 2)); + card_info->LogBlockSize = 512; + card_info->CardBlockSize = 1UL << (card_info->Csd.RdBlockLen); + card_info->CardCapacity *= card_info->CardBlockSize; + card_info->LogBlockNbr = (card_info->CardCapacity) / (card_info->LogBlockSize); + } + + return status; +} + +SdSpiStatus + sd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { + SdSpiStatus status = SdSpiStatusError; + + bool single_sector_read = (blocks == 1); + + if(single_sector_read) { + if(sd_cache_get(address, data)) { + return SdSpiStatusOK; + } + + status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms); + + if(status == SdSpiStatusOK) { + sd_cache_put(address, data); + } + } else { + status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms); + } + + return status; +} + +SdSpiStatus + sd_write_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { + sd_cache_invalidate_range(address, address + blocks); + SdSpiStatus status = sd_spi_cmd_write_blocks(data, address, blocks, timeout_ms); + return status; +} + +SdSpiStatus sd_get_cid(SD_CID* cid) { + SdSpiStatus status; + + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); + furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; + + memset(cid, 0, sizeof(SD_CID)); + status = sd_spi_get_cid(cid); + + furi_hal_sd_spi_handle = NULL; + furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); + + return status; +} \ No newline at end of file diff --git a/firmware/targets/f7/fatfs/sd_spi_io.h b/firmware/targets/f7/fatfs/sd_spi_io.h new file mode 100644 index 000000000..8850eceb7 --- /dev/null +++ b/firmware/targets/f7/fatfs/sd_spi_io.h @@ -0,0 +1,157 @@ +#pragma once +#include +#include + +#define __IO volatile + +#define SD_TIMEOUT_MS (1000) + +typedef enum { + SdSpiStatusOK, + SdSpiStatusError, + SdSpiStatusTimeout, +} SdSpiStatus; + +/** + * @brief Card Specific Data: CSD Register + */ +typedef struct { + /* Header part */ + uint8_t CSDStruct : 2; /* CSD structure */ + uint8_t Reserved1 : 6; /* Reserved */ + uint8_t TAAC : 8; /* Data read access-time 1 */ + uint8_t NSAC : 8; /* Data read access-time 2 in CLK cycles */ + uint8_t MaxBusClkFrec : 8; /* Max. bus clock frequency */ + uint16_t CardComdClasses : 12; /* Card command classes */ + uint8_t RdBlockLen : 4; /* Max. read data block length */ + uint8_t PartBlockRead : 1; /* Partial blocks for read allowed */ + uint8_t WrBlockMisalign : 1; /* Write block misalignment */ + uint8_t RdBlockMisalign : 1; /* Read block misalignment */ + uint8_t DSRImpl : 1; /* DSR implemented */ + + /* v1 or v2 struct */ + union csd_version { + struct { + uint8_t Reserved1 : 2; /* Reserved */ + uint16_t DeviceSize : 12; /* Device Size */ + uint8_t MaxRdCurrentVDDMin : 3; /* Max. read current @ VDD min */ + uint8_t MaxRdCurrentVDDMax : 3; /* Max. read current @ VDD max */ + uint8_t MaxWrCurrentVDDMin : 3; /* Max. write current @ VDD min */ + uint8_t MaxWrCurrentVDDMax : 3; /* Max. write current @ VDD max */ + uint8_t DeviceSizeMul : 3; /* Device size multiplier */ + } v1; + struct { + uint8_t Reserved1 : 6; /* Reserved */ + uint32_t DeviceSize : 22; /* Device Size */ + uint8_t Reserved2 : 1; /* Reserved */ + } v2; + } version; + + uint8_t EraseSingleBlockEnable : 1; /* Erase single block enable */ + uint8_t EraseSectorSize : 7; /* Erase group size multiplier */ + uint8_t WrProtectGrSize : 7; /* Write protect group size */ + uint8_t WrProtectGrEnable : 1; /* Write protect group enable */ + uint8_t Reserved2 : 2; /* Reserved */ + uint8_t WrSpeedFact : 3; /* Write speed factor */ + uint8_t MaxWrBlockLen : 4; /* Max. write data block length */ + uint8_t WriteBlockPartial : 1; /* Partial blocks for write allowed */ + uint8_t Reserved3 : 5; /* Reserved */ + uint8_t FileFormatGrouop : 1; /* File format group */ + uint8_t CopyFlag : 1; /* Copy flag (OTP) */ + uint8_t PermWrProtect : 1; /* Permanent write protection */ + uint8_t TempWrProtect : 1; /* Temporary write protection */ + uint8_t FileFormat : 2; /* File Format */ + uint8_t Reserved4 : 2; /* Reserved */ + uint8_t crc : 7; /* Reserved */ + uint8_t Reserved5 : 1; /* always 1*/ + +} SD_CSD; + +/** + * @brief Card Identification Data: CID Register + */ +typedef struct { + uint8_t ManufacturerID; /* ManufacturerID */ + char OEM_AppliID[2]; /* OEM/Application ID */ + char ProdName[5]; /* Product Name */ + uint8_t ProdRev; /* Product Revision */ + uint32_t ProdSN; /* Product Serial Number */ + uint8_t Reserved1; /* Reserved1 */ + uint8_t ManufactYear; /* Manufacturing Year */ + uint8_t ManufactMonth; /* Manufacturing Month */ + uint8_t CID_CRC; /* CID CRC */ + uint8_t Reserved2; /* always 1 */ +} SD_CID; + +/** + * @brief SD Card information structure + */ +typedef struct { + SD_CSD Csd; + SD_CID Cid; + uint64_t CardCapacity; /*!< Card Capacity */ + uint32_t CardBlockSize; /*!< Card Block Size */ + uint32_t LogBlockNbr; /*!< Specifies the Card logical Capacity in blocks */ + uint32_t LogBlockSize; /*!< Specifies logical block size in bytes */ +} SD_CardInfo; + +/** + * @brief SD card max mount retry count + * + * @return uint8_t + */ +uint8_t sd_max_mount_retry_count(); + +/** + * @brief Init sd card + * + * @param power_reset reset card power + * @return SdSpiStatus + */ +SdSpiStatus sd_init(bool power_reset); + +/** + * @brief Get card state + * + * @return SdSpiStatus + */ +SdSpiStatus sd_get_card_state(void); + +/** + * @brief Get card info + * + * @param card_info + * @return SdSpiStatus + */ +SdSpiStatus sd_get_card_info(SD_CardInfo* card_info); + +/** + * @brief Read blocks + * + * @param data + * @param address + * @param blocks + * @param timeout_ms + * @return SdSpiStatus + */ +SdSpiStatus sd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms); + +/** + * @brief Write blocks + * + * @param data + * @param address + * @param blocks + * @param timeout_ms + * @return SdSpiStatus + */ +SdSpiStatus + sd_write_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms); + +/** + * @brief Get card CSD register + * + * @param Cid + * @return SdSpiStatus + */ +SdSpiStatus sd_get_cid(SD_CID* cid); \ No newline at end of file diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c index b9b65f06a..998adee29 100644 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c +++ b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c @@ -779,25 +779,10 @@ uint8_t SD_GetCIDRegister(SD_CID* Cid) { Cid->ManufacturerID = CID_Tab[0]; /* Byte 1 */ - Cid->OEM_AppliID = CID_Tab[1] << 8; - - /* Byte 2 */ - Cid->OEM_AppliID |= CID_Tab[2]; + memcpy(Cid->OEM_AppliID, CID_Tab + 1, 2); /* Byte 3 */ - Cid->ProdName1 = CID_Tab[3] << 24; - - /* Byte 4 */ - Cid->ProdName1 |= CID_Tab[4] << 16; - - /* Byte 5 */ - Cid->ProdName1 |= CID_Tab[5] << 8; - - /* Byte 6 */ - Cid->ProdName1 |= CID_Tab[6]; - - /* Byte 7 */ - Cid->ProdName2 = CID_Tab[7]; + memcpy(Cid->ProdName, CID_Tab + 3, 5); /* Byte 8 */ Cid->ProdRev = CID_Tab[8]; @@ -815,11 +800,12 @@ uint8_t SD_GetCIDRegister(SD_CID* Cid) { Cid->ProdSN |= CID_Tab[12]; /* Byte 13 */ - Cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4; - Cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8; + Cid->Reserved1 = (CID_Tab[13] & 0xF0) >> 4; + Cid->ManufactYear = (CID_Tab[13] & 0x0F) << 4; /* Byte 14 */ - Cid->ManufactDate |= CID_Tab[14]; + Cid->ManufactYear |= (CID_Tab[14] & 0xF0) >> 4; + Cid->ManufactMonth = (CID_Tab[14] & 0x0F); /* Byte 15 */ Cid->CID_CRC = (CID_Tab[15] & 0xFE) >> 1; @@ -837,6 +823,21 @@ uint8_t SD_GetCIDRegister(SD_CID* Cid) { return retr; } +uint8_t BSP_SD_GetCIDRegister(SD_CID* Cid) { + uint8_t retr = BSP_SD_ERROR; + + /* Slow speed init */ + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_slow); + furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_slow; + + memset(Cid, 0, sizeof(SD_CID)); + retr = SD_GetCIDRegister(Cid); + + furi_hal_sd_spi_handle = NULL; + furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); + return retr; +} + /** * @brief Sends 5 bytes command to the SD card and get response * @param Cmd: The user expected command to send to SD card. diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.h b/firmware/targets/f7/fatfs/stm32_adafruit_sd.h index e0c5e3bef..a133c5922 100644 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.h +++ b/firmware/targets/f7/fatfs/stm32_adafruit_sd.h @@ -133,16 +133,16 @@ typedef struct { * @brief Card Identification Data: CID Register */ typedef struct { - __IO uint8_t ManufacturerID; /* ManufacturerID */ - __IO uint16_t OEM_AppliID; /* OEM/Application ID */ - __IO uint32_t ProdName1; /* Product Name part1 */ - __IO uint8_t ProdName2; /* Product Name part2*/ - __IO uint8_t ProdRev; /* Product Revision */ - __IO uint32_t ProdSN; /* Product Serial Number */ - __IO uint8_t Reserved1; /* Reserved1 */ - __IO uint16_t ManufactDate; /* Manufacturing Date */ - __IO uint8_t CID_CRC; /* CID CRC */ - __IO uint8_t Reserved2; /* always 1 */ + uint8_t ManufacturerID; /* ManufacturerID */ + char OEM_AppliID[2]; /* OEM/Application ID */ + char ProdName[5]; /* Product Name */ + uint8_t ProdRev; /* Product Revision */ + uint32_t ProdSN; /* Product Serial Number */ + uint8_t Reserved1; /* Reserved1 */ + uint8_t ManufactYear; /* Manufacturing Year */ + uint8_t ManufactMonth; /* Manufacturing Month */ + uint8_t CID_CRC; /* CID CRC */ + uint8_t Reserved2; /* always 1 */ } SD_CID; /** @@ -207,6 +207,7 @@ uint8_t uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); uint8_t BSP_SD_GetCardState(void); uint8_t BSP_SD_GetCardInfo(SD_CardInfo* pCardInfo); +uint8_t BSP_SD_GetCIDRegister(SD_CID* Cid); /* Link functions for SD Card peripheral*/ void SD_SPI_Slow_Init(void); diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index 81a8bf60a..ad79ba33a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -17,7 +17,7 @@ void furi_hal_init_early() { furi_hal_os_init(); - furi_hal_spi_init_early(); + furi_hal_spi_config_init_early(); furi_hal_i2c_init_early(); furi_hal_light_init(); @@ -29,7 +29,7 @@ void furi_hal_deinit_early() { furi_hal_rtc_deinit_early(); furi_hal_i2c_deinit_early(); - furi_hal_spi_deinit_early(); + furi_hal_spi_config_deinit_early(); furi_hal_resources_deinit_early(); @@ -51,7 +51,7 @@ void furi_hal_init() { furi_hal_version_init(); - furi_hal_spi_init(); + furi_hal_spi_config_init(); furi_hal_ibutton_init(); FURI_LOG_I(TAG, "iButton OK"); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 4e10b90d7..79fbc693f 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -54,27 +54,25 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { }, }, }, - [FuriHalBtProfileHidKeyboard] = - { - .start = furi_hal_bt_hid_start, - .stop = furi_hal_bt_hid_stop, - .config = - { - .adv_service_uuid = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, - .appearance_char = GAP_APPEARANCE_KEYBOARD, - .bonding_mode = true, - .pairing_method = GapPairingPinCodeVerifyYesNo, - .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, - .conn_param = - { - .conn_int_min = 0x18, // 30 ms - .conn_int_max = 0x24, // 45 ms - .slave_latency = 0, - .supervisor_timeout = 0, - }, - }, - }, -}; + [FuriHalBtProfileHidKeyboard] = { + .start = furi_hal_bt_hid_start, + .stop = furi_hal_bt_hid_stop, + .config = + { + .adv_service_uuid = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, + .appearance_char = GAP_APPEARANCE_KEYBOARD, + .bonding_mode = true, + .pairing_method = GapPairingPinCodeVerifyYesNo, + .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, + .conn_param = + { + .conn_int_min = 0x18, // 30 ms + .conn_int_max = 0x24, // 45 ms + .slave_latency = 0, + .supervisor_timeout = 0, + }, + }, + }}; FuriHalBtProfileConfig* current_profile = NULL; void furi_hal_bt_init() { @@ -201,26 +199,26 @@ bool furi_hal_bt_start_app(FuriHalBtProfile profile, GapEventCallback event_cb, FURI_LOG_E(TAG, "Can't start Ble App - unsupported radio stack"); break; } - // Set mac address - memcpy( - profile_config[profile].config.mac_address, - furi_hal_version_get_ble_mac(), - sizeof(profile_config[profile].config.mac_address)); - // Set advertise name - strlcpy( - profile_config[profile].config.adv_name, - furi_hal_version_get_ble_local_device_name_ptr(), - FURI_HAL_VERSION_DEVICE_NAME_LENGTH); - // Configure GAP GapConfig* config = &profile_config[profile].config; + // Configure GAP if(profile == FuriHalBtProfileSerial) { + // Set mac address + memcpy( + profile_config[profile].config.mac_address, + furi_hal_version_get_ble_mac(), + sizeof(profile_config[profile].config.mac_address)); config->adv_service_uuid |= furi_hal_version_get_hw_color(); } else if(profile == FuriHalBtProfileHidKeyboard) { // Change MAC address for HID profile - config->mac_address[2]++; - // Change name Flipper -> Flipper Remote - const char* clicker_str = "Flipper Remote"; - memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str)); + uint8_t default_mac[GAP_MAC_ADDR_SIZE] = FURI_HAL_BT_DEFAULT_MAC_ADDR; + if(memcmp(config->mac_address, default_mac, 6) == 0) { + config->mac_address[2]++; + } + // Change name Flipper -> Control + if(strlen(&config->adv_name[1]) == 0) { + const char* clicker_str = "Control"; + memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str)); + } } if(!gap_init(config, event_cb, context)) { gap_thread_stop(); @@ -282,6 +280,10 @@ bool furi_hal_bt_is_active() { return gap_get_state() > GapStateIdle; } +bool furi_hal_bt_is_connected() { + return gap_get_state() == GapStateConnected; +} + void furi_hal_bt_start_advertising() { if(gap_get_state() == GapStateIdle) { gap_start_advertising(); @@ -420,6 +422,21 @@ float furi_hal_bt_get_rssi() { return val; } +/** fill the RSSI of the remote host of the bt connection and returns the last + * time the RSSI was updated + * +*/ +uint32_t furi_hal_bt_get_conn_rssi(uint8_t* rssi) { + int8_t ret_rssi = 0; + uint32_t since = gap_get_remote_conn_rssi(&ret_rssi); + + if(ret_rssi == 127 || since == 0) return 0; + + *rssi = (uint8_t)abs(ret_rssi); + + return since; +} + uint32_t furi_hal_bt_get_transmitted_packets() { uint32_t packets = 0; aci_hal_le_tx_test_packet_number(&packets); @@ -444,3 +461,45 @@ bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode) { FURI_LOG_E(TAG, "Failed to switch C2 mode: %d", fw_start_res); return false; } + +void furi_hal_bt_set_profile_adv_name( + FuriHalBtProfile profile, + const char name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH - 1]) { + furi_assert(profile < FuriHalBtProfileNumber); + furi_assert(name); + + profile_config[profile].config.adv_name[0] = 0x09; + memcpy( + &(profile_config[profile].config.adv_name[1]), + name, + FURI_HAL_VERSION_DEVICE_NAME_LENGTH - 1); +} + +const char* furi_hal_bt_get_profile_adv_name(FuriHalBtProfile profile) { + furi_assert(profile < FuriHalBtProfileNumber); + return &(profile_config[profile].config.adv_name[1]); +} + +void furi_hal_bt_set_profile_mac_addr( + FuriHalBtProfile profile, + const uint8_t mac_addr[GAP_MAC_ADDR_SIZE]) { + furi_assert(profile < FuriHalBtProfileNumber); + furi_assert(mac_addr); + + memcpy(profile_config[profile].config.mac_address, mac_addr, GAP_MAC_ADDR_SIZE); +} + +const uint8_t* furi_hal_bt_get_profile_mac_addr(FuriHalBtProfile profile) { + furi_assert(profile < FuriHalBtProfileNumber); + return profile_config[profile].config.mac_address; +} + +void furi_hal_bt_set_profile_pairing_method(FuriHalBtProfile profile, GapPairing pairing_method) { + furi_assert(profile < FuriHalBtProfileNumber); + profile_config[profile].config.pairing_method = pairing_method; +} + +GapPairing furi_hal_bt_get_profile_pairing_method(FuriHalBtProfile profile) { + furi_assert(profile < FuriHalBtProfileNumber); + return profile_config[profile].config.pairing_method; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c index ab3855f42..be0bd2af3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c @@ -1,5 +1,5 @@ -#include "furi_hal_bt_hid.h" -#include "furi_hal_usb_hid.h" +#include +#include #include "usb_hid.h" #include "dev_info_service.h" #include "battery_service.h" @@ -20,6 +20,7 @@ enum HidReportId { ReportIdKeyboard = 1, ReportIdMouse = 2, ReportIdConsumer = 3, + ReportIdLEDState = 4, }; // Report numbers corresponded to the report id with an offset of 1 enum HidInputNumber { @@ -63,12 +64,6 @@ static const uint8_t furi_hal_bt_hid_report_map_data[] = { HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_USAGE_PAGE(HID_PAGE_LED), - HID_REPORT_COUNT(8), - HID_REPORT_SIZE(1), - HID_USAGE_MINIMUM(1), - HID_USAGE_MAXIMUM(8), - HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_REPORT_COUNT(FURI_HAL_BT_HID_KB_MAX_KEYS), HID_REPORT_SIZE(8), HID_LOGICAL_MINIMUM(0), @@ -77,6 +72,13 @@ static const uint8_t furi_hal_bt_hid_report_map_data[] = { HID_USAGE_MINIMUM(0), HID_USAGE_MAXIMUM(101), HID_INPUT(HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), + HID_REPORT_ID(ReportIdLEDState), + HID_USAGE_PAGE(HID_PAGE_LED), + HID_REPORT_COUNT(8), + HID_REPORT_SIZE(1), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(8), + HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_END_COLLECTION, // Mouse Report HID_USAGE_PAGE(HID_PAGE_DESKTOP), @@ -125,6 +127,62 @@ FuriHalBtHidKbReport* kb_report = NULL; FuriHalBtHidMouseReport* mouse_report = NULL; FuriHalBtHidConsumerReport* consumer_report = NULL; +typedef struct { +// shortcuts +#define s_undefined data.bits.b_undefined +#define s_num_lock data.bits.b_num_lock +#define s_caps_lock data.bits.b_caps_lock +#define s_scroll_lock data.bits.b_scroll_lock +#define s_compose data.bits.b_compose +#define s_kana data.bits.b_kana +#define s_power data.bits.b_power +#define s_shift data.bits.b_shift +#define s_value data.value + union { + struct { + uint8_t b_undefined : 1; + uint8_t b_num_lock : 1; + uint8_t b_caps_lock : 1; + uint8_t b_scroll_lock : 1; + uint8_t b_compose : 1; + uint8_t b_kana : 1; + uint8_t b_power : 1; + uint8_t b_shift : 1; + } bits; + uint8_t value; + } data; +} __attribute__((__packed__)) FuriHalBtHidLedState; + +FuriHalBtHidLedState hid_host_led_state = {.s_value = 0}; + +uint16_t furi_hal_bt_hid_led_state_cb(uint8_t state, void* ctx) { + FuriHalBtHidLedState* led_state = (FuriHalBtHidLedState*)ctx; + + FURI_LOG_D("HalBtHid", "LED state updated !"); + + led_state->s_value = state; + + return 0; +} + +uint8_t furi_hal_bt_hid_get_led_state(void) { + FURI_LOG_D( + "HalBtHid", + "LED state: RFU=%d NUMLOCK=%d CAPSLOCK=%d SCROLLLOCK=%d COMPOSE=%d KANA=%d POWER=%d SHIFT=%d", + hid_host_led_state.s_undefined, + hid_host_led_state.s_num_lock, + hid_host_led_state.s_caps_lock, + hid_host_led_state.s_scroll_lock, + hid_host_led_state.s_compose, + hid_host_led_state.s_kana, + hid_host_led_state.s_power, + hid_host_led_state.s_shift); + + return (hid_host_led_state.s_value >> 1); // bit 0 is undefined (after shift bit location + // match with HID led state bits defines) + // see bad_kb_script.c (ducky_numlock_on function) +} + void furi_hal_bt_hid_start() { // Start device info if(!dev_info_svc_is_started()) { @@ -138,10 +196,13 @@ void furi_hal_bt_hid_start() { if(!hid_svc_is_started()) { hid_svc_start(); } - // Configure HID Keyboard + + hid_svc_register_led_state_callback(furi_hal_bt_hid_led_state_cb, &hid_host_led_state); + kb_report = malloc(sizeof(FuriHalBtHidKbReport)); mouse_report = malloc(sizeof(FuriHalBtHidMouseReport)); consumer_report = malloc(sizeof(FuriHalBtHidConsumerReport)); + // Configure Report Map characteristic hid_svc_update_report_map( furi_hal_bt_hid_report_map_data, sizeof(furi_hal_bt_hid_report_map_data)); @@ -160,6 +221,9 @@ void furi_hal_bt_hid_stop() { furi_assert(kb_report); furi_assert(mouse_report); furi_assert(consumer_report); + + hid_svc_register_led_state_callback(NULL, NULL); + // Stop all services if(dev_info_svc_is_started()) { dev_info_svc_stop(); @@ -180,12 +244,16 @@ void furi_hal_bt_hid_stop() { bool furi_hal_bt_hid_kb_press(uint16_t button) { furi_assert(kb_report); - for(uint8_t i = 0; i < FURI_HAL_BT_HID_KB_MAX_KEYS; i++) { + uint8_t i; + for(i = 0; i < FURI_HAL_BT_HID_KB_MAX_KEYS; i++) { if(kb_report->key[i] == 0) { kb_report->key[i] = button & 0xFF; break; } } + if(i == FURI_HAL_BT_HID_KB_MAX_KEYS) { + return false; + } kb_report->mods |= (button >> 8); return hid_svc_update_input_report( ReportNumberKeyboard, (uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport)); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c b/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c index aa09dde52..2539e6bd0 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c @@ -1,4 +1,4 @@ -#include "furi_hal_bt_serial.h" +#include #include "dev_info_service.h" #include "battery_service.h" #include "serial_service.h" diff --git a/firmware/targets/f7/furi_hal/furi_hal_cortex.c b/firmware/targets/f7/furi_hal/furi_hal_cortex.c index 192b83ee4..d0bce5038 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_cortex.c +++ b/firmware/targets/f7/furi_hal/furi_hal_cortex.c @@ -1,4 +1,4 @@ -#include "furi_hal_cortex.h" +#include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c b/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c index 678eb2965..afc4fdf52 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c @@ -1,4 +1,4 @@ -#include "furi_hal_i2c_config.h" +#include #include #include #include diff --git a/firmware/targets/furi_hal_include/furi_hal_ibutton.h b/firmware/targets/f7/furi_hal/furi_hal_ibutton.h similarity index 98% rename from firmware/targets/furi_hal_include/furi_hal_ibutton.h rename to firmware/targets/f7/furi_hal/furi_hal_ibutton.h index 84ef0cd6a..fb57d628b 100644 --- a/firmware/targets/furi_hal_include/furi_hal_ibutton.h +++ b/firmware/targets/f7/furi_hal/furi_hal_ibutton.h @@ -7,7 +7,7 @@ #include #include -#include "furi_hal_gpio.h" +#include #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index 7682b4118..5af43f4e5 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -1,4 +1,4 @@ -#include "furi_hal_infrared.h" +#include #include #include "stm32wbxx_ll_dma.h" #include "sys/_stdint.h" diff --git a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c b/firmware/targets/f7/furi_hal/furi_hal_interrupt.c index 038ae9489..1b1132d0c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_interrupt.c @@ -1,5 +1,5 @@ -#include "furi_hal_interrupt.h" -#include "furi_hal_os.h" +#include +#include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_light.c b/firmware/targets/f7/furi_hal/furi_hal_light.c index e6b3ab7d9..83e1603b7 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_light.c +++ b/firmware/targets/f7/furi_hal/furi_hal_light.c @@ -1,5 +1,5 @@ #include -#include "furi_hal_resources.h" +#include #include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 6381d1a91..ce81fd058 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -1,5 +1,5 @@ #include -#include "furi_hal_nfc.h" +#include #include #include #include diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_nfc.h rename to firmware/targets/f7/furi_hal/furi_hal_nfc.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.c b/firmware/targets/f7/furi_hal/furi_hal_pwm.c index e47f752ab..8f84b5fd8 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_pwm.c +++ b/firmware/targets/f7/furi_hal/furi_hal_pwm.c @@ -1,4 +1,4 @@ -#include "furi_hal_pwm.h" +#include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_random.c b/firmware/targets/f7/furi_hal/furi_hal_random.c index 2d1920903..780618052 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_random.c +++ b/firmware/targets/f7/furi_hal/furi_hal_random.c @@ -1,4 +1,4 @@ -#include "furi_hal_random.h" +#include #include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index 98ebedf51..4e63263cf 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.c @@ -8,9 +8,11 @@ const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin}; const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; const GpioPin gpio_cc1101_g0 = {.port = CC1101_G0_GPIO_Port, .pin = CC1101_G0_Pin}; +const GpioPin gpio_cc1101_g0_ext = {.port = GPIOB, .pin = LL_GPIO_PIN_2}; const GpioPin gpio_rf_sw_0 = {.port = RF_SW_0_GPIO_Port, .pin = RF_SW_0_Pin}; const GpioPin gpio_subghz_cs = {.port = CC1101_CS_GPIO_Port, .pin = CC1101_CS_Pin}; +const GpioPin gpio_subghz_cs_ext = {.port = GPIOA, .pin = LL_GPIO_PIN_4}; const GpioPin gpio_display_cs = {.port = DISPLAY_CS_GPIO_Port, .pin = DISPLAY_CS_Pin}; const GpioPin gpio_display_rst_n = {.port = DISPLAY_RST_GPIO_Port, .pin = DISPLAY_RST_Pin}; const GpioPin gpio_display_di = {.port = DISPLAY_DI_GPIO_Port, .pin = DISPLAY_DI_Pin}; @@ -31,6 +33,9 @@ const GpioPin gpio_spi_d_sck = {.port = SPI_D_SCK_GPIO_Port, .pin = SPI_D_SCK_Pi const GpioPin gpio_spi_r_miso = {.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin}; const GpioPin gpio_spi_r_mosi = {.port = SPI_R_MOSI_GPIO_Port, .pin = SPI_R_MOSI_Pin}; const GpioPin gpio_spi_r_sck = {.port = SPI_R_SCK_GPIO_Port, .pin = SPI_R_SCK_Pin}; +const GpioPin gpio_spi_r_miso_ext = {.port = GPIOA, .pin = LL_GPIO_PIN_6}; +const GpioPin gpio_spi_r_mosi_ext = {.port = GPIOA, .pin = LL_GPIO_PIN_7}; +const GpioPin gpio_spi_r_sck_ext = {.port = GPIOB, .pin = LL_GPIO_PIN_3}; const GpioPin gpio_ext_pc0 = {.port = GPIOC, .pin = LL_GPIO_PIN_0}; const GpioPin gpio_ext_pc1 = {.port = GPIOC, .pin = LL_GPIO_PIN_1}; @@ -62,6 +67,23 @@ const GpioPin periph_power = {.port = GPIOA, .pin = LL_GPIO_PIN_3}; const GpioPin gpio_usb_dm = {.port = GPIOA, .pin = LL_GPIO_PIN_11}; const GpioPin gpio_usb_dp = {.port = GPIOA, .pin = LL_GPIO_PIN_12}; +const GpioPinRecord gpio_pins[] = { + {.pin = &gpio_ext_pa7, .name = "PA7", .debug = false}, + {.pin = &gpio_ext_pa6, .name = "PA6", .debug = false}, + {.pin = &gpio_ext_pa4, .name = "PA4", .debug = false}, + {.pin = &gpio_ext_pb3, .name = "PB3", .debug = false}, + {.pin = &gpio_ext_pb2, .name = "PB2", .debug = false}, + {.pin = &gpio_ext_pc3, .name = "PC3", .debug = false}, + {.pin = &gpio_ext_pc1, .name = "PC1", .debug = false}, + {.pin = &gpio_ext_pc0, .name = "PC0", .debug = false}, + + /* Dangerous pins, may damage hardware */ + {.pin = &gpio_usart_rx, .name = "PB7", .debug = true}, + {.pin = &gpio_speaker, .name = "PB8", .debug = true}, +}; + +const size_t gpio_pins_count = sizeof(gpio_pins) / sizeof(GpioPinRecord); + const InputPin input_pins[] = { {.gpio = &gpio_button_up, .key = InputKeyUp, .inverted = true, .name = "Up"}, {.gpio = &gpio_button_down, .key = InputKeyDown, .inverted = true, .name = "Down"}, @@ -73,8 +95,18 @@ const InputPin input_pins[] = { const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); +static void furi_hal_resources_init_input_pins(GpioMode mode) { + for(size_t i = 0; i < input_pins_count; i++) { + furi_hal_gpio_init( + input_pins[i].gpio, + mode, + (input_pins[i].inverted) ? GpioPullUp : GpioPullDown, + GpioSpeedLow); + } +} + void furi_hal_resources_init_early() { - furi_hal_gpio_init(&gpio_button_left, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_resources_init_input_pins(GpioModeInput); // SD Card stepdown control furi_hal_gpio_write(&periph_power, 1); @@ -117,14 +149,12 @@ void furi_hal_resources_init_early() { } void furi_hal_resources_deinit_early() { + furi_hal_resources_init_input_pins(GpioModeAnalog); } void furi_hal_resources_init() { // Button pins - for(size_t i = 0; i < input_pins_count; i++) { - furi_hal_gpio_init( - input_pins[i].gpio, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedLow); - } + furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall); // Display pins furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); @@ -166,3 +196,26 @@ void furi_hal_resources_init() { NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(EXTI15_10_IRQn); } + +int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) { + if(gpio == &gpio_ext_pa7) + return 2; + else if(gpio == &gpio_ext_pa6) + return 3; + else if(gpio == &gpio_ext_pa4) + return 4; + else if(gpio == &gpio_ext_pb3) + return 5; + else if(gpio == &gpio_ext_pb2) + return 6; + else if(gpio == &gpio_ext_pc3) + return 7; + else if(gpio == &gpio_ext_pc1) + return 15; + else if(gpio == &gpio_ext_pc0) + return 16; + else if(gpio == &ibutton_gpio) + return 17; + else + return -1; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.h b/firmware/targets/f7/furi_hal/furi_hal_resources.h index 64e5e19f9..33e2a3289 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.h +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.h @@ -38,16 +38,27 @@ typedef struct { const char* name; } InputPin; +typedef struct { + const GpioPin* pin; + const char* name; + const bool debug; +} GpioPinRecord; + extern const InputPin input_pins[]; extern const size_t input_pins_count; +extern const GpioPinRecord gpio_pins[]; +extern const size_t gpio_pins_count; + extern const GpioPin vibro_gpio; extern const GpioPin ibutton_gpio; extern const GpioPin gpio_cc1101_g0; +extern const GpioPin gpio_cc1101_g0_ext; extern const GpioPin gpio_rf_sw_0; extern const GpioPin gpio_subghz_cs; +extern const GpioPin gpio_subghz_cs_ext; extern const GpioPin gpio_display_cs; extern const GpioPin gpio_display_rst_n; extern const GpioPin gpio_display_di; @@ -68,6 +79,9 @@ extern const GpioPin gpio_spi_d_sck; extern const GpioPin gpio_spi_r_miso; extern const GpioPin gpio_spi_r_mosi; extern const GpioPin gpio_spi_r_sck; +extern const GpioPin gpio_spi_r_miso_ext; +extern const GpioPin gpio_spi_r_mosi_ext; +extern const GpioPin gpio_spi_r_sck_ext; extern const GpioPin gpio_ext_pc0; extern const GpioPin gpio_ext_pc1; @@ -207,6 +221,13 @@ void furi_hal_resources_deinit_early(); void furi_hal_resources_init(); +/** + * Get a corresponding external connector pin number for a gpio + * @param gpio GpioPin + * @return pin number or -1 if gpio is not on the external connector + */ +int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/furi_hal_include/furi_hal_rfid.h b/firmware/targets/f7/furi_hal/furi_hal_rfid.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_rfid.h rename to firmware/targets/f7/furi_hal/furi_hal_rfid.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_sd.c b/firmware/targets/f7/furi_hal/furi_hal_sd.c index 688a4e61b..1b0de5628 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_sd.c +++ b/firmware/targets/f7/furi_hal/furi_hal_sd.c @@ -1,24 +1,21 @@ -#include "furi_hal_sd.h" +#include #include #include #include void hal_sd_detect_init(void) { // low speed input with pullup - LL_GPIO_SetPinMode(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_MODE_INPUT); - LL_GPIO_SetPinSpeed(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_SPEED_FREQ_LOW); - LL_GPIO_SetPinPull(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_PULL_UP); + furi_hal_gpio_init(&gpio_sdcard_cd, GpioModeInput, GpioPullUp, GpioSpeedLow); } void hal_sd_detect_set_low(void) { // low speed input with pullup - LL_GPIO_SetPinMode(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_MODE_OUTPUT); - LL_GPIO_SetPinOutputType(SD_CD_GPIO_Port, SD_CD_Pin, LL_GPIO_OUTPUT_OPENDRAIN); - LL_GPIO_ResetOutputPin(SD_CD_GPIO_Port, SD_CD_Pin); + furi_hal_gpio_init_simple(&gpio_sdcard_cd, GpioModeOutputOpenDrain); + furi_hal_gpio_write(&gpio_sdcard_cd, 0); } bool hal_sd_detect(void) { - bool result = !(LL_GPIO_IsInputPinSet(SD_CD_GPIO_Port, SD_CD_Pin)); + bool result = !furi_hal_gpio_read(&gpio_sdcard_cd); return result; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi.c b/firmware/targets/f7/furi_hal/furi_hal_spi.c index 2d54278d6..42b854799 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi.c @@ -1,36 +1,31 @@ -#include "furi_hal_spi.h" -#include "furi_hal_resources.h" -#include - -#include -#include #include +#include +#include +#include +#include +#include #include #include #include #define TAG "FuriHalSpi" -void furi_hal_spi_init_early() { - furi_hal_spi_bus_init(&furi_hal_spi_bus_d); - furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display); -} +#define SPI_DMA DMA2 +#define SPI_DMA_RX_CHANNEL LL_DMA_CHANNEL_3 +#define SPI_DMA_TX_CHANNEL LL_DMA_CHANNEL_4 +#define SPI_DMA_RX_IRQ FuriHalInterruptIdDma2Ch3 +#define SPI_DMA_TX_IRQ FuriHalInterruptIdDma2Ch4 +#define SPI_DMA_RX_DEF SPI_DMA, SPI_DMA_RX_CHANNEL +#define SPI_DMA_TX_DEF SPI_DMA, SPI_DMA_TX_CHANNEL -void furi_hal_spi_deinit_early() { - furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_display); - furi_hal_spi_bus_deinit(&furi_hal_spi_bus_d); -} +// For simplicity, I assume that only one SPI DMA transaction can occur at a time. +static FuriSemaphore* spi_dma_lock = NULL; +static FuriSemaphore* spi_dma_completed = NULL; -void furi_hal_spi_init() { - furi_hal_spi_bus_init(&furi_hal_spi_bus_r); - - furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); - furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast); - furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow); - - FURI_LOG_I(TAG, "Init OK"); +void furi_hal_spi_dma_init() { + spi_dma_lock = furi_semaphore_alloc(1, 1); + spi_dma_completed = furi_semaphore_alloc(1, 1); } void furi_hal_spi_bus_init(FuriHalSpiBus* bus) { @@ -108,7 +103,7 @@ bool furi_hal_spi_bus_rx( bool furi_hal_spi_bus_tx( FuriHalSpiBusHandle* handle, - uint8_t* buffer, + const uint8_t* buffer, size_t size, uint32_t timeout) { furi_assert(handle); @@ -133,7 +128,7 @@ bool furi_hal_spi_bus_tx( bool furi_hal_spi_bus_trx( FuriHalSpiBusHandle* handle, - uint8_t* tx_buffer, + const uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) { @@ -173,3 +168,209 @@ bool furi_hal_spi_bus_trx( return ret; } + +static void spi_dma_isr() { +#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_3 + if(LL_DMA_IsActiveFlag_TC3(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_RX_DEF)) { + LL_DMA_ClearFlag_TC3(SPI_DMA); + furi_check(furi_semaphore_release(spi_dma_completed) == FuriStatusOk); + } +#else +#error Update this code. Would you kindly? +#endif + +#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_4 + if(LL_DMA_IsActiveFlag_TC4(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_TX_DEF)) { + LL_DMA_ClearFlag_TC4(SPI_DMA); + furi_check(furi_semaphore_release(spi_dma_completed) == FuriStatusOk); + } +#else +#error Update this code. Would you kindly? +#endif +} + +bool furi_hal_spi_bus_trx_dma( + FuriHalSpiBusHandle* handle, + uint8_t* tx_buffer, + uint8_t* rx_buffer, + size_t size, + uint32_t timeout_ms) { + furi_assert(handle); + furi_assert(handle->bus->current_handle == handle); + furi_assert(size > 0); + + // If scheduler is not running, use blocking mode + if(xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { + return furi_hal_spi_bus_trx(handle, tx_buffer, rx_buffer, size, timeout_ms); + } + + // Lock DMA + furi_check(furi_semaphore_acquire(spi_dma_lock, FuriWaitForever) == FuriStatusOk); + + const uint32_t dma_dummy_u32 = 0xFFFFFFFF; + + bool ret = true; + SPI_TypeDef* spi = handle->bus->spi; + uint32_t dma_rx_req; + uint32_t dma_tx_req; + + if(spi == SPI1) { + dma_rx_req = LL_DMAMUX_REQ_SPI1_RX; + dma_tx_req = LL_DMAMUX_REQ_SPI1_TX; + } else if(spi == SPI2) { + dma_rx_req = LL_DMAMUX_REQ_SPI2_RX; + dma_tx_req = LL_DMAMUX_REQ_SPI2_TX; + } else { + furi_crash(NULL); + } + + if(rx_buffer == NULL) { + // Only TX mode, do not use RX channel + + LL_DMA_InitTypeDef dma_config = {0}; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (spi->DR); + dma_config.MemoryOrM2MDstAddress = (uint32_t)tx_buffer; + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_NORMAL; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE; + dma_config.NbData = size; + dma_config.PeriphRequest = dma_tx_req; + dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; + LL_DMA_Init(SPI_DMA_TX_DEF, &dma_config); + +#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_4 + LL_DMA_ClearFlag_TC4(SPI_DMA); +#else +#error Update this code. Would you kindly? +#endif + + furi_hal_interrupt_set_isr(SPI_DMA_TX_IRQ, spi_dma_isr, NULL); + + bool dma_tx_was_enabled = LL_SPI_IsEnabledDMAReq_TX(spi); + if(!dma_tx_was_enabled) { + LL_SPI_EnableDMAReq_TX(spi); + } + + // acquire semaphore before enabling DMA + furi_check(furi_semaphore_acquire(spi_dma_completed, timeout_ms) == FuriStatusOk); + + LL_DMA_EnableIT_TC(SPI_DMA_TX_DEF); + LL_DMA_EnableChannel(SPI_DMA_TX_DEF); + + // and wait for it to be released (DMA transfer complete) + if(furi_semaphore_acquire(spi_dma_completed, timeout_ms) != FuriStatusOk) { + ret = false; + FURI_LOG_E(TAG, "DMA timeout\r\n"); + } + // release semaphore, because we are using it as a flag + furi_semaphore_release(spi_dma_completed); + + LL_DMA_DisableIT_TC(SPI_DMA_TX_DEF); + LL_DMA_DisableChannel(SPI_DMA_TX_DEF); + if(!dma_tx_was_enabled) { + LL_SPI_DisableDMAReq_TX(spi); + } + furi_hal_interrupt_set_isr(SPI_DMA_TX_IRQ, NULL, NULL); + + LL_DMA_DeInit(SPI_DMA_TX_DEF); + } else { + // TRX or RX mode, use both channels + uint32_t tx_mem_increase_mode; + + if(tx_buffer == NULL) { + // RX mode, use dummy data instead of TX buffer + tx_buffer = (uint8_t*)&dma_dummy_u32; + tx_mem_increase_mode = LL_DMA_PERIPH_NOINCREMENT; + } else { + tx_mem_increase_mode = LL_DMA_MEMORY_INCREMENT; + } + + LL_DMA_InitTypeDef dma_config = {0}; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (spi->DR); + dma_config.MemoryOrM2MDstAddress = (uint32_t)tx_buffer; + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_NORMAL; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = tx_mem_increase_mode; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE; + dma_config.NbData = size; + dma_config.PeriphRequest = dma_tx_req; + dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; + LL_DMA_Init(SPI_DMA_TX_DEF, &dma_config); + + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (spi->DR); + dma_config.MemoryOrM2MDstAddress = (uint32_t)rx_buffer; + dma_config.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + dma_config.Mode = LL_DMA_MODE_NORMAL; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE; + dma_config.NbData = size; + dma_config.PeriphRequest = dma_rx_req; + dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; + LL_DMA_Init(SPI_DMA_RX_DEF, &dma_config); + +#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_3 + LL_DMA_ClearFlag_TC3(SPI_DMA); +#else +#error Update this code. Would you kindly? +#endif + + furi_hal_interrupt_set_isr(SPI_DMA_RX_IRQ, spi_dma_isr, NULL); + + bool dma_tx_was_enabled = LL_SPI_IsEnabledDMAReq_TX(spi); + bool dma_rx_was_enabled = LL_SPI_IsEnabledDMAReq_RX(spi); + + if(!dma_tx_was_enabled) { + LL_SPI_EnableDMAReq_TX(spi); + } + + if(!dma_rx_was_enabled) { + LL_SPI_EnableDMAReq_RX(spi); + } + + // acquire semaphore before enabling DMA + furi_check(furi_semaphore_acquire(spi_dma_completed, timeout_ms) == FuriStatusOk); + + LL_DMA_EnableIT_TC(SPI_DMA_RX_DEF); + LL_DMA_EnableChannel(SPI_DMA_RX_DEF); + LL_DMA_EnableChannel(SPI_DMA_TX_DEF); + + // and wait for it to be released (DMA transfer complete) + if(furi_semaphore_acquire(spi_dma_completed, timeout_ms) != FuriStatusOk) { + ret = false; + FURI_LOG_E(TAG, "DMA timeout\r\n"); + } + // release semaphore, because we are using it as a flag + furi_semaphore_release(spi_dma_completed); + + LL_DMA_DisableIT_TC(SPI_DMA_RX_DEF); + + LL_DMA_DisableChannel(SPI_DMA_TX_DEF); + LL_DMA_DisableChannel(SPI_DMA_RX_DEF); + + if(!dma_tx_was_enabled) { + LL_SPI_DisableDMAReq_TX(spi); + } + + if(!dma_rx_was_enabled) { + LL_SPI_DisableDMAReq_RX(spi); + } + + furi_hal_interrupt_set_isr(SPI_DMA_RX_IRQ, NULL, NULL); + + LL_DMA_DeInit(SPI_DMA_TX_DEF); + LL_DMA_DeInit(SPI_DMA_RX_DEF); + } + + furi_hal_spi_bus_end_txrx(handle, timeout_ms); + + furi_check(furi_semaphore_release(spi_dma_lock) == FuriStatusOk); + + return ret; +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c index 56f67bbf8..695418af1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c @@ -1,5 +1,10 @@ #include #include +#include +#include +#include + +#define TAG "FuriHalSpiConfig" /* SPI Presets */ @@ -72,6 +77,27 @@ const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = { FuriMutex* furi_hal_spi_bus_r_mutex = NULL; +void furi_hal_spi_config_init_early() { + furi_hal_spi_bus_init(&furi_hal_spi_bus_d); + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display); +} + +void furi_hal_spi_config_deinit_early() { + furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_display); + furi_hal_spi_bus_deinit(&furi_hal_spi_bus_d); +} + +void furi_hal_spi_config_init() { + furi_hal_spi_bus_init(&furi_hal_spi_bus_r); + + furi_hal_spi_bus_handle_init(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast); + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow); + + FURI_LOG_I(TAG, "Init OK"); +} + static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal); @@ -260,6 +286,15 @@ static void furi_hal_spi_bus_handle_subghz_event_callback( furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_8m); } +FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz_int = { + .bus = &furi_hal_spi_bus_r, + .callback = furi_hal_spi_bus_handle_subghz_event_callback, + .miso = &gpio_spi_r_miso, + .mosi = &gpio_spi_r_mosi, + .sck = &gpio_spi_r_sck, + .cs = &gpio_subghz_cs, +}; + FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = { .bus = &furi_hal_spi_bus_r, .callback = furi_hal_spi_bus_handle_subghz_event_callback, @@ -269,6 +304,15 @@ FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = { .cs = &gpio_subghz_cs, }; +FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz_ext = { + .bus = &furi_hal_spi_bus_r, + .callback = furi_hal_spi_bus_handle_subghz_event_callback, + .miso = &gpio_ext_pa6, + .mosi = &gpio_ext_pa7, + .sck = &gpio_ext_pb3, + .cs = &gpio_ext_pa4, +}; + static void furi_hal_spi_bus_handle_nfc_event_callback( FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_config.h b/firmware/targets/f7/furi_hal/furi_hal_spi_config.h index eab633a19..8ea138bdc 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_config.h +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_config.h @@ -27,8 +27,12 @@ extern FuriHalSpiBus furi_hal_spi_bus_r; /** Furi Hal Spi Bus D (Display, SdCard) */ extern FuriHalSpiBus furi_hal_spi_bus_d; -/** CC1101 on `furi_hal_spi_bus_r` */ +/** CC1101 on current SPI bus */ extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz; +/** CC1101 on `furi_hal_spi_bus_r` */ +extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz_int; +/** CC1101 on external `furi_hal_spi_bus_r` */ +extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz_ext; /** ST25R3916 on `furi_hal_spi_bus_r` */ extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc; diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index fdeb5c742..0fe5d1878 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -1,111 +1,204 @@ -#include "furi_hal_subghz.h" -#include "furi_hal_subghz_configs.h" - +#include +#include #include #include #include #include #include #include - -#include +#include #include +#include + #include #include #include #define TAG "FuriHalSubGhz" +//Initialisation timeout (ms) +#define INIT_TIMEOUT 10 static uint32_t furi_hal_subghz_debug_gpio_buff[2]; +static bool last_OTG_state = false; -typedef struct { - volatile SubGhzState state; - volatile SubGhzRegulation regulation; - volatile FuriHalSubGhzPreset preset; - const GpioPin* async_mirror_pin; -} FuriHalSubGhz; +/* DMA Channels definition */ +#define SUBGHZ_DMA DMA2 +#define SUBGHZ_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 +#define SUBGHZ_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 +#define SUBGHZ_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 +#define SUBGHZ_DMA_CH1_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH1_CHANNEL +#define SUBGHZ_DMA_CH2_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH2_CHANNEL volatile FuriHalSubGhz furi_hal_subghz = { .state = SubGhzStateInit, .regulation = SubGhzRegulationTxRx, .preset = FuriHalSubGhzPresetIDLE, .async_mirror_pin = NULL, + .radio_type = SubGhzRadioInternal, + .spi_bus_handle = &furi_hal_spi_bus_handle_subghz, + .cc1101_g0_pin = &gpio_cc1101_g0, }; +bool furi_hal_subghz_set_radio_type(SubGhzRadioType state) { + furi_hal_subghz.radio_type = state; + furi_hal_spi_bus_handle_deinit(furi_hal_subghz.spi_bus_handle); + if(state) { + furi_hal_subghz.spi_bus_handle = &furi_hal_spi_bus_handle_subghz_ext; + furi_hal_subghz.cc1101_g0_pin = &gpio_cc1101_g0_ext; + } else { + furi_hal_subghz.spi_bus_handle = &furi_hal_spi_bus_handle_subghz; + furi_hal_subghz.cc1101_g0_pin = &gpio_cc1101_g0; + } + furi_hal_spi_bus_handle_init(furi_hal_subghz.spi_bus_handle); + furi_hal_subghz_init_check(); + return true; +} + +SubGhzRadioType furi_hal_subghz_get_radio_type(void) { + return furi_hal_subghz.radio_type; +} + void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin) { furi_hal_subghz.async_mirror_pin = pin; } -void furi_hal_subghz_init() { +void furi_hal_subghz_init(void) { + furi_hal_subghz_init_check(); +} + +void furi_hal_subghz_enable_ext_power(void) { + if(furi_hal_subghz.radio_type != SubGhzRadioInternal && !furi_hal_power_is_otg_enabled()) { + furi_hal_power_enable_otg(); + } +} + +void furi_hal_subghz_disable_ext_power(void) { + if(furi_hal_subghz.radio_type != SubGhzRadioInternal && !last_OTG_state) { + furi_hal_power_disable_otg(); + } +} + +bool furi_hal_subghz_check_radio(void) { + bool result = true; + + furi_hal_subghz_enable_ext_power(); + + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + uint8_t ver = cc1101_get_version(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); + + if((ver != 0) && (ver != 255)) { + FURI_LOG_D(TAG, "Radio check ok"); + } else { + FURI_LOG_D(TAG, "Radio check failed"); + furi_hal_subghz_disable_ext_power(); + result = false; + } + return result; +} + +bool furi_hal_subghz_init_check(void) { + bool result = true; + furi_assert(furi_hal_subghz.state == SubGhzStateInit); furi_hal_subghz.state = SubGhzStateIdle; furi_hal_subghz.preset = FuriHalSubGhzPresetIDLE; - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + last_OTG_state = furi_hal_power_is_otg_enabled(); + furi_hal_subghz_enable_ext_power(); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); #ifdef FURI_HAL_SUBGHZ_TX_GPIO furi_hal_gpio_init(&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); #endif // Reset - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - cc1101_reset(&furi_hal_spi_bus_handle_subghz); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_reset(furi_hal_subghz.spi_bus_handle); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); // Prepare GD0 for power on self test - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { + // GD0 low + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); + uint32_t test_start_time = furi_get_tick(); + while(furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin) != false && result) { + if(furi_get_tick() - test_start_time > INIT_TIMEOUT) { + result = false; + } + } - // GD0 low - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW); - while(furi_hal_gpio_read(&gpio_cc1101_g0) != false) - ; - - // GD0 high - cc1101_write_reg( - &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); - while(furi_hal_gpio_read(&gpio_cc1101_g0) != true) - ; + // GD0 high + cc1101_write_reg( + furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + test_start_time = furi_get_tick(); + while(furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin) != true && result) { + if(furi_get_tick() - test_start_time > INIT_TIMEOUT) { + result = false; + } + } + } else { + // GD0 low + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); + while(furi_hal_gpio_read(&gpio_cc1101_g0) != false) + ; + // GD0 high + cc1101_write_reg( + furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + while(furi_hal_gpio_read(&gpio_cc1101_g0) != true) + ; + } // Reset GD0 to floating state - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); // RF switches furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW); // Go to sleep - cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); + cc1101_shutdown(furi_hal_subghz.spi_bus_handle); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); - FURI_LOG_I(TAG, "Init OK"); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); + + if(result) { + FURI_LOG_I(TAG, "Init OK"); + } else { + FURI_LOG_E(TAG, "Failed to initialization"); + furi_hal_subghz_disable_ext_power(); + } + return result; } void furi_hal_subghz_sleep() { furi_assert(furi_hal_subghz.state == SubGhzStateIdle); - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); - cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz); + cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); + cc1101_shutdown(furi_hal_subghz.spi_bus_handle); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); + + furi_hal_subghz_disable_ext_power(); furi_hal_subghz.preset = FuriHalSubGhzPresetIDLE; } void furi_hal_subghz_dump_state() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); printf( "[furi_hal_subghz] cc1101 chip %d, version %d\r\n", - cc1101_get_partnumber(&furi_hal_spi_bus_handle_subghz), - cc1101_get_version(&furi_hal_spi_bus_handle_subghz)); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + cc1101_get_partnumber(furi_hal_subghz.spi_bus_handle), + cc1101_get_version(furi_hal_subghz.spi_bus_handle)); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) { @@ -137,15 +230,15 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) { void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) { //load config - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_reset(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_reset(furi_hal_subghz.spi_bus_handle); uint32_t i = 0; uint8_t pa[8] = {0}; while(preset_data[i]) { - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, preset_data[i], preset_data[i + 1]); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, preset_data[i], preset_data[i + 1]); i += 2; } - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); //load pa table memcpy(&pa[0], &preset_data[i + 2], 8); @@ -167,48 +260,48 @@ void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) { } void furi_hal_subghz_load_registers(uint8_t* data) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_reset(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_reset(furi_hal_subghz.spi_bus_handle); uint32_t i = 0; while(data[i]) { - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i], data[i + 1]); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, data[i], data[i + 1]); i += 2; } - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } void furi_hal_subghz_load_patable(const uint8_t data[8]) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_set_pa_table(&furi_hal_spi_bus_handle_subghz, data); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_set_pa_table(furi_hal_subghz.spi_bus_handle, data); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_FIFO, size); - cc1101_write_fifo(&furi_hal_spi_bus_handle_subghz, data, size); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_flush_tx(furi_hal_subghz.spi_bus_handle); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_FIFO, size); + cc1101_write_fifo(furi_hal_subghz.spi_bus_handle, data, size); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } void furi_hal_subghz_flush_rx() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_flush_rx(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_flush_rx(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } void furi_hal_subghz_flush_tx() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_flush_tx(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } bool furi_hal_subghz_rx_pipe_not_empty() { CC1101RxBytes status[1]; - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); cc1101_read_reg( - &furi_hal_spi_bus_handle_subghz, (CC1101_STATUS_RXBYTES) | CC1101_BURST, (uint8_t*)status); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_subghz.spi_bus_handle, (CC1101_STATUS_RXBYTES) | CC1101_BURST, (uint8_t*)status); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); // TODO: you can add a buffer overflow flag if needed if(status->NUM_RXBYTES > 0) { return true; @@ -218,10 +311,10 @@ bool furi_hal_subghz_rx_pipe_not_empty() { } bool furi_hal_subghz_is_rx_data_crc_valid() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); uint8_t data[1]; - cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, CC1101_STATUS_LQI | CC1101_BURST, data); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + cc1101_read_reg(furi_hal_subghz.spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); if(((data[0] >> 7) & 0x01)) { return true; } else { @@ -230,51 +323,52 @@ bool furi_hal_subghz_is_rx_data_crc_valid() { } void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_read_fifo(&furi_hal_spi_bus_handle_subghz, data, size); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_read_fifo(furi_hal_subghz.spi_bus_handle, data, size); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } void furi_hal_subghz_shutdown() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); // Reset and shutdown - cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + cc1101_shutdown(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); + furi_hal_subghz_disable_ext_power(); } void furi_hal_subghz_reset() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz); - cc1101_reset(&furi_hal_spi_bus_handle_subghz); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle); + cc1101_reset(furi_hal_subghz.spi_bus_handle); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } void furi_hal_subghz_idle() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } void furi_hal_subghz_rx() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_switch_to_rx(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } bool furi_hal_subghz_tx() { - // if(furi_hal_subghz.regulation != SubGhzRegulationTxRx) return false; - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - cc1101_switch_to_tx(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + if(furi_hal_subghz.regulation != SubGhzRegulationTxRx) return false; + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + cc1101_switch_to_tx(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); return true; } float furi_hal_subghz_get_rssi() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - int32_t rssi_dec = cc1101_get_rssi(&furi_hal_spi_bus_handle_subghz); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + int32_t rssi_dec = cc1101_get_rssi(furi_hal_subghz.spi_bus_handle); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); float rssi = rssi_dec; if(rssi_dec >= 128) { @@ -287,10 +381,10 @@ float furi_hal_subghz_get_rssi() { } uint8_t furi_hal_subghz_get_lqi() { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); uint8_t data[1]; - cc1101_read_reg(&furi_hal_spi_bus_handle_subghz, CC1101_STATUS_LQI | CC1101_BURST, data); - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + cc1101_read_reg(furi_hal_subghz.spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); return data[0] & 0x7F; } @@ -299,6 +393,7 @@ uint8_t furi_hal_subghz_get_lqi() { These changes are at your own risk. The PLL may not lock and FZ devs have warned of possible damage Set flag use_ext_range_at_own_risk in extend_range.txt to use */ + bool furi_hal_subghz_is_frequency_valid(uint32_t value) { if(!(value >= 281000000 && value <= 361000000) && !(value >= 378000000 && value <= 481000000) && @@ -325,16 +420,18 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) { } bool furi_hal_subghz_is_tx_allowed(uint32_t value) { - //checking regional settings bool is_extended = false; bool is_allowed = false; + // TODO: !!! Move file check to another place Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + if(flipper_format_file_open_existing(fff_data_file, "/ext/subghz/assets/extend_range.txt")) { flipper_format_read_bool(fff_data_file, "use_ext_range_at_own_risk", &is_extended, 1); flipper_format_read_bool(fff_data_file, "ignore_default_tx_region", &is_allowed, 1); } + flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); @@ -380,16 +477,17 @@ bool furi_hal_subghz_is_tx_allowed(uint32_t value) { if(!(value >= 299999755 && value <= 348000335) && !(value >= 386999938 && value <= 464000000) && !(value >= 778999847 && value <= 928000000) && !(is_extended)) { - FURI_LOG_I(TAG, "Frequency blocked - outside standard range"); - is_allowed = false; + FURI_LOG_I(TAG, "Frequency blocked - outside regional range"); + return false; } else if( !(value >= 281000000 && value <= 361000000) && !(value >= 378000000 && value <= 481000000) && !(value >= 749000000 && value <= 962000000) && is_extended) { FURI_LOG_I(TAG, "Frequency blocked - outside extended range"); - is_allowed = false; + return false; } - return is_allowed; + + return true; } uint32_t furi_hal_subghz_set_frequency(uint32_t value) { @@ -398,40 +496,39 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) { } else { furi_hal_subghz.regulation = SubGhzRegulationTxRx; } - - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - uint32_t real_frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, value); - cc1101_calibrate(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); + uint32_t real_frequency = cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, value); + cc1101_calibrate(furi_hal_subghz.spi_bus_handle); while(true) { - CC1101Status status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz); + CC1101Status status = cc1101_get_status(furi_hal_subghz.spi_bus_handle); if(status.STATE == CC1101StateIDLE) break; } - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); return real_frequency; } void furi_hal_subghz_set_path(FuriHalSubGhzPath path) { - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); if(path == FuriHalSubGhzPath433) { furi_hal_gpio_write(&gpio_rf_sw_0, 0); cc1101_write_reg( - &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); + furi_hal_subghz.spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); } else if(path == FuriHalSubGhzPath315) { furi_hal_gpio_write(&gpio_rf_sw_0, 1); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW); } else if(path == FuriHalSubGhzPath868) { furi_hal_gpio_write(&gpio_rf_sw_0, 1); cc1101_write_reg( - &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); + furi_hal_subghz.spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV); } else if(path == FuriHalSubGhzPathIsolate) { furi_hal_gpio_write(&gpio_rf_sw_0, 0); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); + cc1101_write_reg(furi_hal_subghz.spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW); } else { furi_crash("SubGhz: Incorrect path during set."); } - furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); + furi_hal_spi_release(furi_hal_subghz.spi_bus_handle); } static bool furi_hal_subghz_start_debug() { @@ -462,31 +559,53 @@ volatile FuriHalSubGhzCaptureCallback furi_hal_subghz_capture_callback = NULL; volatile void* furi_hal_subghz_capture_callback_context = NULL; static void furi_hal_subghz_capture_ISR() { - // Channel 1 - if(LL_TIM_IsActiveFlag_CC1(TIM2)) { - LL_TIM_ClearFlag_CC1(TIM2); - furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); - if(furi_hal_subghz_capture_callback) { - if(furi_hal_subghz.async_mirror_pin != NULL) - furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); + if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { + if(!furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin)) { + if(furi_hal_subghz_capture_callback) { + if(furi_hal_subghz.async_mirror_pin != NULL) + furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); - furi_hal_subghz_capture_callback( - true, - furi_hal_subghz_capture_delta_duration, - (void*)furi_hal_subghz_capture_callback_context); + furi_hal_subghz_capture_callback( + true, TIM2->CNT, (void*)furi_hal_subghz_capture_callback_context); + } + } else { + if(furi_hal_subghz_capture_callback) { + if(furi_hal_subghz.async_mirror_pin != NULL) + furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true); + + furi_hal_subghz_capture_callback( + false, TIM2->CNT, (void*)furi_hal_subghz_capture_callback_context); + } } - } - // Channel 2 - if(LL_TIM_IsActiveFlag_CC2(TIM2)) { - LL_TIM_ClearFlag_CC2(TIM2); - if(furi_hal_subghz_capture_callback) { - if(furi_hal_subghz.async_mirror_pin != NULL) - furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true); + //Forced correction for improved accuracy + TIM2->CNT = 9; + } else { + // Channel 1 + if(LL_TIM_IsActiveFlag_CC1(TIM2)) { + LL_TIM_ClearFlag_CC1(TIM2); + furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); + if(furi_hal_subghz_capture_callback) { + if(furi_hal_subghz.async_mirror_pin != NULL) + furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); - furi_hal_subghz_capture_callback( - false, - LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, - (void*)furi_hal_subghz_capture_callback_context); + furi_hal_subghz_capture_callback( + true, + furi_hal_subghz_capture_delta_duration, + (void*)furi_hal_subghz_capture_callback_context); + } + } + // Channel 2 + if(LL_TIM_IsActiveFlag_CC2(TIM2)) { + LL_TIM_ClearFlag_CC2(TIM2); + if(furi_hal_subghz_capture_callback) { + if(furi_hal_subghz.async_mirror_pin != NULL) + furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true); + + furi_hal_subghz_capture_callback( + false, + LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, + (void*)furi_hal_subghz_capture_callback_context); + } } } } @@ -498,47 +617,64 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* furi_hal_subghz_capture_callback = callback; furi_hal_subghz_capture_callback_context = context; - furi_hal_gpio_init_ex( - &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, + GpioModeInterruptRiseFall, + GpioPullUp, + GpioSpeedVeryHigh); + furi_hal_gpio_add_int_callback( + furi_hal_subghz.cc1101_g0_pin, + furi_hal_subghz_capture_ISR, + furi_hal_subghz_capture_callback); + furi_hal_gpio_enable_int_callback(furi_hal_subghz.cc1101_g0_pin); + } else { + furi_hal_gpio_init_ex( + &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + } // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 0x7FFFFFFE; - TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV4; + TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV4; // Clock division for capture filter LL_TIM_Init(TIM2, &TIM_InitStruct); // Timer: advanced LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_DisableARRPreload(TIM2); - LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI2FP2); - LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); - LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); - LL_TIM_EnableMasterSlaveMode(TIM2); + if(furi_hal_subghz.radio_type == SubGhzRadioInternal) { + LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI2FP2); + LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); + LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); + LL_TIM_EnableMasterSlaveMode(TIM2); + } LL_TIM_DisableDMAReq_TRIG(TIM2); LL_TIM_DisableIT_TRIG(TIM2); - // Timer: channel 1 indirect - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_INDIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); + if(furi_hal_subghz.radio_type == SubGhzRadioInternal) { + // Timer: channel 1 indirect + LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_INDIRECTTI); + LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING); + LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); - // Timer: channel 2 direct - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV32_N8); + // Timer: channel 2 direct + LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI); + LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING); + LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV32_N8); - // ISR setup - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_capture_ISR, NULL); + // ISR setup + furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_capture_ISR, NULL); - // Interrupts and channels - LL_TIM_EnableIT_CC1(TIM2); - LL_TIM_EnableIT_CC2(TIM2); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + // Interrupts and channels + LL_TIM_EnableIT_CC1(TIM2); + LL_TIM_EnableIT_CC2(TIM2); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + } // Start timer LL_TIM_SetCounter(TIM2, 0); @@ -549,6 +685,9 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* // Switch to RX furi_hal_subghz_rx(); + + // Clear the variable after the end of the session + furi_hal_subghz_capture_delta_duration = 0; } void furi_hal_subghz_stop_async_rx() { @@ -565,9 +704,11 @@ void furi_hal_subghz_stop_async_rx() { furi_hal_subghz_stop_debug(); FURI_CRITICAL_EXIT(); - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + if(furi_hal_subghz.radio_type == SubGhzRadioInternal) { + furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + } - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } typedef struct { @@ -601,8 +742,8 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { *buffer = 0; buffer++; samples--; - LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableIT_HT(SUBGHZ_DMA_CH1_DEF); + LL_DMA_DisableIT_TC(SUBGHZ_DMA_CH1_DEF); LL_TIM_EnableIT_UPDATE(TIM2); break; } else { @@ -643,17 +784,22 @@ static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) { static void furi_hal_subghz_async_tx_dma_isr() { furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx); - if(LL_DMA_IsActiveFlag_HT1(DMA1)) { - LL_DMA_ClearFlag_HT1(DMA1); + +#if SUBGHZ_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + if(LL_DMA_IsActiveFlag_HT1(SUBGHZ_DMA)) { + LL_DMA_ClearFlag_HT1(SUBGHZ_DMA); furi_hal_subghz_async_tx_refill( furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); } - if(LL_DMA_IsActiveFlag_TC1(DMA1)) { - LL_DMA_ClearFlag_TC1(DMA1); + if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) { + LL_DMA_ClearFlag_TC1(SUBGHZ_DMA); furi_hal_subghz_async_tx_refill( furi_hal_subghz_async_tx.buffer + API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF); } +#else +#error Update this code. Would you kindly? +#endif } static void furi_hal_subghz_async_tx_timer_isr() { @@ -662,11 +808,12 @@ static void furi_hal_subghz_async_tx_timer_isr() { if(LL_TIM_GetAutoReload(TIM2) == 0) { if(furi_hal_subghz.state == SubGhzStateAsyncTx) { furi_hal_subghz.state = SubGhzStateAsyncTxLast; - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableChannel(SUBGHZ_DMA_CH1_DEF); } else if(furi_hal_subghz.state == SubGhzStateAsyncTxLast) { furi_hal_subghz.state = SubGhzStateAsyncTxEnd; //forcibly pulls the pin to the ground so that there is no carrier - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullDown, GpioSpeedLow); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullDown, GpioSpeedLow); LL_TIM_DisableCounter(TIM2); } else { furi_crash(NULL); @@ -680,7 +827,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_assert(callback); //If transmission is prohibited by regional settings - // if(furi_hal_subghz.regulation != SubGhzRegulationTxRx) return false; + if(furi_hal_subghz.regulation != SubGhzRegulationTxRx) return false; furi_hal_subghz_async_tx.callback = callback; furi_hal_subghz_async_tx.callback_context = context; @@ -693,9 +840,19 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* furi_hal_subghz_async_tx.buffer = malloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); - // Connect CC1101_GD0 to TIM2 as output - furi_hal_gpio_init_ex( - &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn1TIM2); + if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, true); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + } else { + // Connect CC1101_GD0 to TIM2 as output + furi_hal_gpio_init_ex( + &gpio_cc1101_g0, + GpioModeAltFunctionPushPull, + GpioPullDown, + GpioSpeedLow, + GpioAltFn1TIM2); + } // Configure DMA LL_DMA_InitTypeDef dma_config = {0}; @@ -710,11 +867,11 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* dma_config.NbData = API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config.Priority = LL_DMA_MODE_NORMAL; - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); - furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, furi_hal_subghz_async_tx_dma_isr, NULL); - LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config); + furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, furi_hal_subghz_async_tx_dma_isr, NULL); + LL_DMA_EnableIT_TC(SUBGHZ_DMA_CH1_DEF); + LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); + LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); // Configure TIM2 LL_TIM_InitTypeDef TIM_InitStruct = {0}; @@ -755,9 +912,20 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* LL_TIM_SetCounter(TIM2, 0); LL_TIM_EnableCounter(TIM2); - // Start debug - if(furi_hal_subghz_start_debug()) { - const GpioPin* gpio = furi_hal_subghz.async_mirror_pin; + //Signal generation for external module + + // Start debug (and speaker) + furi_hal_subghz_start_debug(); + + const GpioPin* gpio = furi_hal_subghz.cc1101_g0_pin; + + if((furi_hal_subghz.async_mirror_pin != NULL) && + (furi_hal_subghz.radio_type == SubGhzRadioInternal)) { + gpio = furi_hal_subghz.async_mirror_pin; + } + if(((furi_hal_subghz.async_mirror_pin != NULL) && + (furi_hal_subghz.radio_type == SubGhzRadioInternal)) || + (furi_hal_subghz.radio_type == SubGhzRadioExternal)) { furi_hal_subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; furi_hal_subghz_debug_gpio_buff[1] = gpio->pin; @@ -772,9 +940,9 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* dma_config.NbData = 2; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 2); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_Init(SUBGHZ_DMA_CH2_DEF, &dma_config); + LL_DMA_SetDataLength(SUBGHZ_DMA_CH2_DEF, 2); + LL_DMA_EnableChannel(SUBGHZ_DMA_CH2_DEF); } return true; @@ -792,9 +960,9 @@ void furi_hal_subghz_stop_async_tx() { // Shutdown radio furi_hal_subghz_idle(); -#ifdef FURI_HAL_SUBGHZ_TX_GPIO - furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, false); -#endif + if(furi_hal_subghz.radio_type == SubGhzRadioExternal) { + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + } // Deinitialize Timer FURI_CRITICAL_ENTER(); @@ -802,16 +970,20 @@ void furi_hal_subghz_stop_async_tx() { furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); // Deinitialize DMA - LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DeInit(SUBGHZ_DMA_CH1_DEF); - furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL); + furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, NULL, NULL); // Deinitialize GPIO - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); // Stop debug - if(furi_hal_subghz_stop_debug()) { - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + furi_hal_subghz_stop_debug(); + + if(((furi_hal_subghz.async_mirror_pin != NULL) && + (furi_hal_subghz.radio_type == SubGhzRadioInternal)) || + (furi_hal_subghz.radio_type == SubGhzRadioExternal)) { + LL_DMA_DisableChannel(SUBGHZ_DMA_CH2_DEF); } FURI_CRITICAL_EXIT(); diff --git a/firmware/targets/furi_hal_include/furi_hal_subghz.h b/firmware/targets/f7/furi_hal/furi_hal_subghz.h similarity index 82% rename from firmware/targets/furi_hal_include/furi_hal_subghz.h rename to firmware/targets/f7/furi_hal/furi_hal_subghz.h index b3319e226..b19a71f9a 100644 --- a/firmware/targets/furi_hal_include/furi_hal_subghz.h +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.h @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -61,6 +62,25 @@ typedef enum { SubGhzRegulationTxRx, /**TxRx*/ } SubGhzRegulation; +/** SubGhz radio types */ +typedef enum { + SubGhzRadioInternal, + SubGhzRadioExternal, +} SubGhzRadioType; + +/** Structure for accessing SubGhz settings*/ +typedef struct { + volatile SubGhzState state; + volatile SubGhzRegulation regulation; + volatile FuriHalSubGhzPreset preset; + const GpioPin* async_mirror_pin; + SubGhzRadioType radio_type; + FuriHalSpiBusHandle* spi_bus_handle; + const GpioPin* cc1101_g0_pin; +} FuriHalSubGhz; + +extern volatile FuriHalSubGhz furi_hal_subghz; + /* Mirror RX/TX async modulation signal to specified pin * * @warning Configures pin to output mode. Make sure it is not connected @@ -76,6 +96,13 @@ void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin); */ void furi_hal_subghz_init(); +/** Initialize and switch to power save mode Used by internal API-HAL + * initialization routine Can be used to reinitialize device to safe state and + * send it to sleep + * @return true if initialisation is successfully + */ +bool furi_hal_subghz_init_check(void); + /** Send device to sleep mode */ void furi_hal_subghz_sleep(); @@ -258,6 +285,30 @@ bool furi_hal_subghz_is_async_tx_complete(); */ void furi_hal_subghz_stop_async_tx(); +/** Switching between internal and external radio + * @param state SubGhzRadioInternal or SubGhzRadioExternal + * @return true if switching is successful + */ +bool furi_hal_subghz_set_radio_type(SubGhzRadioType state); + +/** Get current radio + * @return SubGhzRadioInternal or SubGhzRadioExternal + */ +SubGhzRadioType furi_hal_subghz_get_radio_type(void); + +/** Check for a radio module + * @return true if check is successful + */ +bool furi_hal_subghz_check_radio(void); + +/** Turn on the power of the external radio module + */ +void furi_hal_subghz_enable_ext_power(void); + +/** Turn off the power of the external radio module + */ +void furi_hal_subghz_disable_ext_power(void); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_target_hw.h b/firmware/targets/f7/furi_hal/furi_hal_target_hw.h new file mode 100644 index 000000000..128122f84 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_target_hw.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include +#include +#include diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index e740155f5..0038bd348 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -1,6 +1,6 @@ -#include "furi_hal_version.h" -#include "furi_hal_usb_i.h" -#include "furi_hal_usb.h" +#include +#include +#include #include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c index 88deafdcc..4c4f727ba 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -1,7 +1,7 @@ -#include "furi_hal_version.h" -#include "furi_hal_usb_i.h" -#include "furi_hal_usb.h" -#include "furi_hal_usb_cdc.h" +#include +#include +#include +#include #include #include "usb.h" diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c index fc1ce024c..a3bc84227 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -1,7 +1,7 @@ -#include "furi_hal_version.h" -#include "furi_hal_usb_i.h" -#include "furi_hal_usb.h" -#include "furi_hal_usb_hid.h" +#include +#include +#include +#include #include #include "usb.h" diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c b/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c index c099aec8a..fe711512a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c @@ -1,7 +1,7 @@ -#include "furi_hal_version.h" -#include "furi_hal_usb_i.h" -#include "furi_hal_usb_hid_u2f.h" -#include "furi_hal_usb.h" +#include +#include +#include +#include #include #include "usb.h" #include "usb_hid.h" diff --git a/firmware/targets/f7/furi_hal/furi_hal_version.c b/firmware/targets/f7/furi_hal/furi_hal_version.c index 418dda10a..643a30e6e 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_version.c +++ b/firmware/targets/f7/furi_hal/furi_hal_version.c @@ -224,14 +224,6 @@ void furi_hal_version_init() { FURI_LOG_I(TAG, "Init OK"); } -bool furi_hal_version_do_i_belong_here() { - return furi_hal_version_get_hw_target() == 7; -} - -const char* furi_hal_version_get_model_name() { - return "Flipper Zero"; -} - FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { if(*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { return FuriHalVersionOtpVersionEmpty; diff --git a/firmware/targets/f7/furi_hal/furi_hal_version_device.c b/firmware/targets/f7/furi_hal/furi_hal_version_device.c new file mode 100644 index 000000000..c059c2cbe --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_version_device.c @@ -0,0 +1,21 @@ +#include + +bool furi_hal_version_do_i_belong_here() { + return (furi_hal_version_get_hw_target() == 7) || (furi_hal_version_get_hw_target() == 0); +} + +const char* furi_hal_version_get_model_name() { + return "Flipper Zero"; +} + +const char* furi_hal_version_get_model_code() { + return "FZ.1"; +} + +const char* furi_hal_version_get_fcc_id() { + return "2A2V6-FZ"; +} + +const char* furi_hal_version_get_ic_id() { + return "27624-FZ"; +} diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/inc/FreeRTOSConfig.h similarity index 100% rename from firmware/targets/f7/Inc/FreeRTOSConfig.h rename to firmware/targets/f7/inc/FreeRTOSConfig.h diff --git a/firmware/targets/f7/Inc/alt_boot.h b/firmware/targets/f7/inc/alt_boot.h similarity index 80% rename from firmware/targets/f7/Inc/alt_boot.h rename to firmware/targets/f7/inc/alt_boot.h index 91bf9bdf7..d8be3aa48 100644 --- a/firmware/targets/f7/Inc/alt_boot.h +++ b/firmware/targets/f7/inc/alt_boot.h @@ -8,6 +8,8 @@ void flipper_boot_update_exec(); void flipper_boot_dfu_exec(); +void flipper_boot_recovery_exec(); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/Inc/stm32.h b/firmware/targets/f7/inc/stm32.h similarity index 100% rename from firmware/targets/f7/Inc/stm32.h rename to firmware/targets/f7/inc/stm32.h diff --git a/firmware/targets/f7/Inc/stm32_assert.h b/firmware/targets/f7/inc/stm32_assert.h similarity index 100% rename from firmware/targets/f7/Inc/stm32_assert.h rename to firmware/targets/f7/inc/stm32_assert.h diff --git a/firmware/targets/f7/Src/dfu.c b/firmware/targets/f7/src/dfu.c similarity index 100% rename from firmware/targets/f7/Src/dfu.c rename to firmware/targets/f7/src/dfu.c diff --git a/firmware/targets/f7/Src/main.c b/firmware/targets/f7/src/main.c similarity index 90% rename from firmware/targets/f7/Src/main.c rename to firmware/targets/f7/src/main.c index d9a2221a2..1f2b5d6e4 100644 --- a/firmware/targets/f7/Src/main.c +++ b/firmware/targets/f7/src/main.c @@ -49,6 +49,10 @@ int main() { // But if we do, abandon to avoid bootloops furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); furi_hal_power_reset(); + } else if(!furi_hal_gpio_read(&gpio_button_up)) { + furi_hal_light_sequence("rgb WR"); + flipper_boot_recovery_exec(); + furi_hal_power_reset(); } else { furi_hal_light_sequence("rgb G"); furi_thread_start(main_thread); diff --git a/firmware/targets/f7/src/recovery.c b/firmware/targets/f7/src/recovery.c new file mode 100644 index 000000000..d56be4fe0 --- /dev/null +++ b/firmware/targets/f7/src/recovery.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include + +#define COUNTER_VALUE (100U) + +static void flipper_boot_recovery_draw_splash(u8g2_t* fb, size_t progress) { + u8g2_ClearBuffer(fb); + u8g2_SetDrawColor(fb, 0x01); + + u8g2_SetFont(fb, u8g2_font_helvB08_tr); + u8g2_DrawStr(fb, 2, 8, "PIN and Factory Reset"); + u8g2_SetFont(fb, u8g2_font_haxrcorp4089_tr); + u8g2_DrawStr(fb, 2, 21, "Hold Right to confirm"); + u8g2_DrawStr(fb, 2, 31, "Press Down to cancel"); + + if(progress < COUNTER_VALUE) { + size_t width = progress / (COUNTER_VALUE / 100); + u8g2_DrawBox(fb, 14 + (50 - width / 2), 54, width, 3); + } + + u8g2_SetPowerSave(fb, 0); + u8g2_SendBuffer(fb); +} + +void flipper_boot_recovery_exec() { + u8g2_t* fb = malloc(sizeof(u8g2_t)); + u8g2_Setup_st756x_flipper(fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); + u8g2_InitDisplay(fb); + + size_t counter = COUNTER_VALUE; + while(counter) { + if(!furi_hal_gpio_read(&gpio_button_down)) { + break; + } + + if(!furi_hal_gpio_read(&gpio_button_right)) { + counter--; + } else { + counter = COUNTER_VALUE; + } + + flipper_boot_recovery_draw_splash(fb, counter); + } + + if(!counter) { + furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); + furi_hal_rtc_set_pin_fails(0); + furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); + } +} diff --git a/firmware/targets/f7/Src/system_stm32wbxx.c b/firmware/targets/f7/src/system_stm32wbxx.c similarity index 100% rename from firmware/targets/f7/Src/system_stm32wbxx.c rename to firmware/targets/f7/src/system_stm32wbxx.c diff --git a/firmware/targets/f7/Src/update.c b/firmware/targets/f7/src/update.c similarity index 99% rename from firmware/targets/f7/Src/update.c rename to firmware/targets/f7/src/update.c index a68a8b7a7..b223a5dc3 100644 --- a/firmware/targets/f7/Src/update.c +++ b/firmware/targets/f7/src/update.c @@ -42,7 +42,7 @@ static bool flipper_update_init() { furi_hal_rtc_init(); furi_hal_interrupt_init(); - furi_hal_spi_init(); + furi_hal_spi_config_init(); MX_FATFS_Init(); if(!hal_sd_detect()) { diff --git a/firmware/targets/f7/stm32wb55xx_flash.ld b/firmware/targets/f7/stm32wb55xx_flash.ld index e1fb98b9f..df4c5b726 100644 --- a/firmware/targets/f7/stm32wb55xx_flash.ld +++ b/firmware/targets/f7/stm32wb55xx_flash.ld @@ -1,7 +1,7 @@ /** ***************************************************************************** ** -** File : stm32wb55xx_flash_cm4.ld +** File : stm32wb55xx_flash.ld ** ** Abstract : System Workbench Minimal System calls file ** diff --git a/firmware/targets/f7/stm32wb55xx_ram_fw.ld b/firmware/targets/f7/stm32wb55xx_ram_fw.ld index db9e407c9..0ac9be4df 100644 --- a/firmware/targets/f7/stm32wb55xx_ram_fw.ld +++ b/firmware/targets/f7/stm32wb55xx_ram_fw.ld @@ -1,7 +1,7 @@ /** ***************************************************************************** ** -** File : stm32wb55xx_flash_cm4.ld +** File : stm32wb55xx_ram_fw.ld ** ** Abstract : System Workbench Minimal System calls file ** diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json new file mode 100644 index 000000000..49aa109bd --- /dev/null +++ b/firmware/targets/f7/target.json @@ -0,0 +1,45 @@ +{ + "include_paths": [ + "ble_glue", + "fatfs", + "furi_hal", + "inc" + ], + "sdk_header_paths": [ + "../furi_hal_include", + "furi_hal", + "platform_specific" + ], + "startup_script": "startup_stm32wb55xx_cm4.s", + "linker_script_flash": "stm32wb55xx_flash.ld", + "linker_script_ram": "stm32wb55xx_ram_fw.ld", + "linker_script_app": "application_ext.ld", + "sdk_symbols": "api_symbols.csv", + "linker_dependencies": [ + "print", + "flipper7", + "furi", + "freertos", + "stm32cubewb", + "hwdrivers", + "fatfs", + "littlefs", + "subghz", + "flipperformat", + "toolbox", + "nfc", + "microtar", + "usb_stm32", + "st25rfal002", + "infrared", + "appframe", + "assets", + "one_wire", + "misc", + "mbedtls", + "lfrfid", + "flipper_application", + "flipperformat", + "toolbox" + ] +} \ No newline at end of file diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/firmware/targets/furi_hal_include/furi_hal.h index 8613c4d5e..ad4340dd4 100644 --- a/firmware/targets/furi_hal_include/furi_hal.h +++ b/firmware/targets/furi_hal_include/furi_hal.h @@ -10,37 +10,34 @@ template struct STOP_EXTERNING_ME {}; #endif -#include "furi_hal_cortex.h" -#include "furi_hal_clock.h" -#include "furi_hal_crypto.h" -#include "furi_hal_console.h" -#include "furi_hal_debug.h" -#include "furi_hal_os.h" -#include "furi_hal_sd.h" -#include "furi_hal_i2c.h" -#include "furi_hal_resources.h" -#include "furi_hal_region.h" -#include "furi_hal_rtc.h" -#include "furi_hal_speaker.h" -#include "furi_hal_gpio.h" -#include "furi_hal_light.h" -#include "furi_hal_power.h" -#include "furi_hal_interrupt.h" -#include "furi_hal_version.h" -#include "furi_hal_bt.h" -#include "furi_hal_spi.h" -#include "furi_hal_flash.h" -#include "furi_hal_subghz.h" -#include "furi_hal_vibro.h" -#include "furi_hal_ibutton.h" -#include "furi_hal_rfid.h" -#include "furi_hal_nfc.h" -#include "furi_hal_usb.h" -#include "furi_hal_usb_hid.h" -#include "furi_hal_compress.h" -#include "furi_hal_uart.h" -#include "furi_hal_info.h" -#include "furi_hal_random.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/firmware/targets/furi_hal_include/furi_hal_bt.h index 800fc3fe3..d717d346d 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt.h @@ -12,7 +12,7 @@ #include #include -#include "furi_hal_bt_serial.h" +#include #define FURI_HAL_BT_STACK_VERSION_MAJOR (1) #define FURI_HAL_BT_STACK_VERSION_MINOR (12) @@ -224,6 +224,34 @@ uint32_t furi_hal_bt_get_transmitted_packets(); */ bool furi_hal_bt_ensure_c2_mode(BleGlueC2Mode mode); +/** Modify profile advertisement name and restart bluetooth + * @param[in] profile profile type + * @param[in] name new adv name +*/ +void furi_hal_bt_set_profile_adv_name( + FuriHalBtProfile profile, + const char name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH - 1]); + +const char* furi_hal_bt_get_profile_adv_name(FuriHalBtProfile profile); + +/** Modify profile mac address and restart bluetooth + * @param[in] profile profile type + * @param[in] mac new mac address +*/ +void furi_hal_bt_set_profile_mac_addr( + FuriHalBtProfile profile, + const uint8_t mac_addr[GAP_MAC_ADDR_SIZE]); + +const uint8_t* furi_hal_bt_get_profile_mac_addr(FuriHalBtProfile profile); + +uint32_t furi_hal_bt_get_conn_rssi(uint8_t* rssi); + +void furi_hal_bt_set_profile_pairing_method(FuriHalBtProfile profile, GapPairing pairing_method); + +GapPairing furi_hal_bt_get_profile_pairing_method(FuriHalBtProfile profile); + +bool furi_hal_bt_is_connected(void); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h b/firmware/targets/furi_hal_include/furi_hal_bt_hid.h index 4e74bbda7..56a8b4e48 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt_hid.h @@ -86,6 +86,13 @@ bool furi_hal_bt_hid_consumer_key_release(uint16_t button); */ bool furi_hal_bt_hid_consumer_key_release_all(); +/** Retrieves LED state from remote BT HID host + * + * @return (look at HID usage page to know what each bit of the returned byte means) + * NB: RFU bit has been shifted out in the returned octet so USB defines should work +*/ +uint8_t furi_hal_bt_hid_get_led_state(void); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/furi_hal_include/furi_hal_spi.h b/firmware/targets/furi_hal_include/furi_hal_spi.h index df7ffa93d..af15a8838 100644 --- a/firmware/targets/furi_hal_include/furi_hal_spi.h +++ b/firmware/targets/furi_hal_include/furi_hal_spi.h @@ -8,13 +8,16 @@ extern "C" { #endif /** Early initialize SPI HAL */ -void furi_hal_spi_init_early(); +void furi_hal_spi_config_init_early(); /** Early deinitialize SPI HAL */ -void furi_hal_spi_deinit_early(); +void furi_hal_spi_config_deinit_early(); /** Initialize SPI HAL */ -void furi_hal_spi_init(); +void furi_hal_spi_config_init(); + +/** Initialize SPI DMA HAL */ +void furi_hal_spi_dma_init(); /** Initialize SPI Bus * @@ -82,7 +85,7 @@ bool furi_hal_spi_bus_rx( */ bool furi_hal_spi_bus_tx( FuriHalSpiBusHandle* handle, - uint8_t* buffer, + const uint8_t* buffer, size_t size, uint32_t timeout); @@ -98,11 +101,28 @@ bool furi_hal_spi_bus_tx( */ bool furi_hal_spi_bus_trx( FuriHalSpiBusHandle* handle, - uint8_t* tx_buffer, + const uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout); +/** SPI Transmit and Receive with DMA + * + * @param handle pointer to FuriHalSpiBusHandle instance + * @param tx_buffer pointer to tx buffer + * @param rx_buffer pointer to rx buffer + * @param size transaction size (buffer size) + * @param timeout_ms operation timeout in ms + * + * @return true on success + */ +bool furi_hal_spi_bus_trx_dma( + FuriHalSpiBusHandle* handle, + uint8_t* tx_buffer, + uint8_t* rx_buffer, + size_t size, + uint32_t timeout_ms); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/furi_hal_include/furi_hal_version.h b/firmware/targets/furi_hal_include/furi_hal_version.h index 3e524b75c..889b29777 100644 --- a/firmware/targets/furi_hal_include/furi_hal_version.h +++ b/firmware/targets/furi_hal_include/furi_hal_version.h @@ -17,7 +17,8 @@ extern "C" { #define FURI_HAL_VERSION_NAME_LENGTH 8 #define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1) /** BLE symbol + name */ -#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH) +#define FURI_HAL_VERSION_DEVICE_NAME_LENGTH \ + (1 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH) + 9 // for bad kb custom name /** OTP Versions enum */ typedef enum { @@ -67,6 +68,24 @@ bool furi_hal_version_do_i_belong_here(); */ const char* furi_hal_version_get_model_name(); +/** Get model name + * + * @return model code C-string + */ +const char* furi_hal_version_get_model_code(); + +/** Get FCC ID + * + * @return FCC id as C-string + */ +const char* furi_hal_version_get_fcc_id(); + +/** Get IC id + * + * @return IC id as C-string + */ +const char* furi_hal_version_get_ic_id(); + /** Get OTP version * * @return OTP Version diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index c7acf95b4..1ec847d45 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -52,30 +52,6 @@ extern "C" { } #endif -static inline bool furi_is_irq_context() { - bool irq = false; - BaseType_t state; - - if(FURI_IS_IRQ_MODE()) { - /* Called from interrupt context */ - irq = true; - } else { - /* Get FreeRTOS scheduler state */ - state = xTaskGetSchedulerState(); - - if(state != taskSCHEDULER_NOT_STARTED) { - /* Scheduler was started */ - if(FURI_IS_IRQ_MASKED()) { - /* Interrupts are masked */ - irq = true; - } - } - } - - /* Return context, 0: thread context, 1: IRQ context */ - return (irq); -} - #ifdef __cplusplus } #endif diff --git a/furi/core/kernel.c b/furi/core/kernel.c index 73d2012b4..7928ad11c 100644 --- a/furi/core/kernel.c +++ b/furi/core/kernel.c @@ -7,8 +7,32 @@ #include CMSIS_device_header +bool furi_kernel_is_irq_or_masked() { + bool irq = false; + BaseType_t state; + + if(FURI_IS_IRQ_MODE()) { + /* Called from interrupt context */ + irq = true; + } else { + /* Get FreeRTOS scheduler state */ + state = xTaskGetSchedulerState(); + + if(state != taskSCHEDULER_NOT_STARTED) { + /* Scheduler was started */ + if(FURI_IS_IRQ_MASKED()) { + /* Interrupts are masked */ + irq = true; + } + } + } + + /* Return context, 0: thread context, 1: IRQ context */ + return (irq); +} + int32_t furi_kernel_lock() { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); int32_t lock; @@ -33,7 +57,7 @@ int32_t furi_kernel_lock() { } int32_t furi_kernel_unlock() { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); int32_t lock; @@ -63,7 +87,7 @@ int32_t furi_kernel_unlock() { } int32_t furi_kernel_restore_lock(int32_t lock) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); switch(xTaskGetSchedulerState()) { case taskSCHEDULER_SUSPENDED: @@ -99,7 +123,7 @@ uint32_t furi_kernel_get_tick_frequency() { } void furi_delay_tick(uint32_t ticks) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); if(ticks == 0U) { taskYIELD(); } else { @@ -108,7 +132,7 @@ void furi_delay_tick(uint32_t ticks) { } FuriStatus furi_delay_until_tick(uint32_t tick) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); TickType_t tcnt, delay; FuriStatus stat; @@ -137,7 +161,7 @@ FuriStatus furi_delay_until_tick(uint32_t tick) { uint32_t furi_get_tick() { TickType_t ticks; - if(furi_is_irq_context() != 0U) { + if(furi_kernel_is_irq_or_masked() != 0U) { ticks = xTaskGetTickCountFromISR(); } else { ticks = xTaskGetTickCount(); diff --git a/furi/core/kernel.h b/furi/core/kernel.h index f30f109bb..371f76c1f 100644 --- a/furi/core/kernel.h +++ b/furi/core/kernel.h @@ -10,19 +10,42 @@ extern "C" { #endif +/** Check if CPU is in IRQ or kernel running and IRQ is masked + * + * Originally this primitive was born as a workaround for FreeRTOS kernel primitives shenanigans with PRIMASK. + * + * Meaningful use cases are: + * + * - When kernel is started and you want to ensure that you are not in IRQ or IRQ is not masked(like in critical section) + * - When kernel is not started and you want to make sure that you are not in IRQ mode, ignoring PRIMASK. + * + * As you can see there will be edge case when kernel is not started and PRIMASK is not 0 that may cause some funky behavior. + * Most likely it will happen after kernel primitives being used, but control not yet passed to kernel. + * It's up to you to figure out if it is safe for your code or not. + * + * @return true if CPU is in IRQ or kernel running and IRQ is masked + */ +bool furi_kernel_is_irq_or_masked(); + /** Lock kernel, pause process scheduling + * + * @warning This should never be called in interrupt request context. * * @return previous lock state(0 - unlocked, 1 - locked) */ int32_t furi_kernel_lock(); /** Unlock kernel, resume process scheduling + * + * @warning This should never be called in interrupt request context. * * @return previous lock state(0 - unlocked, 1 - locked) */ int32_t furi_kernel_unlock(); /** Restore kernel lock state + * + * @warning This should never be called in interrupt request context. * * @param[in] lock The lock state * @@ -37,7 +60,9 @@ int32_t furi_kernel_restore_lock(int32_t lock); uint32_t furi_kernel_get_tick_frequency(); /** Delay execution - * + * + * @warning This should never be called in interrupt request context. + * * Also keep in mind delay is aliased to scheduler timer intervals. * * @param[in] ticks The ticks count to pause @@ -45,6 +70,8 @@ uint32_t furi_kernel_get_tick_frequency(); void furi_delay_tick(uint32_t ticks); /** Delay until tick + * + * @warning This should never be called in interrupt request context. * * @param[in] ticks The tick until which kerel should delay task execution * diff --git a/furi/core/message_queue.c b/furi/core/message_queue.c index 9a41f8775..ddf56f006 100644 --- a/furi/core/message_queue.c +++ b/furi/core/message_queue.c @@ -1,11 +1,11 @@ +#include "kernel.h" #include "message_queue.h" -#include "core/common_defines.h" #include #include #include "check.h" FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size) { - furi_assert((furi_is_irq_context() == 0U) && (msg_count > 0U) && (msg_size > 0U)); + furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (msg_count > 0U) && (msg_size > 0U)); QueueHandle_t handle = xQueueCreate(msg_count, msg_size); furi_check(handle); @@ -14,7 +14,7 @@ FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size } void furi_message_queue_free(FuriMessageQueue* instance) { - furi_assert(furi_is_irq_context() == 0U); + furi_assert(furi_kernel_is_irq_or_masked() == 0U); furi_assert(instance); vQueueDelete((QueueHandle_t)instance); @@ -28,7 +28,7 @@ FuriStatus stat = FuriStatusOk; - if(furi_is_irq_context() != 0U) { + if(furi_kernel_is_irq_or_masked() != 0U) { if((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) { stat = FuriStatusErrorParameter; } else { @@ -65,7 +65,7 @@ FuriStatus furi_message_queue_get(FuriMessageQueue* instance, void* msg_ptr, uin stat = FuriStatusOk; - if(furi_is_irq_context() != 0U) { + if(furi_kernel_is_irq_or_masked() != 0U) { if((hQueue == NULL) || (msg_ptr == NULL) || (timeout != 0U)) { stat = FuriStatusErrorParameter; } else { @@ -131,7 +131,7 @@ uint32_t furi_message_queue_get_count(FuriMessageQueue* instance) { if(hQueue == NULL) { count = 0U; - } else if(furi_is_irq_context() != 0U) { + } else if(furi_kernel_is_irq_or_masked() != 0U) { count = uxQueueMessagesWaitingFromISR(hQueue); } else { count = uxQueueMessagesWaiting(hQueue); @@ -148,7 +148,7 @@ uint32_t furi_message_queue_get_space(FuriMessageQueue* instance) { if(mq == NULL) { space = 0U; - } else if(furi_is_irq_context() != 0U) { + } else if(furi_kernel_is_irq_or_masked() != 0U) { isrm = taskENTER_CRITICAL_FROM_ISR(); /* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */ @@ -167,7 +167,7 @@ FuriStatus furi_message_queue_reset(FuriMessageQueue* instance) { QueueHandle_t hQueue = (QueueHandle_t)instance; FuriStatus stat; - if(furi_is_irq_context() != 0U) { + if(furi_kernel_is_irq_or_masked() != 0U) { stat = FuriStatusErrorISR; } else if(hQueue == NULL) { stat = FuriStatusErrorParameter; diff --git a/furi/core/thread.c b/furi/core/thread.c index c966dd572..ef9560b4a 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -530,6 +530,12 @@ bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { return true; } +FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { + FuriThread* thread = furi_thread_get_current(); + + return thread->output.write_callback; +} + size_t furi_thread_stdout_write(const char* data, size_t size) { FuriThread* thread = furi_thread_get_current(); diff --git a/furi/core/thread.h b/furi/core/thread.h index c2f5a9130..1542d5bf0 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -227,6 +227,12 @@ const char* furi_thread_get_name(FuriThreadId thread_id); uint32_t furi_thread_get_stack_space(FuriThreadId thread_id); +/** Get STDOUT callback for thead + * + * @return STDOUT callback + */ +FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(); + /** Set STDOUT callback for thread * * @param callback callback or NULL to clear diff --git a/furi/core/timer.c b/furi/core/timer.c index be7efebe2..4b6ccecba 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -3,7 +3,6 @@ #include "memmgr.h" #include "kernel.h" -#include "core/common_defines.h" #include #include @@ -27,7 +26,7 @@ static void TimerCallback(TimerHandle_t hTimer) { } FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* context) { - furi_assert((furi_is_irq_context() == 0U) && (func != NULL)); + furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (func != NULL)); TimerHandle_t hTimer; TimerCallback_t* callb; @@ -60,7 +59,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co } void furi_timer_free(FuriTimer* instance) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -82,7 +81,7 @@ void furi_timer_free(FuriTimer* instance) { } FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -99,7 +98,7 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { } FuriStatus furi_timer_stop(FuriTimer* instance) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; @@ -117,7 +116,7 @@ FuriStatus furi_timer_stop(FuriTimer* instance) { } uint32_t furi_timer_is_running(FuriTimer* instance) { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; diff --git a/furi/furi.c b/furi/furi.c index a616bce63..cc0e3f4f1 100644 --- a/furi/furi.c +++ b/furi/furi.c @@ -3,7 +3,7 @@ #include "queue.h" void furi_init() { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED); furi_log_init(); @@ -11,7 +11,7 @@ void furi_init() { } void furi_run() { - furi_assert(!furi_is_irq_context()); + furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED); #if(__ARM_ARCH_7A__ == 0U) diff --git a/lib/SConscript b/lib/SConscript index 27979bc5c..d72ef7700 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -9,7 +9,6 @@ env.Append( Dir("flipper_format"), Dir("infrared"), Dir("nfc"), - Dir("one_wire"), Dir("ST25RFAL002"), Dir("subghz"), Dir("toolbox"), @@ -17,17 +16,9 @@ env.Append( Dir("update_util"), Dir("print"), ], - SDK_HEADERS=[ - File("one_wire/one_wire_host_timing.h"), - File("one_wire/one_wire_host.h"), - File("one_wire/one_wire_slave.h"), - File("one_wire/one_wire_device.h"), - File("one_wire/ibutton/ibutton_worker.h"), - File("one_wire/maxim_crc.h"), - File("u8g2/u8g2.h"), - ], ) + env.Append( CPPPATH=[ "#/", @@ -36,6 +27,23 @@ env.Append( # Ugly hack Dir("../assets/compiled"), ], + SDK_HEADERS=[ + *( + File(f"#/lib/mlib/m-{name}.h") + for name in ( + "algo", + "array", + "bptree", + "core", + "deque", + "dict", + "list", + "rbtree", + "tuple", + "variant", + ) + ), + ], CPPDEFINES=[ '"M_MEMORY_FULL(x)=abort()"', ], @@ -49,13 +57,13 @@ env.Append( # littlefs # subghz # toolbox +# one_wire +# micro-ecc # misc # digital_signal -# fnv1a-hash -# micro-ecc +# fnv1a_hash # microtar # nfc -# one_wire # qrcode # u8g2 # update_util @@ -79,6 +87,7 @@ libs = env.BuildModules( "drivers", "fatfs", "flipper_format", + "one_wire", "infrared", "littlefs", "mbedtls", diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index cbdde9814..a1b484ad1 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -14,9 +14,15 @@ env.Append( "USE_FULL_LL_DRIVER", ], SDK_HEADERS=[ - *env.GlobRecursive("*_ll_*.h", "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/", exclude="*usb.h"), + *env.GlobRecursive( + "*_ll_*.h", + "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/", + exclude="*usb.h", + ), File("STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h"), - File("STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h"), + File( + "STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h" + ), ], ) diff --git a/lib/app-scened-template/view_modules/popup_vm.cpp b/lib/app-scened-template/view_modules/popup_vm.cpp index e2c8732e8..330aa44ca 100644 --- a/lib/app-scened-template/view_modules/popup_vm.cpp +++ b/lib/app-scened-template/view_modules/popup_vm.cpp @@ -1,5 +1,6 @@ #include "popup_vm.h" -#include "gui/modules/popup.h" +#include + PopupVM::PopupVM() { popup = popup_alloc(); } diff --git a/lib/flipper_application/application_manifest.c b/lib/flipper_application/application_manifest.c index ab92e4930..fea92c262 100644 --- a/lib/flipper_application/application_manifest.c +++ b/lib/flipper_application/application_manifest.c @@ -1,5 +1,7 @@ #include "application_manifest.h" +#include + bool flipper_application_manifest_is_valid(const FlipperApplicationManifest* manifest) { if((manifest->base.manifest_magic != FAP_MANIFEST_MAGIC) || (manifest->base.manifest_version != FAP_MANIFEST_SUPPORTED_VERSION)) { @@ -19,3 +21,8 @@ bool flipper_application_manifest_is_compatible( return true; } + +bool flipper_application_manifest_is_target_compatible(const FlipperApplicationManifest* manifest) { + const Version* version = furi_hal_version_get_firmware_version(); + return version_get_target(version) == manifest->base.hardware_target_id; +} \ No newline at end of file diff --git a/lib/flipper_application/application_manifest.h b/lib/flipper_application/application_manifest.h index f46d44fd7..25e4f8d0a 100644 --- a/lib/flipper_application/application_manifest.h +++ b/lib/flipper_application/application_manifest.h @@ -65,6 +65,14 @@ bool flipper_application_manifest_is_compatible( const FlipperApplicationManifest* manifest, const ElfApiInterface* api_interface); +/** + * @brief Check if application is compatible with current hardware + * + * @param manifest + * @return bool + */ +bool flipper_application_manifest_is_target_compatible(const FlipperApplicationManifest* manifest); + #ifdef __cplusplus } #endif diff --git a/lib/flipper_application/flipper_application.c b/lib/flipper_application/flipper_application.c index 8b049a7d4..58909218a 100644 --- a/lib/flipper_application/flipper_application.c +++ b/lib/flipper_application/flipper_application.c @@ -43,6 +43,10 @@ static FlipperApplicationPreloadStatus return FlipperApplicationPreloadStatusInvalidManifest; } + if(!flipper_application_manifest_is_target_compatible(&app->manifest)) { + return FlipperApplicationPreloadStatusTargetMismatch; + } + if(!flipper_application_manifest_is_compatible( &app->manifest, elf_file_get_api_interface(app->elf))) { return FlipperApplicationPreloadStatusApiMismatch; diff --git a/lib/misc.scons b/lib/misc.scons index 1f951000e..b0afa932a 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -28,7 +28,6 @@ libs_recurse = [ "digital_signal", "pulse_reader", "micro-ecc", - "one_wire", "u8g2", "update_util", ] diff --git a/lib/nfc/helpers/nfc_generators.c b/lib/nfc/helpers/nfc_generators.c index 590ff4d50..50c89aba8 100644 --- a/lib/nfc/helpers/nfc_generators.c +++ b/lib/nfc/helpers/nfc_generators.c @@ -30,12 +30,32 @@ static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { furi_hal_random_fill_buf(&uid[1], length - 1); } -static void nfc_generate_mf_classic_block_0(uint8_t* block, uint8_t uid_len) { +static void nfc_generate_mf_classic_block_0( + uint8_t* block, + uint8_t uid_len, + uint8_t sak, + uint8_t atqa0, + uint8_t atqa1) { // Block length is always 16 bytes, and the UID can be either 4 or 7 bytes furi_assert(uid_len == 4 || uid_len == 7); furi_assert(block); - nfc_generate_mf_classic_uid(block, uid_len); - for(int i = uid_len; i < 16; i++) { + + if(uid_len == 4) { + // Calculate BCC + block[uid_len] = 0; + + for(int i = 0; i < uid_len; i++) { + block[uid_len] ^= block[i]; + } + } else { + uid_len -= 1; + } + + block[uid_len + 1] = sak; + block[uid_len + 2] = atqa0; + block[uid_len + 3] = atqa1; + + for(int i = uid_len + 4; i < 16; i++) { block[i] = 0xFF; } } @@ -74,7 +94,6 @@ static void data->nfc_data.type = FuriHalNfcTypeA; data->nfc_data.interface = FuriHalNfcInterfaceRf; data->nfc_data.uid_len = uid_len; - nfc_generate_mf_classic_block_0(data->mf_classic_data.block[0].value, uid_len); data->nfc_data.atqa[0] = 0x44; data->nfc_data.atqa[1] = 0x00; data->nfc_data.sak = 0x08; @@ -316,6 +335,7 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) { void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { nfc_generate_common_start(data); + nfc_generate_mf_classic_uid(data->mf_classic_data.block[0].value, uid_len); nfc_generate_mf_classic_common(data, uid_len, type); // Set the UID @@ -339,7 +359,6 @@ void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType } // Set SAK to 18 data->nfc_data.sak = 0x18; - } else if(type == MfClassicType1k) { // Set every block to 0xFF for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) { @@ -366,6 +385,13 @@ void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType data->nfc_data.sak = 0x09; } + nfc_generate_mf_classic_block_0( + data->mf_classic_data.block[0].value, + uid_len, + data->nfc_data.sak, + data->nfc_data.atqa[0], + data->nfc_data.atqa[1]); + mfc->type = type; } diff --git a/lib/nfc/helpers/reader_analyzer.c b/lib/nfc/helpers/reader_analyzer.c index 45f1a572f..0063b13e7 100644 --- a/lib/nfc/helpers/reader_analyzer.c +++ b/lib/nfc/helpers/reader_analyzer.c @@ -163,6 +163,7 @@ void reader_analyzer_stop(ReaderAnalyzer* instance) { } if(instance->pcap) { nfc_debug_pcap_free(instance->pcap); + instance->pcap = NULL; } } diff --git a/lib/nfc/parsers/all_in_one.c b/lib/nfc/parsers/all_in_one.c index c02710a29..edcc0d0c7 100644 --- a/lib/nfc/parsers/all_in_one.c +++ b/lib/nfc/parsers/all_in_one.c @@ -4,7 +4,7 @@ #include #include -#include "furi_hal.h" +#include #define ALL_IN_ONE_LAYOUT_UNKNOWN 0 #define ALL_IN_ONE_LAYOUT_A 1 diff --git a/lib/nfc/parsers/plantain_4k_parser.c b/lib/nfc/parsers/plantain_4k_parser.c index e636bee00..aed41965c 100644 --- a/lib/nfc/parsers/plantain_4k_parser.c +++ b/lib/nfc/parsers/plantain_4k_parser.c @@ -3,7 +3,7 @@ #include #include -#include "furi_hal.h" +#include static const MfClassicAuthContext plantain_keys_4k[] = { {.sector = 0, .key_a = 0xFFFFFFFFFFFF, .key_b = 0xFFFFFFFFFFFF}, diff --git a/lib/nfc/parsers/plantain_parser.c b/lib/nfc/parsers/plantain_parser.c index c0e2a0947..3a1d17732 100644 --- a/lib/nfc/parsers/plantain_parser.c +++ b/lib/nfc/parsers/plantain_parser.c @@ -3,7 +3,7 @@ #include #include -#include "furi_hal.h" +#include static const MfClassicAuthContext plantain_keys[] = { {.sector = 0, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, diff --git a/lib/nfc/parsers/two_cities.c b/lib/nfc/parsers/two_cities.c index 335248b2a..0e2ed5690 100644 --- a/lib/nfc/parsers/two_cities.c +++ b/lib/nfc/parsers/two_cities.c @@ -4,7 +4,7 @@ #include #include -#include "furi_hal.h" +#include static const MfClassicAuthContext two_cities_keys_4k[] = { {.sector = 0, .key_a = 0xffffffffffff, .key_b = 0xffffffffffff}, diff --git a/lib/nfc/protocols/emv.c b/lib/nfc/protocols/emv.c index e00d09e70..4c4ac856b 100644 --- a/lib/nfc/protocols/emv.c +++ b/lib/nfc/protocols/emv.c @@ -142,21 +142,44 @@ static bool emv_decode_response(uint8_t* buff, uint16_t len, EmvApplication* app success = true; FURI_LOG_T(TAG, "found EMV_TAG_AFL %x (len=%d)", tag, tlen); break; - case EMV_TAG_CARD_NUM: // Track 2 Equivalent Data. 0xD0 delimits PAN from expiry (YYMM) + case EMV_TAG_TRACK_1_EQUIV: { + char track_1_equiv[80]; + memcpy(track_1_equiv, &buff[i], tlen); + track_1_equiv[tlen] = '\0'; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_1_EQUIV %x : %s", tag, track_1_equiv); + break; + } + case EMV_TAG_TRACK_2_EQUIV: { + // 0xD0 delimits PAN from expiry (YYMM) for(int x = 1; x < tlen; x++) { if(buff[i + x + 1] > 0xD0) { memcpy(app->card_number, &buff[i], x + 1); app->card_number_len = x + 1; + app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4); + app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4); break; } } + + // Convert 4-bit to ASCII representation + char track_2_equiv[41]; + uint8_t track_2_equiv_len = 0; + for(int x = 0; x < tlen; x++) { + char top = (buff[i + x] >> 4) + '0'; + char bottom = (buff[i + x] & 0x0F) + '0'; + track_2_equiv[x * 2] = top; + track_2_equiv_len++; + if(top == '?') break; + track_2_equiv[x * 2 + 1] = bottom; + track_2_equiv_len++; + if(bottom == '?') break; + } + track_2_equiv[track_2_equiv_len] = '\0'; success = true; - FURI_LOG_T( - TAG, - "found EMV_TAG_CARD_NUM %x (len=%d)", - EMV_TAG_CARD_NUM, - app->card_number_len); + FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x : %s", tag, track_2_equiv); break; + } case EMV_TAG_PAN: memcpy(app->card_number, &buff[i], tlen); app->card_number_len = tlen; diff --git a/lib/nfc/protocols/emv.h b/lib/nfc/protocols/emv.h index 0ccf7c3e0..c5b089fdf 100644 --- a/lib/nfc/protocols/emv.h +++ b/lib/nfc/protocols/emv.h @@ -11,7 +11,8 @@ #define EMV_TAG_CARD_NAME 0x50 #define EMV_TAG_FCI 0xBF0C #define EMV_TAG_LOG_CTRL 0x9F4D -#define EMV_TAG_CARD_NUM 0x57 +#define EMV_TAG_TRACK_1_EQUIV 0x56 +#define EMV_TAG_TRACK_2_EQUIV 0x57 #define EMV_TAG_PAN 0x5A #define EMV_TAG_AFL 0x94 #define EMV_TAG_EXP_DATE 0x5F24 diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 5fda122ab..a9b286611 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -7,10 +7,17 @@ #define TAG "MfClassic" -#define MF_CLASSIC_AUTH_KEY_A_CMD (0x60U) -#define MF_CLASSIC_AUTH_KEY_B_CMD (0x61U) -#define MF_CLASSIC_READ_BLOCK_CMD (0x30) -#define MF_CLASSIC_WRITE_BLOCK_CMD (0xA0) +#define MF_CLASSIC_ACK_CMD 0xAU +#define MF_CLASSIC_NACK_BUF_VALID_CMD 0x0U +#define MF_CLASSIC_NACK_BUF_INVALID_CMD 0x4U +#define MF_CLASSIC_AUTH_KEY_A_CMD 0x60U +#define MF_CLASSIC_AUTH_KEY_B_CMD 0x61U +#define MF_CLASSIC_READ_BLOCK_CMD 0x30U +#define MF_CLASSIC_WRITE_BLOCK_CMD 0xA0U +#define MF_CLASSIC_TRANSFER_CMD 0xB0U +#define MF_CLASSIC_DECREMENT_CMD 0xC0U +#define MF_CLASSIC_INCREMENT_CMD 0xC1U +#define MF_CLASSIC_RESTORE_CMD 0xC2U const char* mf_classic_get_type_str(MfClassicType type) { if(type == MfClassicTypeMini) { @@ -217,8 +224,8 @@ void mf_classic_get_read_sectors_and_keys( uint8_t first_block = mf_classic_get_first_block_num_of_sector(i); uint8_t total_blocks_in_sec = mf_classic_get_blocks_num_in_sector(i); bool blocks_read = true; - for(size_t i = first_block; i < first_block + total_blocks_in_sec; i++) { - blocks_read = mf_classic_is_block_read(data, i); + for(size_t j = first_block; j < first_block + total_blocks_in_sec; j++) { + blocks_read = mf_classic_is_block_read(data, j); if(!blocks_read) break; } if(blocks_read) { @@ -353,6 +360,16 @@ static bool mf_classic_is_allowed_access( } } +bool mf_classic_is_value_block(MfClassicData* data, uint8_t block_num) { + // Check if key A can write, if it can, it's transport configuration, not data block + return !mf_classic_is_allowed_access_data_block( + data, block_num, MfClassicKeyA, MfClassicActionDataWrite) && + (mf_classic_is_allowed_access_data_block( + data, block_num, MfClassicKeyB, MfClassicActionDataInc) || + mf_classic_is_allowed_access_data_block( + data, block_num, MfClassicKeyB, MfClassicActionDataDec)); +} + bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { UNUSED(ATQA1); if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) { @@ -401,6 +418,36 @@ void mf_classic_reader_add_sector( } } +bool mf_classic_block_to_value(const uint8_t* block, int32_t* value, uint8_t* addr) { + uint32_t v = *(uint32_t*)&block[0]; + uint32_t v_inv = *(uint32_t*)&block[4]; + uint32_t v1 = *(uint32_t*)&block[8]; + + bool val_checks = + ((v == v1) && (v == ~v_inv) && (block[12] == (~block[13] & 0xFF)) && + (block[14] == (~block[15] & 0xFF)) && (block[12] == block[14])); + if(value) { + *value = (int32_t)v; + } + if(addr) { + *addr = block[12]; + } + return val_checks; +} + +void mf_classic_value_to_block(int32_t value, uint8_t addr, uint8_t* block) { + uint32_t v_inv = ~((uint32_t)value); + + memcpy(block, &value, 4); //-V1086 + memcpy(block + 4, &v_inv, 4); //-V1086 + memcpy(block + 8, &value, 4); //-V1086 + + block[12] = addr; + block[13] = ~addr & 0xFF; + block[14] = addr; + block[15] = ~addr & 0xFF; +} + void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint8_t sector) { furi_assert(auth_ctx); auth_ctx->sector = sector; @@ -553,8 +600,9 @@ bool mf_classic_read_block( uint8_t plain_cmd[4] = {MF_CLASSIC_READ_BLOCK_CMD, block_num, 0x00, 0x00}; nfca_append_crc16(plain_cmd, 2); - crypto1_encrypt(crypto, NULL, plain_cmd, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); - tx_rx->tx_bits = 4 * 9; + crypto1_encrypt( + crypto, NULL, plain_cmd, sizeof(plain_cmd) * 8, tx_rx->tx_data, tx_rx->tx_parity); + tx_rx->tx_bits = sizeof(plain_cmd) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; if(furi_hal_nfc_tx_rx(tx_rx, 50)) { @@ -605,6 +653,14 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { mf_classic_set_block_read(data, i, &block_tmp); blocks_read++; + } else if(i > start_block) { + // Try to re-auth to read block in case prevous block was protected from read + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyA, &crypto, false, 0)) break; + if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mf_classic_set_block_read(data, i, &block_tmp); + blocks_read++; + } } furi_hal_nfc_sleep(); } else { @@ -618,12 +674,21 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u if(!key_b_found) break; FURI_LOG_D(TAG, "Try to read blocks with key B"); key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b)); + if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break; for(size_t i = start_block; i < start_block + total_blocks; i++) { if(!mf_classic_is_block_read(data, i)) { if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyB, &crypto, false, 0)) continue; if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { mf_classic_set_block_read(data, i, &block_tmp); blocks_read++; + } else if(i > start_block) { + // Try to re-auth to read block in case prevous block was protected from read + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyB, &crypto, false, 0)) break; + if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mf_classic_set_block_read(data, i, &block_tmp); + blocks_read++; + } } furi_hal_nfc_sleep(); } else { @@ -676,6 +741,11 @@ static bool mf_classic_read_sector_with_reader( // Read blocks for(uint8_t i = 0; i < sector->total_blocks; i++) { + if(mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) continue; + if(i == 0) continue; + // Try to auth to read next block in case previous is locked + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, first_block + i, key, key_type, crypto, false, 0)) continue; mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i]); } // Save sector keys in last block @@ -760,6 +830,9 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ bool is_encrypted = false; uint8_t plain_data[MF_CLASSIC_MAX_DATA_SIZE]; MfClassicKey access_key = MfClassicKeyA; + // Used for decrement and increment - copy to block on transfer + uint8_t transfer_buf[MF_CLASSIC_BLOCK_SIZE] = {}; + bool transfer_buf_valid = false; // Read command while(!command_processed) { //-V654 @@ -778,18 +851,25 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); } - if(plain_data[0] == 0x50 && plain_data[1] == 0x00) { + // After increment, decrement or restore the only allowed command is transfer + uint8_t cmd = plain_data[0]; + if(transfer_buf_valid && cmd != MF_CLASSIC_TRANSFER_CMD) { + break; + } + + if(cmd == 0x50 && plain_data[1] == 0x00) { FURI_LOG_T(TAG, "Halt received"); furi_hal_nfc_listen_sleep(); command_processed = true; break; - } else if(plain_data[0] == 0x60 || plain_data[0] == 0x61) { + } + if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD || cmd == MF_CLASSIC_AUTH_KEY_B_CMD) { uint8_t block = plain_data[1]; uint64_t key = 0; uint8_t sector_trailer_block = mf_classic_get_sector_trailer_num_by_block(block); MfClassicSectorTrailer* sector_trailer = (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; - if(plain_data[0] == 0x60) { + if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) { key = nfc_util_bytes2num(sector_trailer->key_a, 6); access_key = MfClassicKeyA; } else { @@ -807,9 +887,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ crypto1_word(&emulator->crypto, emulator->cuid ^ nonce, 0); memcpy(tx_rx->tx_data, nt, sizeof(nt)); tx_rx->tx_parity[0] = 0; - for(size_t i = 0; i < sizeof(nt); i++) { - tx_rx->tx_parity[0] |= nfc_util_odd_parity8(nt[i]) << (7 - i); - } + nfc_util_odd_parity(tx_rx->tx_data, tx_rx->tx_parity, sizeof(nt)); tx_rx->tx_bits = sizeof(nt) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; } else { @@ -830,7 +908,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } if(tx_rx->rx_bits != 64) { - FURI_LOG_W(TAG, "Incorrect nr + ar"); + FURI_LOG_W(TAG, "Incorrect nr + ar length: %d", tx_rx->rx_bits); command_processed = true; break; } @@ -838,16 +916,6 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ uint32_t nr = nfc_util_bytes2num(tx_rx->rx_data, 4); uint32_t ar = nfc_util_bytes2num(&tx_rx->rx_data[4], 4); - FURI_LOG_D( - TAG, - "%08lx key%c block %d nt/nr/ar: %08lx %08lx %08lx", - emulator->cuid, - access_key == MfClassicKeyA ? 'A' : 'B', - sector_trailer_block, - nonce, - nr, - ar); - crypto1_word(&emulator->crypto, nr, 1); uint32_t cardRr = ar ^ crypto1_word(&emulator->crypto, 0, 0); if(cardRr != prng_successor(nonce, 64)) { @@ -858,22 +926,30 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } uint32_t ans = prng_successor(nonce, 96); - uint8_t responce[4] = {}; - nfc_util_num2bytes(ans, 4, responce); + uint8_t response[4] = {}; + nfc_util_num2bytes(ans, 4, response); crypto1_encrypt( &emulator->crypto, NULL, - responce, - sizeof(responce) * 8, + response, + sizeof(response) * 8, tx_rx->tx_data, tx_rx->tx_parity); - tx_rx->tx_bits = sizeof(responce) * 8; + tx_rx->tx_bits = sizeof(response) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; is_encrypted = true; - } else if(is_encrypted && plain_data[0] == 0x30) { + continue; + } + + if(!is_encrypted) { + FURI_LOG_T(TAG, "Invalid command before auth session established: %02X", cmd); + break; + } + + if(cmd == MF_CLASSIC_READ_BLOCK_CMD) { uint8_t block = plain_data[1]; - uint8_t block_data[18] = {}; + uint8_t block_data[MF_CLASSIC_BLOCK_SIZE + 2] = {}; memcpy(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE); if(mf_classic_is_sector_trailer(block)) { if(!mf_classic_is_allowed_access( @@ -908,24 +984,24 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ sizeof(block_data) * 8, tx_rx->tx_data, tx_rx->tx_parity); - tx_rx->tx_bits = 18 * 8; + tx_rx->tx_bits = (MF_CLASSIC_BLOCK_SIZE + 2) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; - } else if(is_encrypted && plain_data[0] == 0xA0) { + } else if(cmd == MF_CLASSIC_WRITE_BLOCK_CMD) { uint8_t block = plain_data[1]; if(block > mf_classic_get_total_block_num(emulator->data.type)) { break; } // Send ACK - uint8_t ack = 0x0A; + uint8_t ack = MF_CLASSIC_ACK_CMD; crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; - if(tx_rx->rx_bits != 18 * 8) break; + if(tx_rx->rx_bits != (MF_CLASSIC_BLOCK_SIZE + 2) * 8) break; crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); - uint8_t block_data[16] = {}; + uint8_t block_data[MF_CLASSIC_BLOCK_SIZE] = {}; memcpy(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE); if(mf_classic_is_sector_trailer(block)) { if(mf_classic_is_allowed_access( @@ -944,6 +1020,8 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ if(mf_classic_is_allowed_access( emulator, block, access_key, MfClassicActionDataWrite)) { memcpy(block_data, plain_data, MF_CLASSIC_BLOCK_SIZE); + } else { + break; } } if(memcmp(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE) != 0) { @@ -951,19 +1029,83 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ emulator->data_changed = true; } // Send ACK - ack = 0x0A; + ack = MF_CLASSIC_ACK_CMD; + crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_bits = 4; + } else if( + cmd == MF_CLASSIC_DECREMENT_CMD || cmd == MF_CLASSIC_INCREMENT_CMD || + cmd == MF_CLASSIC_RESTORE_CMD) { + uint8_t block = plain_data[1]; + + if(block > mf_classic_get_total_block_num(emulator->data.type)) { + break; + } + + MfClassicAction action = MfClassicActionDataDec; + if(cmd == MF_CLASSIC_INCREMENT_CMD) { + action = MfClassicActionDataInc; + } + if(!mf_classic_is_allowed_access(emulator, block, access_key, action)) { + break; + } + + int32_t prev_value; + uint8_t addr; + if(!mf_classic_block_to_value(emulator->data.block[block].value, &prev_value, &addr)) { + break; + } + + // Send ACK + uint8_t ack = MF_CLASSIC_ACK_CMD; + crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_bits = 4; + + if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; + if(tx_rx->rx_bits != (sizeof(int32_t) + 2) * 8) break; + + crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); + int32_t value = *(int32_t*)&plain_data[0]; + if(value < 0) { + value = -value; + } + if(cmd == MF_CLASSIC_DECREMENT_CMD) { + value = -value; + } else if(cmd == MF_CLASSIC_RESTORE_CMD) { + value = 0; + } + + mf_classic_value_to_block(prev_value + value, addr, transfer_buf); + transfer_buf_valid = true; + // Commands do not ACK + tx_rx->tx_bits = 0; + } else if(cmd == MF_CLASSIC_TRANSFER_CMD) { + uint8_t block = plain_data[1]; + if(!mf_classic_is_allowed_access(emulator, block, access_key, MfClassicActionDataDec)) { + break; + } + if(memcmp(transfer_buf, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE) != + 0) { + memcpy(emulator->data.block[block].value, transfer_buf, MF_CLASSIC_BLOCK_SIZE); + emulator->data_changed = true; + } + transfer_buf_valid = false; + + uint8_t ack = MF_CLASSIC_ACK_CMD; crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; } else { - // Unknown command + FURI_LOG_T(TAG, "Unknown command: %02X", cmd); break; } } if(!command_processed) { // Send NACK - uint8_t nack = 0x04; + uint8_t nack = transfer_buf_valid ? MF_CLASSIC_NACK_BUF_VALID_CMD : + MF_CLASSIC_NACK_BUF_INVALID_CMD; if(is_encrypted) { crypto1_encrypt(&emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); } else { @@ -977,37 +1119,50 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ return true; } +void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto) { + furi_assert(tx_rx); + + uint8_t plain_data[4] = {0x50, 0x00, 0x00, 0x00}; + + nfca_append_crc16(plain_data, 2); + if(crypto) { + crypto1_encrypt( + crypto, NULL, plain_data, sizeof(plain_data) * 8, tx_rx->tx_data, tx_rx->tx_parity); + } else { + memcpy(tx_rx->tx_data, plain_data, sizeof(plain_data)); + nfc_util_odd_parity(tx_rx->tx_data, tx_rx->tx_parity, sizeof(plain_data)); + } + + tx_rx->tx_bits = sizeof(plain_data) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + furi_hal_nfc_tx_rx(tx_rx, 50); +} + bool mf_classic_write_block( FuriHalNfcTxRxContext* tx_rx, - MfClassicBlock* src_block, + Crypto1* crypto, uint8_t block_num, - MfClassicKey key_type, - uint64_t key) { + MfClassicBlock* src_block) { furi_assert(tx_rx); + furi_assert(crypto); furi_assert(src_block); - Crypto1 crypto = {}; - uint8_t plain_data[18] = {}; - uint8_t resp = 0; bool write_success = false; + uint8_t plain_data[MF_CLASSIC_BLOCK_SIZE + 2] = {}; + uint8_t resp; do { - furi_hal_nfc_sleep(); - if(!mf_classic_auth(tx_rx, block_num, key, key_type, &crypto, false, 0)) { - FURI_LOG_D(TAG, "Auth fail"); - break; - } // Send write command plain_data[0] = MF_CLASSIC_WRITE_BLOCK_CMD; plain_data[1] = block_num; nfca_append_crc16(plain_data, 2); - crypto1_encrypt(&crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); + crypto1_encrypt(crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = 4 * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 4) { - crypto1_decrypt(&crypto, tx_rx->rx_data, 4, &resp); + crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); if(resp != 0x0A) { FURI_LOG_D(TAG, "NACK received on write cmd: %02X", resp); break; @@ -1025,7 +1180,7 @@ bool mf_classic_write_block( memcpy(plain_data, src_block->value, MF_CLASSIC_BLOCK_SIZE); nfca_append_crc16(plain_data, MF_CLASSIC_BLOCK_SIZE); crypto1_encrypt( - &crypto, + crypto, NULL, plain_data, (MF_CLASSIC_BLOCK_SIZE + 2) * 8, @@ -1035,8 +1190,8 @@ bool mf_classic_write_block( tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 4) { - crypto1_decrypt(&crypto, tx_rx->rx_data, 4, &resp); - if(resp != 0x0A) { + crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + if(resp != MF_CLASSIC_ACK_CMD) { FURI_LOG_D(TAG, "NACK received on sending data"); break; } @@ -1048,22 +1203,200 @@ bool mf_classic_write_block( FURI_LOG_D(TAG, "Failed to send data"); break; } - write_success = true; - // Send Halt - plain_data[0] = 0x50; - plain_data[1] = 0x00; - nfca_append_crc16(plain_data, 2); - crypto1_encrypt(&crypto, NULL, plain_data, 2 * 8, tx_rx->tx_data, tx_rx->tx_parity); - tx_rx->tx_bits = 2 * 8; - tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; - // No response is expected - furi_hal_nfc_tx_rx(tx_rx, 50); + write_success = true; } while(false); return write_success; } +bool mf_classic_auth_write_block( + FuriHalNfcTxRxContext* tx_rx, + MfClassicBlock* src_block, + uint8_t block_num, + MfClassicKey key_type, + uint64_t key) { + furi_assert(tx_rx); + furi_assert(src_block); + + Crypto1 crypto = {}; + bool write_success = false; + + do { + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, block_num, key, key_type, &crypto, false, 0)) { + FURI_LOG_D(TAG, "Auth fail"); + break; + } + + if(!mf_classic_write_block(tx_rx, &crypto, block_num, src_block)) { + FURI_LOG_D(TAG, "Write fail"); + break; + } + write_success = true; + + mf_classic_halt(tx_rx, &crypto); + } while(false); + + return write_success; +} + +bool mf_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num) { + furi_assert(tx_rx); + furi_assert(crypto); + + // Send transfer command + uint8_t plain_data[4] = {MF_CLASSIC_TRANSFER_CMD, block_num, 0, 0}; + uint8_t resp = 0; + bool transfer_success = false; + + nfca_append_crc16(plain_data, 2); + crypto1_encrypt( + crypto, NULL, plain_data, sizeof(plain_data) * 8, tx_rx->tx_data, tx_rx->tx_parity); + tx_rx->tx_bits = sizeof(plain_data) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + + do { + if(furi_hal_nfc_tx_rx(tx_rx, 50)) { + if(tx_rx->rx_bits == 4) { + crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + if(resp != 0x0A) { + FURI_LOG_D(TAG, "NACK received on transfer cmd: %02X", resp); + break; + } + } else { + FURI_LOG_D(TAG, "Not ACK received"); + break; + } + } else { + FURI_LOG_D(TAG, "Failed to send transfer cmd"); + break; + } + + transfer_success = true; + } while(false); + + return transfer_success; +} + +bool mf_classic_value_cmd( + FuriHalNfcTxRxContext* tx_rx, + Crypto1* crypto, + uint8_t block_num, + uint8_t cmd, + int32_t d_value) { + furi_assert(tx_rx); + furi_assert(crypto); + furi_assert( + cmd == MF_CLASSIC_INCREMENT_CMD || cmd == MF_CLASSIC_DECREMENT_CMD || + cmd == MF_CLASSIC_RESTORE_CMD); + furi_assert(d_value >= 0); + + uint8_t plain_data[sizeof(d_value) + 2] = {}; + uint8_t resp = 0; + bool success = false; + + do { + // Send cmd + plain_data[0] = cmd; + plain_data[1] = block_num; + nfca_append_crc16(plain_data, 2); + crypto1_encrypt(crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); + tx_rx->tx_bits = 4 * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + + if(furi_hal_nfc_tx_rx(tx_rx, 50)) { + if(tx_rx->rx_bits == 4) { + crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + if(resp != 0x0A) { + FURI_LOG_D(TAG, "NACK received on write cmd: %02X", resp); + break; + } + } else { + FURI_LOG_D(TAG, "Not ACK received"); + break; + } + } else { + FURI_LOG_D(TAG, "Failed to send write cmd"); + break; + } + + // Send data + memcpy(plain_data, &d_value, sizeof(d_value)); + nfca_append_crc16(plain_data, sizeof(d_value)); + crypto1_encrypt( + crypto, NULL, plain_data, (sizeof(d_value) + 2) * 8, tx_rx->tx_data, tx_rx->tx_parity); + tx_rx->tx_bits = (sizeof(d_value) + 2) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + // inc, dec, restore do not ACK, but they do NACK + if(furi_hal_nfc_tx_rx(tx_rx, 50)) { + if(tx_rx->rx_bits == 4) { + crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + if(resp != 0x0A) { + FURI_LOG_D(TAG, "NACK received on transfer cmd: %02X", resp); + break; + } + } else { + FURI_LOG_D(TAG, "Not NACK received"); + break; + } + } + + success = true; + + } while(false); + + return success; +} + +bool mf_classic_value_cmd_full( + FuriHalNfcTxRxContext* tx_rx, + MfClassicBlock* src_block, + uint8_t block_num, + MfClassicKey key_type, + uint64_t key, + int32_t d_value) { + furi_assert(tx_rx); + furi_assert(src_block); + + Crypto1 crypto = {}; + uint8_t cmd; + bool success = false; + + if(d_value > 0) { + cmd = MF_CLASSIC_INCREMENT_CMD; + } else if(d_value < 0) { + cmd = MF_CLASSIC_DECREMENT_CMD; + d_value = -d_value; + } else { + cmd = MF_CLASSIC_RESTORE_CMD; + } + + do { + furi_hal_nfc_sleep(); + if(!mf_classic_auth(tx_rx, block_num, key, key_type, &crypto, false, 0)) { + FURI_LOG_D(TAG, "Value cmd auth fail"); + break; + } + if(!mf_classic_value_cmd(tx_rx, &crypto, block_num, cmd, d_value)) { + FURI_LOG_D(TAG, "Value cmd inc/dec/res fail"); + break; + } + + if(!mf_classic_transfer(tx_rx, &crypto, block_num)) { + FURI_LOG_D(TAG, "Value cmd transfer fail"); + break; + } + + success = true; + + // Send Halt + mf_classic_halt(tx_rx, &crypto); + } while(false); + + return success; +} + bool mf_classic_write_sector( FuriHalNfcTxRxContext* tx_rx, MfClassicData* dest_data, @@ -1084,31 +1417,99 @@ bool mf_classic_write_sector( // Compare blocks if(memcmp(dest_data->block[i].value, src_data->block[i].value, MF_CLASSIC_BLOCK_SIZE) != 0) { - bool key_a_write_allowed = mf_classic_is_allowed_access_data_block( - dest_data, i, MfClassicKeyA, MfClassicActionDataWrite); - bool key_b_write_allowed = mf_classic_is_allowed_access_data_block( - dest_data, i, MfClassicKeyB, MfClassicActionDataWrite); + if(mf_classic_is_value_block(dest_data, i)) { + bool key_a_inc_allowed = mf_classic_is_allowed_access_data_block( + dest_data, i, MfClassicKeyA, MfClassicActionDataInc); + bool key_b_inc_allowed = mf_classic_is_allowed_access_data_block( + dest_data, i, MfClassicKeyB, MfClassicActionDataInc); + bool key_a_dec_allowed = mf_classic_is_allowed_access_data_block( + dest_data, i, MfClassicKeyA, MfClassicActionDataDec); + bool key_b_dec_allowed = mf_classic_is_allowed_access_data_block( + dest_data, i, MfClassicKeyB, MfClassicActionDataDec); - if(key_a_found && key_a_write_allowed) { - FURI_LOG_I(TAG, "Writing block %d with key A", i); - uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); - if(!mf_classic_write_block(tx_rx, &src_data->block[i], i, MfClassicKeyA, key)) { - FURI_LOG_E(TAG, "Failed to write block %d", i); - write_success = false; - break; - } - } else if(key_b_found && key_b_write_allowed) { - FURI_LOG_I(TAG, "Writing block %d with key A", i); - uint64_t key = nfc_util_bytes2num(sec_tr->key_b, 6); - if(!mf_classic_write_block(tx_rx, &src_data->block[i], i, MfClassicKeyB, key)) { - FURI_LOG_E(TAG, "Failed to write block %d", i); - write_success = false; - break; + int32_t src_value, dst_value; + + mf_classic_block_to_value(src_data->block[i].value, &src_value, NULL); + mf_classic_block_to_value(dest_data->block[i].value, &dst_value, NULL); + + int32_t diff = src_value - dst_value; + + if(diff > 0) { + if(key_a_found && key_a_inc_allowed) { + FURI_LOG_I(TAG, "Incrementing block %d with key A by %ld", i, diff); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(!mf_classic_value_cmd_full( + tx_rx, &src_data->block[i], i, MfClassicKeyA, key, diff)) { + FURI_LOG_E(TAG, "Failed to increment block %d", i); + write_success = false; + break; + } + } else if(key_b_found && key_b_inc_allowed) { + FURI_LOG_I(TAG, "Incrementing block %d with key B by %ld", i, diff); + uint64_t key = nfc_util_bytes2num(sec_tr->key_b, 6); + if(!mf_classic_value_cmd_full( + tx_rx, &src_data->block[i], i, MfClassicKeyB, key, diff)) { + FURI_LOG_E(TAG, "Failed to increment block %d", i); + write_success = false; + break; + } + } else { + FURI_LOG_E(TAG, "Failed to increment block %d", i); + } + } else if(diff < 0) { + if(key_a_found && key_a_dec_allowed) { + FURI_LOG_I(TAG, "Decrementing block %d with key A by %ld", i, -diff); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(!mf_classic_value_cmd_full( + tx_rx, &src_data->block[i], i, MfClassicKeyA, key, diff)) { + FURI_LOG_E(TAG, "Failed to decrement block %d", i); + write_success = false; + break; + } + } else if(key_b_found && key_b_dec_allowed) { + FURI_LOG_I(TAG, "Decrementing block %d with key B by %ld", i, diff); + uint64_t key = nfc_util_bytes2num(sec_tr->key_b, 6); + if(!mf_classic_value_cmd_full( + tx_rx, &src_data->block[i], i, MfClassicKeyB, key, diff)) { + FURI_LOG_E(TAG, "Failed to decrement block %d", i); + write_success = false; + break; + } + } else { + FURI_LOG_E(TAG, "Failed to decrement block %d", i); + } + } else { + FURI_LOG_E(TAG, "Value block %d address changed, cannot write it", i); } } else { - FURI_LOG_E(TAG, "Failed to find key with write access"); - write_success = false; - break; + bool key_a_write_allowed = mf_classic_is_allowed_access_data_block( + dest_data, i, MfClassicKeyA, MfClassicActionDataWrite); + bool key_b_write_allowed = mf_classic_is_allowed_access_data_block( + dest_data, i, MfClassicKeyB, MfClassicActionDataWrite); + + if(key_a_found && key_a_write_allowed) { + FURI_LOG_I(TAG, "Writing block %d with key A", i); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); + if(!mf_classic_auth_write_block( + tx_rx, &src_data->block[i], i, MfClassicKeyA, key)) { + FURI_LOG_E(TAG, "Failed to write block %d", i); + write_success = false; + break; + } + } else if(key_b_found && key_b_write_allowed) { + FURI_LOG_I(TAG, "Writing block %d with key A", i); + uint64_t key = nfc_util_bytes2num(sec_tr->key_b, 6); + if(!mf_classic_auth_write_block( + tx_rx, &src_data->block[i], i, MfClassicKeyB, key)) { + FURI_LOG_E(TAG, "Failed to write block %d", i); + write_success = false; + break; + } + } else { + FURI_LOG_E(TAG, "Failed to find key with write access"); + write_success = false; + break; + } } } else { FURI_LOG_D(TAG, "Blocks %d are equal", i); diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index ac5701ecf..e09322ae8 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -6,6 +6,7 @@ #define MF_CLASSIC_BLOCK_SIZE (16) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) +#define MF_MINI_TOTAL_SECTORS_NUM (5) #define MF_CLASSIC_1K_TOTAL_SECTORS_NUM (16) #define MF_CLASSIC_4K_TOTAL_SECTORS_NUM (40) #define MF_MINI_TOTAL_SECTORS_NUM (5) @@ -120,6 +121,12 @@ bool mf_classic_is_allowed_access_data_block( MfClassicKey key, MfClassicAction action); +bool mf_classic_is_value_block(MfClassicData* data, uint8_t block_num); + +bool mf_classic_block_to_value(const uint8_t* block, int32_t* value, uint8_t* addr); + +void mf_classic_value_to_block(int32_t value, uint8_t addr, uint8_t* block); + bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); void mf_classic_set_key_found( @@ -177,6 +184,12 @@ void mf_classic_reader_add_sector( uint64_t key_a, uint64_t key_b); +bool mf_classic_read_block( + FuriHalNfcTxRxContext* tx_rx, + Crypto1* crypto, + uint8_t block_num, + MfClassicBlock* block); + void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, uint8_t sec_num); uint8_t mf_classic_read_card( @@ -188,13 +201,38 @@ uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); +void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto); + bool mf_classic_write_block( + FuriHalNfcTxRxContext* tx_rx, + Crypto1* crypto, + uint8_t block_num, + MfClassicBlock* src_block); + +bool mf_classic_auth_write_block( FuriHalNfcTxRxContext* tx_rx, MfClassicBlock* src_block, uint8_t block_num, MfClassicKey key_type, uint64_t key); +bool mf_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num); + +bool mf_classic_value_cmd( + FuriHalNfcTxRxContext* tx_rx, + Crypto1* crypto, + uint8_t block_num, + uint8_t cmd, + int32_t d_value); + +bool mf_classic_value_cmd_full( + FuriHalNfcTxRxContext* tx_rx, + MfClassicBlock* src_block, + uint8_t block_num, + MfClassicKey key_type, + uint64_t key, + int32_t d_value); + bool mf_classic_write_sector( FuriHalNfcTxRxContext* tx_rx, MfClassicData* dest_data, diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index d642e290a..0e28c0074 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -3,7 +3,7 @@ #include "mifare_ultralight.h" #include "nfc_util.h" #include -#include "furi_hal_nfc.h" +#include #define TAG "MfUltralight" diff --git a/lib/nfc/protocols/nfc_util.c b/lib/nfc/protocols/nfc_util.c index 9de6f982b..8cb6d57f2 100644 --- a/lib/nfc/protocols/nfc_util.c +++ b/lib/nfc/protocols/nfc_util.c @@ -23,7 +23,7 @@ void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest) { } } -uint64_t nfc_util_bytes2num(uint8_t* src, uint8_t len) { +uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) { furi_assert(src); furi_assert(len <= 8); @@ -45,3 +45,26 @@ uint8_t nfc_util_even_parity32(uint32_t data) { uint8_t nfc_util_odd_parity8(uint8_t data) { return nfc_util_odd_byte_parity[data]; } + +void nfc_util_odd_parity(const uint8_t* src, uint8_t* dst, uint8_t len) { + furi_assert(src); + furi_assert(dst); + + uint8_t parity = 0; + uint8_t bit = 0; + while(len--) { + parity |= nfc_util_odd_parity8(*src) << (7 - bit); // parity is MSB first + bit++; + if(bit == 8) { + *dst = parity; + dst++; + parity = 0; + bit = 0; + } + src++; + } + + if(bit) { + *dst = parity; + } +} \ No newline at end of file diff --git a/lib/nfc/protocols/nfc_util.h b/lib/nfc/protocols/nfc_util.h index d530badc3..04fa7622b 100644 --- a/lib/nfc/protocols/nfc_util.h +++ b/lib/nfc/protocols/nfc_util.h @@ -4,8 +4,10 @@ void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest); -uint64_t nfc_util_bytes2num(uint8_t* src, uint8_t len); +uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len); uint8_t nfc_util_even_parity32(uint32_t data); uint8_t nfc_util_odd_parity8(uint8_t data); + +void nfc_util_odd_parity(const uint8_t* src, uint8_t* dst, uint8_t len); diff --git a/lib/one_wire/SConscript b/lib/one_wire/SConscript new file mode 100644 index 000000000..5e06d21e3 --- /dev/null +++ b/lib/one_wire/SConscript @@ -0,0 +1,27 @@ +Import("env") + +env.Append( + LINT_SOURCES=[ + Dir("."), + ], + CPPPATH=[ + "#/lib/one_wire", + ], + SDK_HEADERS=[ + File("one_wire_host_timing.h"), + File("one_wire_host.h"), + File("one_wire_slave.h"), + File("one_wire_device.h"), + File("ibutton/ibutton_worker.h"), + File("maxim_crc.h"), + ], +) + +libenv = env.Clone(FW_LIB_NAME="one_wire") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/subghz/blocks/encoder.c b/lib/subghz/blocks/encoder.c index f3349b5fc..49ec4f177 100644 --- a/lib/subghz/blocks/encoder.c +++ b/lib/subghz/blocks/encoder.c @@ -2,6 +2,8 @@ #include "math.h" #include +#include "furi.h" + #define TAG "SubGhzBlockEncoder" void subghz_protocol_blocks_set_bit_array( @@ -17,21 +19,32 @@ bool subghz_protocol_blocks_get_bit_array(uint8_t data_array[], size_t read_inde return bit_read(data_array[read_index_bit >> 3], 7 - (read_index_bit & 0x7)); } -size_t subghz_protocol_blocks_get_upload( +size_t subghz_protocol_blocks_get_upload_from_bit_array( uint8_t data_array[], size_t count_bit_data_array, LevelDuration* upload, size_t max_size_upload, - uint32_t duration_bit) { - size_t index_bit = 0; + uint32_t duration_bit, + SubGhzProtocolBlockAlignBit align_bit) { + size_t bias_bit = 0; size_t size_upload = 0; uint32_t duration = duration_bit; + + if(align_bit == SubGhzProtocolBlockAlignBitRight) { + if(count_bit_data_array & 0x7) { + bias_bit = 8 - (count_bit_data_array & 0x7); + } + } + size_t index_bit = bias_bit; + bool last_bit = subghz_protocol_blocks_get_bit_array(data_array, index_bit++); - for(size_t i = 1; i < count_bit_data_array; i++) { + for(size_t i = 1 + bias_bit; i < count_bit_data_array + bias_bit; i++) { if(last_bit == subghz_protocol_blocks_get_bit_array(data_array, index_bit)) { duration += duration_bit; } else { - furi_assert(max_size_upload > size_upload); + if(size_upload > max_size_upload) { + furi_crash("SubGhz: Encoder buffer overflow"); + } upload[size_upload++] = level_duration_make( subghz_protocol_blocks_get_bit_array(data_array, index_bit - 1), duration); last_bit = !last_bit; diff --git a/lib/subghz/blocks/encoder.h b/lib/subghz/blocks/encoder.h index 1ff077726..aeaa2add0 100644 --- a/lib/subghz/blocks/encoder.h +++ b/lib/subghz/blocks/encoder.h @@ -19,6 +19,11 @@ typedef struct { } SubGhzProtocolBlockEncoder; +typedef enum { + SubGhzProtocolBlockAlignBitLeft, + SubGhzProtocolBlockAlignBitRight, +} SubGhzProtocolBlockAlignBit; + /** * Set data bit when encoding HEX array. * @param bit_value The value of the bit to be set @@ -47,13 +52,15 @@ bool subghz_protocol_blocks_get_bit_array(uint8_t data_array[], size_t read_inde * @param upload Pointer to a LevelDuration * @param max_size_upload upload size, check not to overflow * @param duration_bit duration 1 bit + * @param align_bit alignment of useful bits in an array */ -size_t subghz_protocol_blocks_get_upload( +size_t subghz_protocol_blocks_get_upload_from_bit_array( uint8_t data_array[], size_t count_bit_data_array, LevelDuration* upload, size_t max_size_upload, - uint32_t duration_bit); + uint32_t duration_bit, + SubGhzProtocolBlockAlignBit align_bit); #ifdef __cplusplus } diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index 94114676d..3d59adc82 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -100,7 +100,7 @@ bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperForma FURI_LOG_E(TAG, "Missing Bit"); break; } - instance->data_count_bit = (uint8_t)temp_data; + instance->data_count_bit = (uint16_t)temp_data; uint8_t key_data[sizeof(uint64_t)] = {0}; if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { diff --git a/lib/subghz/blocks/generic.h b/lib/subghz/blocks/generic.h index a2a0a76cf..e69de8b4f 100644 --- a/lib/subghz/blocks/generic.h +++ b/lib/subghz/blocks/generic.h @@ -5,8 +5,8 @@ #include #include -#include "furi.h" -#include "furi_hal.h" +#include +#include #include "../types.h" #ifdef __cplusplus @@ -20,7 +20,7 @@ struct SubGhzBlockGeneric { uint64_t data; uint64_t data_2; uint32_t serial; - uint8_t data_count_bit; + uint16_t data_count_bit; uint8_t btn; uint32_t cnt; uint8_t cnt_2; diff --git a/lib/subghz/environment.c b/lib/subghz/environment.c index 0a4b7b606..b39b259d4 100644 --- a/lib/subghz/environment.c +++ b/lib/subghz/environment.c @@ -6,6 +6,7 @@ struct SubGhzEnvironment { const SubGhzProtocolRegistry* protocol_registry; const char* came_atomo_rainbow_table_file_name; const char* nice_flor_s_rainbow_table_file_name; + const char* alutech_at_4n_rainbow_table_file_name; }; SubGhzEnvironment* subghz_environment_alloc() { @@ -57,6 +58,21 @@ const char* return instance->came_atomo_rainbow_table_file_name; } +void subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + SubGhzEnvironment* instance, + const char* filename) { + furi_assert(instance); + + instance->alutech_at_4n_rainbow_table_file_name = filename; +} + +const char* + subghz_environment_get_alutech_at_4n_rainbow_table_file_name(SubGhzEnvironment* instance) { + furi_assert(instance); + + return instance->alutech_at_4n_rainbow_table_file_name; +} + void subghz_environment_set_nice_flor_s_rainbow_table_file_name( SubGhzEnvironment* instance, const char* filename) { diff --git a/lib/subghz/environment.h b/lib/subghz/environment.h index e994f7c97..7bd38ba2f 100644 --- a/lib/subghz/environment.h +++ b/lib/subghz/environment.h @@ -52,6 +52,23 @@ void subghz_environment_set_came_atomo_rainbow_table_file_name( */ const char* subghz_environment_get_came_atomo_rainbow_table_file_name(SubGhzEnvironment* instance); +/** + * Set filename to work with Alutech at-4n. + * @param instance Pointer to a SubGhzEnvironment instance + * @param filename Full path to the file + */ +void subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + SubGhzEnvironment* instance, + const char* filename); + +/** + * Get filename to work with Alutech at-4n. + * @param instance Pointer to a SubGhzEnvironment instance + * @return Full path to the file + */ +const char* + subghz_environment_get_alutech_at_4n_rainbow_table_file_name(SubGhzEnvironment* instance); + /** * Set filename to work with Nice Flor-S. * @param instance Pointer to a SubGhzEnvironment instance diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c new file mode 100644 index 000000000..7849f7b21 --- /dev/null +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -0,0 +1,686 @@ +#include "alutech_at_4n.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocoAlutech_at_4n" + +#define SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE 0xFFFFFFFF + +static const SubGhzBlockConst subghz_protocol_alutech_at_4n_const = { + .te_short = 400, + .te_long = 800, + .te_delta = 140, + .min_count_bit_for_found = 72, +}; + +struct SubGhzProtocolDecoderAlutech_at_4n { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + + uint64_t data; + uint32_t crc; + uint16_t header_count; + + const char* alutech_at_4n_rainbow_table_file_name; +}; + +struct SubGhzProtocolEncoderAlutech_at_4n { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; + const char* alutech_at_4n_rainbow_table_file_name; + uint32_t crc; +}; + +typedef enum { + Alutech_at_4nDecoderStepReset = 0, + Alutech_at_4nDecoderStepCheckPreambula, + Alutech_at_4nDecoderStepSaveDuration, + Alutech_at_4nDecoderStepCheckDuration, +} Alutech_at_4nDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_alutech_at_4n_decoder = { + .alloc = subghz_protocol_decoder_alutech_at_4n_alloc, + .free = subghz_protocol_decoder_alutech_at_4n_free, + + .feed = subghz_protocol_decoder_alutech_at_4n_feed, + .reset = subghz_protocol_decoder_alutech_at_4n_reset, + + .get_hash_data = subghz_protocol_decoder_alutech_at_4n_get_hash_data, + .serialize = subghz_protocol_decoder_alutech_at_4n_serialize, + .deserialize = subghz_protocol_decoder_alutech_at_4n_deserialize, + .get_string = subghz_protocol_decoder_alutech_at_4n_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_alutech_at_4n_encoder = { + .alloc = subghz_protocol_encoder_alutech_at_4n_alloc, + .free = subghz_protocol_encoder_alutech_at_4n_free, + + .deserialize = subghz_protocol_encoder_alutech_at_4n_deserialize, + .stop = subghz_protocol_encoder_alutech_at_4n_stop, + .yield = subghz_protocol_encoder_alutech_at_4n_yield, +}; + +const SubGhzProtocol subghz_protocol_alutech_at_4n = { + .name = SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME, + .type = SubGhzProtocolTypeDynamic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_alutech_at_4n_decoder, + .encoder = &subghz_protocol_alutech_at_4n_encoder, +}; + +void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderAlutech_at_4n* instance = + malloc(sizeof(SubGhzProtocolEncoderAlutech_at_4n)); + + instance->base.protocol = &subghz_protocol_alutech_at_4n; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 512; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + + instance->alutech_at_4n_rainbow_table_file_name = + subghz_environment_get_alutech_at_4n_rainbow_table_file_name(environment); + if(instance->alutech_at_4n_rainbow_table_file_name) { + FURI_LOG_I( + TAG, "Loading rainbow table from %s", instance->alutech_at_4n_rainbow_table_file_name); + } + + return instance; +} + +void subghz_protocol_encoder_alutech_at_4n_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + free(instance->encoder.upload); + free(instance); +} + +void subghz_protocol_encoder_alutech_at_4n_stop(void* context) { + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context) { + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +/** + * Read bytes from rainbow table + * @param file_name Full path to rainbow table the file + * @param number_alutech_at_4n_magic_data number in the array + * @return alutech_at_4n_magic_data + */ +static uint32_t subghz_protocol_alutech_at_4n_get_magic_data_in_file( + const char* file_name, + uint8_t number_alutech_at_4n_magic_data) { + if(!strcmp(file_name, "")) return SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + + uint8_t buffer[sizeof(uint32_t)] = {0}; + uint32_t address = number_alutech_at_4n_magic_data * sizeof(uint32_t); + uint32_t alutech_at_4n_magic_data = 0; + + if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint32_t))) { + for(size_t i = 0; i < sizeof(uint32_t); i++) { + alutech_at_4n_magic_data = (alutech_at_4n_magic_data << 8) | buffer[i]; + } + } else { + alutech_at_4n_magic_data = SUBGHZ_NO_ALUTECH_AT_4N_RAINBOW_TABLE; + } + return alutech_at_4n_magic_data; +} + +static uint8_t subghz_protocol_alutech_at_4n_crc(uint64_t data) { + uint8_t* p = (uint8_t*)&data; + uint8_t crc = 0xff; + for(uint8_t y = 0; y < 8; y++) { + crc = crc ^ p[y]; + for(uint8_t i = 0; i < 8; i++) { + if((crc & 0x80) != 0) { + crc <<= 1; + crc ^= 0x31; + } else { + crc <<= 1; + } + } + } + return crc; +} + +static uint8_t subghz_protocol_alutech_at_4n_decrypt_data_crc(uint8_t data) { + uint8_t crc = data; + for(uint8_t i = 0; i < 8; i++) { + if((crc & 0x80) != 0) { + crc <<= 1; + crc ^= 0x31; + } else { + crc <<= 1; + } + } + return ~crc; +} + +static uint64_t subghz_protocol_alutech_at_4n_decrypt(uint64_t data, const char* file_name) { + uint8_t* p = (uint8_t*)&data; + uint32_t data1 = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + uint32_t data2 = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; + uint32_t data3 = 0; + uint32_t magic_data[] = { + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 0), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 1), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 2), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 3), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 4), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 5)}; + + uint32_t i = magic_data[0]; + do { + data2 = data2 - + ((magic_data[1] + (data1 << 4)) ^ ((magic_data[2] + (data1 >> 5)) ^ (data1 + i))); + data3 = data2 + i; + i += magic_data[3]; + data1 = + data1 - ((magic_data[4] + (data2 << 4)) ^ ((magic_data[5] + (data2 >> 5)) ^ data3)); + } while(i != 0); + + p[0] = (uint8_t)(data1 >> 24); + p[1] = (uint8_t)(data1 >> 16); + p[3] = (uint8_t)data1; + p[4] = (uint8_t)(data2 >> 24); + p[5] = (uint8_t)(data2 >> 16); + p[2] = (uint8_t)(data1 >> 8); + p[6] = (uint8_t)(data2 >> 8); + p[7] = (uint8_t)data2; + + return data; +} + +static uint64_t subghz_protocol_alutech_at_4n_encrypt(uint64_t data, const char* file_name) { + uint8_t* p = (uint8_t*)&data; + uint32_t data1 = 0; + uint32_t data2 = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + uint32_t data3 = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; + uint32_t magic_data[] = { + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 6), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 4), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 5), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 1), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 2), + subghz_protocol_alutech_at_4n_get_magic_data_in_file(file_name, 0)}; + + do { + data1 = data1 + magic_data[0]; + data2 = data2 + ((magic_data[1] + (data3 << 4)) ^ + ((magic_data[2] + (data3 >> 5)) ^ (data1 + data3))); + data3 = data3 + ((magic_data[3] + (data2 << 4)) ^ + ((magic_data[4] + (data2 >> 5)) ^ (data1 + data2))); + } while(data1 != magic_data[5]); + p[0] = (uint8_t)(data2 >> 24); + p[1] = (uint8_t)(data2 >> 16); + p[3] = (uint8_t)data2; + p[4] = (uint8_t)(data3 >> 24); + p[5] = (uint8_t)(data3 >> 16); + p[2] = (uint8_t)(data2 >> 8); + p[6] = (uint8_t)(data3 >> 8); + p[7] = (uint8_t)data3; + + return data; +} + +static bool subghz_protocol_alutech_at_4n_gen_data( + SubGhzProtocolEncoderAlutech_at_4n* instance, + uint8_t btn) { + UNUSED(btn); + + uint64_t data = subghz_protocol_blocks_reverse_key(instance->generic.data, 64); + + data = subghz_protocol_alutech_at_4n_decrypt( + data, instance->alutech_at_4n_rainbow_table_file_name); + uint8_t crc = data >> 56; + if(crc == subghz_protocol_alutech_at_4n_decrypt_data_crc((uint8_t)((data >> 8) & 0xFF))) { + instance->generic.btn = (uint8_t)data & 0xFF; + instance->generic.cnt = (uint16_t)(data >> 8) & 0xFFFF; + instance->generic.serial = (uint32_t)(data >> 24) & 0xFFFFFFFF; + } + + if(instance->generic.cnt < 0xFFFF) { + instance->generic.cnt++; + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } + crc = subghz_protocol_alutech_at_4n_decrypt_data_crc((uint8_t)(instance->generic.cnt & 0xFF)); + data = (uint64_t)crc << 56 | (uint64_t)instance->generic.serial << 24 | + (uint32_t)instance->generic.cnt << 8 | instance->generic.btn; + + data = subghz_protocol_alutech_at_4n_encrypt( + data, instance->alutech_at_4n_rainbow_table_file_name); + crc = subghz_protocol_alutech_at_4n_crc(data); + instance->generic.data = subghz_protocol_blocks_reverse_key(data, 64); + instance->crc = subghz_protocol_blocks_reverse_key(crc, 8); + return true; +} + +bool subghz_protocol_alutech_at_4n_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + instance->generic.serial = serial; + instance->generic.cnt = cnt; + instance->generic.data_count_bit = 72; + bool res = subghz_protocol_alutech_at_4n_gen_data(instance, btn); + if(res) { + res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + } + return res; +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance + * @return true On success + */ +static bool subghz_protocol_encoder_alutech_at_4n_get_upload( + SubGhzProtocolEncoderAlutech_at_4n* instance, + uint8_t btn) { + furi_assert(instance); + + //gen new key + if(subghz_protocol_alutech_at_4n_gen_data(instance, btn)) { + //ToDo if you need to add a callback to automatically update the data on the display + } else { + return false; + } + + size_t index = 0; + // Send preambula + for(uint8_t i = 0; i < 12; ++i) { + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_alutech_at_4n_const.te_short); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_alutech_at_4n_const.te_short); // 0 + } + + instance->encoder.upload[index - 1].duration += + (uint32_t)subghz_protocol_alutech_at_4n_const.te_short * 9; + + // Send key data + for(uint8_t i = 64; i > 0; --i) { + if(bit_read(instance->generic.data, i - 1)) { + //1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_alutech_at_4n_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_alutech_at_4n_const.te_long); + } else { + //0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_alutech_at_4n_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_alutech_at_4n_const.te_short); + } + } + // Send crc + for(uint8_t i = 8; i > 0; --i) { + if(bit_read(instance->crc, i - 1)) { + //1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_alutech_at_4n_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_alutech_at_4n_const.te_long); + } else { + //0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_alutech_at_4n_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_alutech_at_4n_const.te_short); + } + } + // Inter-frame silence + instance->encoder.upload[index - 1].duration += + (uint32_t)subghz_protocol_alutech_at_4n_const.te_long * 20; + + size_t size_upload = index; + + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + return true; +} + +bool subghz_protocol_encoder_alutech_at_4n_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderAlutech_at_4n* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_alutech_at_4n_get_upload(instance, instance->generic.btn); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Key"); + break; + } + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_update_uint32(flipper_format, "CRC", &instance->crc, 1)) { + FURI_LOG_E(TAG, "Unable to add CRC"); + break; + } + + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void* subghz_protocol_decoder_alutech_at_4n_alloc(SubGhzEnvironment* environment) { + SubGhzProtocolDecoderAlutech_at_4n* instance = + malloc(sizeof(SubGhzProtocolDecoderAlutech_at_4n)); + instance->base.protocol = &subghz_protocol_alutech_at_4n; + instance->generic.protocol_name = instance->base.protocol->name; + instance->alutech_at_4n_rainbow_table_file_name = + subghz_environment_get_alutech_at_4n_rainbow_table_file_name(environment); + if(instance->alutech_at_4n_rainbow_table_file_name) { + FURI_LOG_I( + TAG, "Loading rainbow table from %s", instance->alutech_at_4n_rainbow_table_file_name); + } + return instance; +} + +void subghz_protocol_decoder_alutech_at_4n_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderAlutech_at_4n* instance = context; + instance->alutech_at_4n_rainbow_table_file_name = NULL; + free(instance); +} + +void subghz_protocol_decoder_alutech_at_4n_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderAlutech_at_4n* instance = context; + instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; +} + +void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderAlutech_at_4n* instance = context; + + switch(instance->decoder.parser_step) { + case Alutech_at_4nDecoderStepReset: + if((level) && DURATION_DIFF(duration, subghz_protocol_alutech_at_4n_const.te_short) < + subghz_protocol_alutech_at_4n_const.te_delta) { + instance->decoder.parser_step = Alutech_at_4nDecoderStepCheckPreambula; + instance->header_count++; + } + break; + case Alutech_at_4nDecoderStepCheckPreambula: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_alutech_at_4n_const.te_short) < + subghz_protocol_alutech_at_4n_const.te_delta)) { + instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; + break; + } + if((instance->header_count > 2) && + (DURATION_DIFF(duration, subghz_protocol_alutech_at_4n_const.te_short * 10) < + subghz_protocol_alutech_at_4n_const.te_delta * 10)) { + // Found header + instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; + instance->header_count = 0; + } + break; + case Alutech_at_4nDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = Alutech_at_4nDecoderStepCheckDuration; + } + break; + case Alutech_at_4nDecoderStepCheckDuration: + if(!level) { + if(duration >= ((uint32_t)subghz_protocol_alutech_at_4n_const.te_short * 2 + + subghz_protocol_alutech_at_4n_const.te_delta)) { + //add last bit + if(DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_alutech_at_4n_const.te_short) < + subghz_protocol_alutech_at_4n_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else if( + DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_alutech_at_4n_const.te_long) < + subghz_protocol_alutech_at_4n_const.te_delta * 2) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } + + // Found end TX + instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; + if(instance->decoder.decode_count_bit == + subghz_protocol_alutech_at_4n_const.min_count_bit_for_found) { + if(instance->generic.data != instance->data) { + instance->generic.data = instance->data; + + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + instance->crc = instance->decoder.decode_data; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.decode_data = 0; + instance->data = 0; + instance->decoder.decode_count_bit = 0; + instance->header_count = 0; + } + break; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_alutech_at_4n_const.te_short) < + subghz_protocol_alutech_at_4n_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_alutech_at_4n_const.te_long) < + subghz_protocol_alutech_at_4n_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + if(instance->decoder.decode_count_bit == 64) { + instance->data = instance->decoder.decode_data; + instance->decoder.decode_data = 0; + } + instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_alutech_at_4n_const.te_long) < + subghz_protocol_alutech_at_4n_const.te_delta * 2) && + (DURATION_DIFF(duration, subghz_protocol_alutech_at_4n_const.te_short) < + subghz_protocol_alutech_at_4n_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + if(instance->decoder.decode_count_bit == 64) { + instance->data = instance->decoder.decode_data; + instance->decoder.decode_data = 0; + } + instance->decoder.parser_step = Alutech_at_4nDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; + instance->header_count = 0; + } + } else { + instance->decoder.parser_step = Alutech_at_4nDecoderStepReset; + instance->header_count = 0; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + * @param file_name Full path to rainbow table the file + */ +static void subghz_protocol_alutech_at_4n_remote_controller( + SubGhzBlockGeneric* instance, + uint8_t crc, + const char* file_name) { + /** + * Message format 72bit LSB first + * data crc + * XXXXXXXXXXXXXXXX CC + * + * For analysis, you need to turn the package MSB + * in decoded messages format + * + * crc1 serial cnt key + * cc SSSSSSSS XXxx BB + * + * crc1 is calculated from the lower part of cnt + * key 1=0xff, 2=0x11, 3=0x22, 4=0x33, 5=0x44 + * + */ + + bool status = false; + uint64_t data = subghz_protocol_blocks_reverse_key(instance->data, 64); + crc = subghz_protocol_blocks_reverse_key(crc, 8); + + if(crc == subghz_protocol_alutech_at_4n_crc(data)) { + data = subghz_protocol_alutech_at_4n_decrypt(data, file_name); + status = true; + } + + if(status && ((uint8_t)(data >> 56) == + subghz_protocol_alutech_at_4n_decrypt_data_crc((uint8_t)((data >> 8) & 0xFF)))) { + instance->btn = (uint8_t)data & 0xFF; + instance->cnt = (uint16_t)(data >> 8) & 0xFFFF; + instance->serial = (uint32_t)(data >> 24) & 0xFFFFFFFF; + } + + if(!status) { + instance->btn = 0; + instance->cnt = 0; + instance->serial = 0; + } +} + +uint8_t subghz_protocol_decoder_alutech_at_4n_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderAlutech_at_4n* instance = context; + return (uint8_t)instance->crc; +} + +bool subghz_protocol_decoder_alutech_at_4n_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderAlutech_at_4n* instance = context; + bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + if(res && !flipper_format_write_uint32(flipper_format, "CRC", &instance->crc, 1)) { + FURI_LOG_E(TAG, "Unable to add CRC"); + res = false; + } + return res; + + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_alutech_at_4n_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderAlutech_at_4n* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_alutech_at_4n_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_uint32(flipper_format, "CRC", (uint32_t*)&instance->crc, 1)) { + FURI_LOG_E(TAG, "Missing CRC"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderAlutech_at_4n* instance = context; + subghz_protocol_alutech_at_4n_remote_controller( + &instance->generic, instance->crc, instance->alutech_at_4n_rainbow_table_file_name); + uint32_t code_found_hi = instance->generic.data >> 32; + uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; + + furi_string_cat_printf( + output, + "%s %d\r\n" + "Key:0x%08lX%08lX%02X\r\n" + "Sn:0x%08lX Btn:0x%01X\r\n" + "Cnt:0x%03lX\r\n", + + instance->generic.protocol_name, + instance->generic.data_count_bit, + code_found_hi, + code_found_lo, + (uint8_t)instance->crc, + instance->generic.serial, + instance->generic.btn, + instance->generic.cnt); +} \ No newline at end of file diff --git a/lib/subghz/protocols/alutech_at_4n.h b/lib/subghz/protocols/alutech_at_4n.h new file mode 100644 index 000000000..b6d51439b --- /dev/null +++ b/lib/subghz/protocols/alutech_at_4n.h @@ -0,0 +1,128 @@ +#pragma once +#include "base.h" + +#define SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME "Alutech at-4n" + +typedef struct SubGhzProtocolDecoderAlutech_at_4n SubGhzProtocolDecoderAlutech_at_4n; +typedef struct SubGhzProtocolEncoderAlutech_at_4n SubGhzProtocolEncoderAlutech_at_4n; + +extern const SubGhzProtocolDecoder subghz_protocol_alutech_at_4n_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_alutech_at_4n_encoder; +extern const SubGhzProtocol subghz_protocol_alutech_at_4n; + +/** + * Allocate SubGhzProtocolEncoderAlutech_at_4n. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderAlutech_at_4n* pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + */ +void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderAlutech_at_4n. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + */ +void subghz_protocol_encoder_alutech_at_4n_free(void* context); + +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 24 bit + * @param btn Button number, 8 bit + * @param cnt Counter value, 16 bit + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_alutech_at_4n_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_alutech_at_4n_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + */ +void subghz_protocol_encoder_alutech_at_4n_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderAlutech_at_4n instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_alutech_at_4n_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderAlutech_at_4n. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderAlutech_at_4n* pointer to a SubGhzProtocolDecoderAlutech_at_4n instance + */ +void* subghz_protocol_decoder_alutech_at_4n_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderAlutech_at_4n. + * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance + */ +void subghz_protocol_decoder_alutech_at_4n_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderAlutech_at_4n. + * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance + */ +void subghz_protocol_decoder_alutech_at_4n_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_alutech_at_4n_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_alutech_at_4n_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderAlutech_at_4n. + * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_decoder_alutech_at_4n_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderAlutech_at_4n. + * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_alutech_at_4n_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance + * @param output Resulting text + */ +void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* output); \ No newline at end of file diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c new file mode 100644 index 000000000..67e0467ee --- /dev/null +++ b/lib/subghz/protocols/bin_raw.c @@ -0,0 +1,1120 @@ +#include "bin_raw.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" +#include +#include +#include + +#define TAG "SubGhzProtocolBinRAW" + +//change very carefully, RAM ends at the most inopportune moment +#define BIN_RAW_BUF_RAW_SIZE 2048 +#define BIN_RAW_BUF_DATA_SIZE 512 + +#define BIN_RAW_THRESHOLD_RSSI -85.0f +#define BIN_RAW_DELTA_RSSI 7.0f +#define BIN_RAW_SEARCH_CLASSES 20 +#define BIN_RAW_TE_MIN_COUNT 40 +#define BIN_RAW_BUF_MIN_DATA_COUNT 128 +#define BIN_RAW_MAX_MARKUP_COUNT 20 + +//#define BIN_RAW_DEBUG + +#ifdef BIN_RAW_DEBUG +#define bin_raw_debug(...) FURI_LOG_RAW_D(__VA_ARGS__) +#define bin_raw_debug_tag(tag, ...) \ + FURI_LOG_RAW_D("\033[0;32m[" tag "]\033[0m "); \ + FURI_LOG_RAW_D(__VA_ARGS__) +#else +#define bin_raw_debug(...) +#define bin_raw_debug_tag(...) +#endif + +static const SubGhzBlockConst subghz_protocol_bin_raw_const = { + .te_short = 30, + .te_long = 65000, + .te_delta = 0, + .min_count_bit_for_found = 0, +}; + +typedef enum { + BinRAWDecoderStepReset = 0, + BinRAWDecoderStepWrite, + BinRAWDecoderStepBufFull, + BinRAWDecoderStepNoParse, +} BinRAWDecoderStep; + +typedef enum { + BinRAWTypeUnknown = 0, + BinRAWTypeNoGap, + BinRAWTypeGap, + BinRAWTypeGapRecurring, + BinRAWTypeGapRolling, + BinRAWTypeGapUnknown, +} BinRAWType; + +struct BinRAW_Markup { + uint16_t byte_bias; + uint16_t bit_count; +}; +typedef struct BinRAW_Markup BinRAW_Markup; + +struct SubGhzProtocolDecoderBinRAW { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + int32_t* data_raw; + uint8_t* data; + BinRAW_Markup data_markup[BIN_RAW_MAX_MARKUP_COUNT]; + size_t data_raw_ind; + uint32_t te; + float adaptive_threshold_rssi; +}; + +struct SubGhzProtocolEncoderBinRAW { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; + + uint8_t* data; + BinRAW_Markup data_markup[BIN_RAW_MAX_MARKUP_COUNT]; + uint32_t te; +}; + +const SubGhzProtocolDecoder subghz_protocol_bin_raw_decoder = { + .alloc = subghz_protocol_decoder_bin_raw_alloc, + .free = subghz_protocol_decoder_bin_raw_free, + + .feed = subghz_protocol_decoder_bin_raw_feed, + .reset = subghz_protocol_decoder_bin_raw_reset, + + .get_hash_data = subghz_protocol_decoder_bin_raw_get_hash_data, + .serialize = subghz_protocol_decoder_bin_raw_serialize, + .deserialize = subghz_protocol_decoder_bin_raw_deserialize, + .get_string = subghz_protocol_decoder_bin_raw_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_bin_raw_encoder = { + .alloc = subghz_protocol_encoder_bin_raw_alloc, + .free = subghz_protocol_encoder_bin_raw_free, + + .deserialize = subghz_protocol_encoder_bin_raw_deserialize, + .stop = subghz_protocol_encoder_bin_raw_stop, + .yield = subghz_protocol_encoder_bin_raw_yield, +}; + +const SubGhzProtocol subghz_protocol_bin_raw = { + .name = SUBGHZ_PROTOCOL_BIN_RAW_NAME, + .type = SubGhzProtocolTypeBinRAW, +#ifdef BIN_RAW_DEBUG + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, +#else + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_BinRAW | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, +#endif + .decoder = &subghz_protocol_bin_raw_decoder, + .encoder = &subghz_protocol_bin_raw_encoder, +}; + +static uint16_t subghz_protocol_bin_raw_get_full_byte(uint16_t bit_count) { + if(bit_count & 0x7) { + return (bit_count >> 3) + 1; + } else { + return (bit_count >> 3); + } +} + +void* subghz_protocol_encoder_bin_raw_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderBinRAW* instance = malloc(sizeof(SubGhzProtocolEncoderBinRAW)); + + instance->base.protocol = &subghz_protocol_bin_raw; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = BIN_RAW_BUF_DATA_SIZE * 5; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->data = malloc(instance->encoder.size_upload * sizeof(uint8_t)); + memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_bin_raw_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderBinRAW* instance = context; + free(instance->encoder.upload); + free(instance->data); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderBinRAW instance + * @return true On success + */ +static bool subghz_protocol_encoder_bin_raw_get_upload(SubGhzProtocolEncoderBinRAW* instance) { + furi_assert(instance); + + //we glue all the pieces of the package into 1 long sequence with left alignment, + //in the uploaded data we have right alignment. + + bin_raw_debug_tag(TAG, "Recovery of offset bits in sequences\r\n"); + uint16_t i = 0; + uint16_t ind = 0; + bin_raw_debug("\tind byte_bias\tbit_count\tbit_bias\r\n"); + while((i < BIN_RAW_MAX_MARKUP_COUNT) && (instance->data_markup[i].bit_count != 0)) { + uint8_t bit_bias = + subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count) * 8 - + instance->data_markup[i].bit_count; + bin_raw_debug( + "\t%d\t%d\t%d :\t\t%d\r\n", + i, + instance->data_markup[i].byte_bias, + instance->data_markup[i].bit_count, + bit_bias); + for(uint16_t y = instance->data_markup[i].byte_bias * 8; + y < instance->data_markup[i].byte_bias * 8 + + subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count) * 8 - + bit_bias; + y++) { + subghz_protocol_blocks_set_bit_array( + subghz_protocol_blocks_get_bit_array(instance->data, y + bit_bias), + instance->data, + ind++, + BIN_RAW_BUF_DATA_SIZE); + } + i++; + } + bin_raw_debug("\r\n"); +#ifdef BIN_RAW_DEBUG + bin_raw_debug_tag(TAG, "Restored Sequence left aligned\r\n"); + for(uint16_t y = 0; y < subghz_protocol_bin_raw_get_full_byte(ind); y++) { + bin_raw_debug("%02X ", instance->data[y]); + } + bin_raw_debug("\r\n\tbin_count_result= %d\r\n\r\n", ind); + + bin_raw_debug_tag( + TAG, "Maximum levels encoded in upload %zu\r\n", instance->encoder.size_upload); +#endif + instance->encoder.size_upload = subghz_protocol_blocks_get_upload_from_bit_array( + instance->data, + ind, + instance->encoder.upload, + instance->encoder.size_upload, + instance->te, + SubGhzProtocolBlockAlignBitLeft); + + bin_raw_debug_tag(TAG, "The result %zu is levels\r\n", instance->encoder.size_upload); + bin_raw_debug_tag(TAG, "Remaining free memory %zu\r\n", memmgr_get_free_heap()); + return true; +} + +bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderBinRAW* instance = context; + + bool res = false; + uint32_t temp_data = 0; + + do { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) { + FURI_LOG_E(TAG, "Missing Bit"); + break; + } + + instance->generic.data_count_bit = (uint16_t)temp_data; + + if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { + FURI_LOG_E(TAG, "Missing TE"); + break; + } + + temp_data = 0; + uint16_t ind = 0; + uint16_t byte_bias = 0; + uint16_t byte_count = 0; + memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + while(flipper_format_read_uint32(flipper_format, "Bit_RAW", (uint32_t*)&temp_data, 1)) { + if(ind >= BIN_RAW_MAX_MARKUP_COUNT) { + FURI_LOG_E(TAG, "Markup overflow"); + break; + } + byte_count += subghz_protocol_bin_raw_get_full_byte(temp_data); + if(byte_count > BIN_RAW_BUF_DATA_SIZE) { + FURI_LOG_E(TAG, "Receive buffer overflow"); + break; + } + + instance->data_markup[ind].bit_count = temp_data; + instance->data_markup[ind].byte_bias = byte_bias; + byte_bias += subghz_protocol_bin_raw_get_full_byte(temp_data); + + if(!flipper_format_read_hex( + flipper_format, + "Data_RAW", + instance->data + instance->data_markup[ind].byte_bias, + subghz_protocol_bin_raw_get_full_byte(temp_data))) { + instance->data_markup[ind].bit_count = 0; + FURI_LOG_E(TAG, "Missing Data_RAW"); + break; + } + ind++; + } + +#ifdef BIN_RAW_DEBUG + uint16_t i = 0; + bin_raw_debug_tag(TAG, "Download data to encoder\r\n"); + bin_raw_debug("\tind byte_bias\tbit_count\t\tbin_data"); + while((i < BIN_RAW_MAX_MARKUP_COUNT) && (instance->data_markup[i].bit_count != 0)) { + bin_raw_debug( + "\r\n\t%d\t%d\t%d :\t", + i, + instance->data_markup[i].byte_bias, + instance->data_markup[i].bit_count); + for(uint16_t y = instance->data_markup[i].byte_bias; + y < instance->data_markup[i].byte_bias + + subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count); + y++) { + bin_raw_debug("%02X ", instance->data[y]); + } + i++; + } + bin_raw_debug("\r\n\r\n"); +#endif + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!subghz_protocol_encoder_bin_raw_get_upload(instance)) break; + instance->encoder.is_running = true; + + res = true; + } while(0); + + return res; +} + +void subghz_protocol_encoder_bin_raw_stop(void* context) { + SubGhzProtocolEncoderBinRAW* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_bin_raw_yield(void* context) { + SubGhzProtocolEncoderBinRAW* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_bin_raw_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderBinRAW* instance = malloc(sizeof(SubGhzProtocolDecoderBinRAW)); + instance->base.protocol = &subghz_protocol_bin_raw; + instance->generic.protocol_name = instance->base.protocol->name; + instance->data_raw_ind = 0; + instance->data_raw = malloc(BIN_RAW_BUF_RAW_SIZE * sizeof(int32_t)); + instance->data = malloc(BIN_RAW_BUF_RAW_SIZE * sizeof(uint8_t)); + memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + instance->adaptive_threshold_rssi = BIN_RAW_THRESHOLD_RSSI; + return instance; +} + +void subghz_protocol_decoder_bin_raw_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBinRAW* instance = context; + free(instance->data_raw); + free(instance->data); + free(instance); +} + +void subghz_protocol_decoder_bin_raw_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBinRAW* instance = context; +#ifdef BIN_RAW_DEBUG + UNUSED(instance); +#else + instance->decoder.parser_step = BinRAWDecoderStepNoParse; + instance->data_raw_ind = 0; +#endif +} + +void subghz_protocol_decoder_bin_raw_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderBinRAW* instance = context; + + if(instance->decoder.parser_step == BinRAWDecoderStepWrite) { + if(instance->data_raw_ind == BIN_RAW_BUF_RAW_SIZE) { + instance->decoder.parser_step = BinRAWDecoderStepBufFull; + } else { + instance->data_raw[instance->data_raw_ind++] = (level ? duration : -duration); + } + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzProtocolDecoderBinRAW* instance + */ +static bool + subghz_protocol_bin_raw_check_remote_controller(SubGhzProtocolDecoderBinRAW* instance) { + struct { + float data; + uint16_t count; + } classes[BIN_RAW_SEARCH_CLASSES]; + + size_t ind = 0; + + memset(classes, 0x00, sizeof(classes)); + + uint16_t data_markup_ind = 0; + memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + + if(instance->data_raw_ind < 512) { + ind = + instance->data_raw_ind - + 100; //there is usually garbage at the end of the record, we exclude it from the classification + } else { + ind = 512; + } + + //sort the durations to find the shortest correlated interval + for(size_t i = 0; i < ind; i++) { + for(size_t k = 0; k < BIN_RAW_SEARCH_CLASSES; k++) { + if(classes[k].count == 0) { + classes[k].data = (float)(abs(instance->data_raw[i])); + classes[k].count++; + break; + } else if( + DURATION_DIFF((float)(abs(instance->data_raw[i])), (classes[k].data)) < + (classes[k].data / 4)) { //if the test value does not differ by more than 25% + classes[k].data += ((float)(abs(instance->data_raw[i])) - classes[k].data) * + 0.05f; //running average k=0.05 + classes[k].count++; + break; + } + } + } + + // if(classes[BIN_RAW_SEARCH_CLASSES - 1].count != 0) { + // //filling the classifier, it means that they received an unclean signal + // return false; + // } + + //looking for the minimum te with an occurrence greater than BIN_RAW_TE_MIN_COUNT + instance->te = subghz_protocol_bin_raw_const.te_long * 2; + + bool te_ok = false; + uint16_t gap_ind = 0; + uint16_t gap_delta = 0; + uint32_t gap = 0; + int data_temp = 0; + BinRAWType bin_raw_type = BinRAWTypeUnknown; + + //sort by number of occurrences + bool swap = true; + while(swap) { + swap = false; + for(size_t i = 1; i < BIN_RAW_SEARCH_CLASSES; i++) { + if(classes[i].count > classes[i - 1].count) { + uint32_t data = classes[i - 1].data; + uint32_t count = classes[i - 1].count; + classes[i - 1].data = classes[i].data; + classes[i - 1].count = classes[i].count; + classes[i].data = data; + classes[i].count = count; + swap = true; + } + } + } +#ifdef BIN_RAW_DEBUG + bin_raw_debug_tag(TAG, "Sorted durations\r\n"); + bin_raw_debug("\t\tind\tcount\tus\r\n"); + for(size_t k = 0; k < BIN_RAW_SEARCH_CLASSES; k++) { + bin_raw_debug("\t\t%zu\t%u\t%lu\r\n", k, classes[k].count, (uint32_t)classes[k].data); + } + bin_raw_debug("\r\n"); +#endif + if((classes[0].count > BIN_RAW_TE_MIN_COUNT) && (classes[1].count == 0)) { + //adopted only the preamble + instance->te = (uint32_t)classes[0].data; + te_ok = true; + gap = 0; //gap no + } else { + //take the 2 most common durations + //check that there are enough + if((classes[0].count < BIN_RAW_TE_MIN_COUNT) || + (classes[1].count < (BIN_RAW_TE_MIN_COUNT >> 1))) + return false; + //arrange the first 2 date values in ascending order + if(classes[0].data > classes[1].data) { + uint32_t data = classes[1].data; + classes[0].data = classes[1].data; + classes[1].data = data; + } + + //determine the value to be corrected + for(uint8_t k = 1; k < 5; k++) { + float delta = (classes[1].data / (classes[0].data / k)); + bin_raw_debug_tag(TAG, "K_div= %f\r\n", (double)(delta)); + delta -= (uint32_t)delta; + + if((delta < 0.20f) || (delta > 0.80f)) { + instance->te = (uint32_t)classes[0].data / k; + bin_raw_debug_tag(TAG, "K= %d\r\n", k); + te_ok = true; //found a correlated duration + break; + } + } + if(!te_ok) { + //did not find the minimum TE satisfying the condition + return false; + } + bin_raw_debug_tag(TAG, "TE= %lu\r\n\r\n", instance->te); + + //looking for a gap + for(size_t k = 2; k < BIN_RAW_SEARCH_CLASSES; k++) { + if((classes[k].count > 2) && (classes[k].data > gap)) { + gap = (uint32_t)classes[k].data; + gap_delta = gap / 5; //calculate 20% deviation from ideal value + } + } + + if((gap / instance->te) < + 10) { //make an assumption, the longest gap should be more than 10 TE + gap = 0; //check that our signal has a gap greater than 10*TE + bin_raw_type = BinRAWTypeNoGap; + } else { + bin_raw_type = BinRAWTypeGap; + //looking for the last occurrence of gap + ind = instance->data_raw_ind - 1; + while((ind > 0) && (DURATION_DIFF(abs(instance->data_raw[ind]), gap) > gap_delta)) { + ind--; + } + gap_ind = ind; + } + } + + //if we consider that there is a gap, then we divide the signal with respect to this gap + //processing input data from the end + if(bin_raw_type == BinRAWTypeGap) { + bin_raw_debug_tag(TAG, "Tinted sequence\r\n"); + ind = (BIN_RAW_BUF_DATA_SIZE * 8); + uint16_t bit_count = 0; + do { + gap_ind--; + data_temp = (int)(round((float)(instance->data_raw[gap_ind]) / instance->te)); + bin_raw_debug("%d ", data_temp); + if(data_temp == 0) bit_count++; //there is noise in the package + for(size_t i = 0; i < abs(data_temp); i++) { + bit_count++; + if(ind) { + ind--; + } else { + break; + } + if(data_temp > 0) { + subghz_protocol_blocks_set_bit_array( + true, instance->data, ind, BIN_RAW_BUF_DATA_SIZE); + } else { + subghz_protocol_blocks_set_bit_array( + false, instance->data, ind, BIN_RAW_BUF_DATA_SIZE); + } + } + //split into full bytes if gap is caught + if(DURATION_DIFF(abs(instance->data_raw[gap_ind]), gap) < gap_delta) { + instance->data_markup[data_markup_ind].byte_bias = ind >> 3; + instance->data_markup[data_markup_ind++].bit_count = bit_count; + bit_count = 0; + + if(data_markup_ind == BIN_RAW_MAX_MARKUP_COUNT) break; + ind &= 0xFFFFFFF8; //jump to the pre whole byte + } + } while(gap_ind != 0); + if((data_markup_ind != BIN_RAW_MAX_MARKUP_COUNT) && (ind != 0)) { + instance->data_markup[data_markup_ind].byte_bias = ind >> 3; + instance->data_markup[data_markup_ind++].bit_count = bit_count; + } + + bin_raw_debug("\r\n\t count bit= %zu\r\n\r\n", (BIN_RAW_BUF_DATA_SIZE * 8) - ind); + + //reset the classifier and classify the received data + memset(classes, 0x00, sizeof(classes)); + + bin_raw_debug_tag(TAG, "Sort the found pieces by the number of bits in them\r\n"); + for(size_t i = 0; i < data_markup_ind; i++) { + for(size_t k = 0; k < BIN_RAW_SEARCH_CLASSES; k++) { + if(classes[k].count == 0) { + classes[k].data = instance->data_markup[i].bit_count; + classes[k].count++; + break; + } else if(instance->data_markup[i].bit_count == (uint16_t)classes[k].data) { + classes[k].count++; + break; + } + } + } + +#ifdef BIN_RAW_DEBUG + bin_raw_debug("\t\tind\tcount\tus\r\n"); + for(size_t k = 0; k < BIN_RAW_SEARCH_CLASSES; k++) { + bin_raw_debug("\t\t%zu\t%u\t%lu\r\n", k, classes[k].count, (uint32_t)classes[k].data); + } + bin_raw_debug("\r\n"); +#endif + + //choose the value with the maximum repetition + data_temp = 0; + for(size_t i = 0; i < BIN_RAW_SEARCH_CLASSES; i++) { + if((classes[i].count > 1) && (data_temp < classes[i].count)) + data_temp = (int)classes[i].data; + } + + //if(data_markup_ind == 0) return false; + +#ifdef BIN_RAW_DEBUG + //output in reverse order + bin_raw_debug_tag(TAG, "Found sequences\r\n"); + bin_raw_debug("\tind byte_bias\tbit_count\t\tbin_data\r\n"); + uint16_t data_markup_ind_temp = data_markup_ind; + if(data_markup_ind) { + data_markup_ind_temp--; + for(size_t i = (ind / 8); i < BIN_RAW_BUF_DATA_SIZE; i++) { + if(instance->data_markup[data_markup_ind_temp].byte_bias == i) { + bin_raw_debug( + "\r\n\t%d\t%d\t%d :\t", + data_markup_ind_temp, + instance->data_markup[data_markup_ind_temp].byte_bias, + instance->data_markup[data_markup_ind_temp].bit_count); + if(data_markup_ind_temp != 0) data_markup_ind_temp--; + } + bin_raw_debug("%02X ", instance->data[i]); + } + bin_raw_debug("\r\n\r\n"); + } + //compare data in chunks with the same number of bits + bin_raw_debug_tag(TAG, "Analyze sequences of long %d bit\r\n\r\n", data_temp); +#endif + + //if(data_temp == 0) data_temp = (int)classes[0].data; + + if(data_temp != 0) { + //check that data in transmission is repeated every packet + for(uint16_t i = 0; i < data_markup_ind - 1; i++) { + if((instance->data_markup[i].bit_count == data_temp) && + (instance->data_markup[i + 1].bit_count == data_temp)) { + //if the number of bits in adjacent parcels is the same, compare the data + bin_raw_debug_tag( + TAG, + "Comparison of neighboring sequences ind_1=%d ind_2=%d %02X=%02X .... %02X=%02X\r\n", + i, + i + 1, + instance->data[instance->data_markup[i].byte_bias], + instance->data[instance->data_markup[i + 1].byte_bias], + instance->data + [instance->data_markup[i].byte_bias + + subghz_protocol_bin_raw_get_full_byte( + instance->data_markup[i].bit_count) - + 1], + instance->data + [instance->data_markup[i + 1].byte_bias + + subghz_protocol_bin_raw_get_full_byte( + instance->data_markup[i + 1].bit_count) - + 1]); + + uint16_t byte_count = + subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count); + if(memcmp( + instance->data + instance->data_markup[i].byte_bias, + instance->data + instance->data_markup[i + 1].byte_bias, + byte_count - 1) == 0) { + bin_raw_debug_tag( + TAG, "Match found bin_raw_type=BinRAWTypeGapRecurring\r\n\r\n"); + + //place in 1 element the offset to valid data + instance->data_markup[0].bit_count = instance->data_markup[i].bit_count; + instance->data_markup[0].byte_bias = instance->data_markup[i].byte_bias; + //markup end sign + instance->data_markup[1].bit_count = 0; + instance->data_markup[1].byte_bias = 0; + + bin_raw_type = BinRAWTypeGapRecurring; + i = data_markup_ind; + break; + } + } + } + } + + if(bin_raw_type == BinRAWTypeGap) { + // check that retry occurs every n packets + for(uint16_t i = 0; i < data_markup_ind - 2; i++) { + uint16_t byte_count = + subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count); + for(uint16_t y = i + 1; y < data_markup_ind - 1; y++) { + bin_raw_debug_tag( + TAG, + "Comparison every N sequences ind_1=%d ind_2=%d %02X=%02X .... %02X=%02X\r\n", + i, + y, + instance->data[instance->data_markup[i].byte_bias], + instance->data[instance->data_markup[y].byte_bias], + instance->data + [instance->data_markup[i].byte_bias + + subghz_protocol_bin_raw_get_full_byte( + instance->data_markup[i].bit_count) - + 1], + instance->data + [instance->data_markup[y].byte_bias + + subghz_protocol_bin_raw_get_full_byte( + instance->data_markup[y].bit_count) - + 1]); + + if(byte_count == + subghz_protocol_bin_raw_get_full_byte( + instance->data_markup[y].bit_count)) { //if the length in bytes matches + + if((memcmp( + instance->data + instance->data_markup[i].byte_bias, + instance->data + instance->data_markup[y].byte_bias, + byte_count - 1) == 0) && + (memcmp( + instance->data + instance->data_markup[i + 1].byte_bias, + instance->data + instance->data_markup[y + 1].byte_bias, + byte_count - 1) == 0)) { + uint8_t index = 0; +#ifdef BIN_RAW_DEBUG + bin_raw_debug_tag( + TAG, "Match found bin_raw_type=BinRAWTypeGapRolling\r\n\r\n"); + //output in reverse order + bin_raw_debug("\tind byte_bias\tbit_count\t\tbin_data\r\n"); + index = y - 1; + for(size_t z = instance->data_markup[y].byte_bias + byte_count; + z < instance->data_markup[i].byte_bias + byte_count; + z++) { + if(instance->data_markup[index].byte_bias == z) { + bin_raw_debug( + "\r\n\t%d\t%d\t%d :\t", + index, + instance->data_markup[index].byte_bias, + instance->data_markup[index].bit_count); + if(index != 0) index--; + } + bin_raw_debug("%02X ", instance->data[z]); + } + + bin_raw_debug("\r\n\r\n"); +#endif + //todo can be optimized + BinRAW_Markup markup_temp[BIN_RAW_MAX_MARKUP_COUNT]; + memcpy( + markup_temp, + instance->data_markup, + BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + memset( + instance->data_markup, + 0x00, + BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + + for(index = i; index < y; index++) { + instance->data_markup[index - i].bit_count = + markup_temp[y - index - 1].bit_count; + instance->data_markup[index - i].byte_bias = + markup_temp[y - index - 1].byte_bias; + } + + bin_raw_type = BinRAWTypeGapRolling; + i = data_markup_ind; + break; + } + } + } + } + } + //todo can be optimized + if(bin_raw_type == BinRAWTypeGap) { + if(data_temp != 0) { //there are sequences with the same number of bits + + BinRAW_Markup markup_temp[BIN_RAW_MAX_MARKUP_COUNT]; + memcpy( + markup_temp, + instance->data_markup, + BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + memset( + instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + uint16_t byte_count = subghz_protocol_bin_raw_get_full_byte(data_temp); + uint16_t index = 0; + uint16_t it = BIN_RAW_MAX_MARKUP_COUNT; + do { + it--; + if(subghz_protocol_bin_raw_get_full_byte(markup_temp[it].bit_count) == + byte_count) { + instance->data_markup[index].bit_count = markup_temp[it].bit_count; + instance->data_markup[index].byte_bias = markup_temp[it].byte_bias; + index++; + bin_raw_type = BinRAWTypeGapUnknown; + } + } while(it != 0); + } + } + + if(bin_raw_type != BinRAWTypeGap) + return true; + else + return false; + + } else { + // if bin_raw_type == BinRAWTypeGap + bin_raw_debug_tag(TAG, "Sequence analysis without gap\r\n"); + ind = 0; + for(size_t i = 0; i < instance->data_raw_ind; i++) { + int data_temp = (int)(round((float)(instance->data_raw[i]) / instance->te)); + if(data_temp == 0) break; //found an interval 2 times shorter than TE, this is noise + bin_raw_debug("%d ", data_temp); + + for(size_t k = 0; k < abs(data_temp); k++) { + if(data_temp > 0) { + subghz_protocol_blocks_set_bit_array( + true, instance->data, ind++, BIN_RAW_BUF_DATA_SIZE); + } else { + subghz_protocol_blocks_set_bit_array( + false, instance->data, ind++, BIN_RAW_BUF_DATA_SIZE); + } + if(ind == BIN_RAW_BUF_DATA_SIZE * 8) { + i = instance->data_raw_ind; + break; + } + } + } + + if(ind != 0) { + bin_raw_type = BinRAWTypeNoGap; + //right alignment + uint8_t bit_bias = (subghz_protocol_bin_raw_get_full_byte(ind) << 3) - ind; +#ifdef BIN_RAW_DEBUG + bin_raw_debug( + "\r\n\t count bit= %zu\tcount full byte= %d\tbias bit= %d\r\n\r\n", + ind, + subghz_protocol_bin_raw_get_full_byte(ind), + bit_bias); + + for(size_t i = 0; i < subghz_protocol_bin_raw_get_full_byte(ind); i++) { + bin_raw_debug("%02X ", instance->data[i]); + } + bin_raw_debug("\r\n\r\n"); +#endif + //checking that the received sequence contains useful data + bool data_check = false; + for(size_t i = 0; i < subghz_protocol_bin_raw_get_full_byte(ind); i++) { + if(instance->data[i] != 0) { + data_check = true; + break; + } + } + + if(data_check) { + for(size_t i = subghz_protocol_bin_raw_get_full_byte(ind) - 1; i > 0; i--) { + instance->data[i] = (instance->data[i - 1] << (8 - bit_bias)) | + (instance->data[i] >> bit_bias); + } + instance->data[0] = (instance->data[0] >> bit_bias); + +#ifdef BIN_RAW_DEBUG + bin_raw_debug_tag(TAG, "Data right alignment\r\n"); + for(size_t i = 0; i < subghz_protocol_bin_raw_get_full_byte(ind); i++) { + bin_raw_debug("%02X ", instance->data[i]); + } + bin_raw_debug("\r\n\r\n"); +#endif + instance->data_markup[0].bit_count = ind; + instance->data_markup[0].byte_bias = 0; + + return true; + } else { + return false; + } + } else { + return false; + } + } + return false; +} + +void subghz_protocol_decoder_bin_raw_data_input_rssi( + SubGhzProtocolDecoderBinRAW* instance, + float rssi) { + furi_assert(instance); + switch(instance->decoder.parser_step) { + case BinRAWDecoderStepReset: + + bin_raw_debug("%ld %ld :", (int32_t)rssi, (int32_t)instance->adaptive_threshold_rssi); + if(rssi > (instance->adaptive_threshold_rssi + BIN_RAW_DELTA_RSSI)) { + instance->data_raw_ind = 0; + memset(instance->data_raw, 0x00, BIN_RAW_BUF_RAW_SIZE * sizeof(int32_t)); + memset(instance->data, 0x00, BIN_RAW_BUF_RAW_SIZE * sizeof(uint8_t)); + instance->decoder.parser_step = BinRAWDecoderStepWrite; + bin_raw_debug_tag(TAG, "RSSI\r\n"); + } else { + //adaptive noise level adjustment + instance->adaptive_threshold_rssi += (rssi - instance->adaptive_threshold_rssi) * 0.2f; + } + break; + + case BinRAWDecoderStepBufFull: + case BinRAWDecoderStepWrite: +#ifdef BIN_RAW_DEBUG + if(rssi > (instance->adaptive_threshold_rssi + BIN_RAW_DELTA_RSSI)) { + bin_raw_debug("\033[0;32m%ld \033[0m ", (int32_t)rssi); + } else { + bin_raw_debug("%ld ", (int32_t)rssi); + } +#endif + if(rssi < instance->adaptive_threshold_rssi + BIN_RAW_DELTA_RSSI) { +#ifdef BIN_RAW_DEBUG + bin_raw_debug("\r\n\r\n"); + bin_raw_debug_tag(TAG, "Data for analysis, positive high, negative low, us\r\n"); + for(size_t i = 0; i < instance->data_raw_ind; i++) { + bin_raw_debug("%ld ", instance->data_raw[i]); + } + bin_raw_debug("\r\n\t count data= %zu\r\n\r\n", instance->data_raw_ind); +#endif + instance->decoder.parser_step = BinRAWDecoderStepReset; + instance->generic.data_count_bit = 0; + if(instance->data_raw_ind >= BIN_RAW_BUF_MIN_DATA_COUNT) { + if(subghz_protocol_bin_raw_check_remote_controller(instance)) { + bin_raw_debug_tag(TAG, "Sequence found\r\n"); + bin_raw_debug("\tind byte_bias\tbit_count\t\tbin_data"); + uint16_t i = 0; + while((i < BIN_RAW_MAX_MARKUP_COUNT) && + (instance->data_markup[i].bit_count != 0)) { + instance->generic.data_count_bit += instance->data_markup[i].bit_count; +#ifdef BIN_RAW_DEBUG + bin_raw_debug( + "\r\n\t%d\t%d\t%d :\t", + i, + instance->data_markup[i].byte_bias, + instance->data_markup[i].bit_count); + for(uint16_t y = instance->data_markup[i].byte_bias; + y < instance->data_markup[i].byte_bias + + subghz_protocol_bin_raw_get_full_byte( + instance->data_markup[i].bit_count); + y++) { + bin_raw_debug("%02X ", instance->data[y]); + } +#endif + i++; + } + bin_raw_debug("\r\n"); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + } + } + break; + + default: + //if instance->decoder.parser_step == BinRAWDecoderStepNoParse or others, restore the initial state + if(rssi < instance->adaptive_threshold_rssi + BIN_RAW_DELTA_RSSI) { + instance->decoder.parser_step = BinRAWDecoderStepReset; + } + break; + } +} + +uint8_t subghz_protocol_decoder_bin_raw_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderBinRAW* instance = context; + return subghz_protocol_blocks_add_bytes( + instance->data + instance->data_markup[0].byte_bias, + subghz_protocol_bin_raw_get_full_byte(instance->data_markup[0].bit_count)); +} + +bool subghz_protocol_decoder_bin_raw_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderBinRAW* instance = context; + + bool res = false; + FuriString* temp_str; + temp_str = furi_string_alloc(); + do { + stream_clean(flipper_format_get_raw_stream(flipper_format)); + if(!flipper_format_write_header_cstr( + flipper_format, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) { + FURI_LOG_E(TAG, "Unable to add header"); + break; + } + + if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { + FURI_LOG_E(TAG, "Unable to add Frequency"); + break; + } + + subghz_block_generic_get_preset_name(furi_string_get_cstr(preset->name), temp_str); + if(!flipper_format_write_string_cstr( + flipper_format, "Preset", furi_string_get_cstr(temp_str))) { + FURI_LOG_E(TAG, "Unable to add Preset"); + break; + } + if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { + if(!flipper_format_write_string_cstr( + flipper_format, "Custom_preset_module", "CC1101")) { + FURI_LOG_E(TAG, "Unable to add Custom_preset_module"); + break; + } + if(!flipper_format_write_hex( + flipper_format, "Custom_preset_data", preset->data, preset->data_size)) { + FURI_LOG_E(TAG, "Unable to add Custom_preset_data"); + break; + } + } + if(!flipper_format_write_string_cstr( + flipper_format, "Protocol", instance->generic.protocol_name)) { + FURI_LOG_E(TAG, "Unable to add Protocol"); + break; + } + + uint32_t temp = instance->generic.data_count_bit; + if(!flipper_format_write_uint32(flipper_format, "Bit", &temp, 1)) { + FURI_LOG_E(TAG, "Unable to add Bit"); + break; + } + + if(!flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) { + FURI_LOG_E(TAG, "Unable to add TE"); + break; + } + + uint16_t i = 0; + while((i < BIN_RAW_MAX_MARKUP_COUNT) && (instance->data_markup[i].bit_count != 0)) { + temp = instance->data_markup[i].bit_count; + if(!flipper_format_write_uint32(flipper_format, "Bit_RAW", &temp, 1)) { + FURI_LOG_E(TAG, "Bit_RAW"); + break; + } + if(!flipper_format_write_hex( + flipper_format, + "Data_RAW", + instance->data + instance->data_markup[i].byte_bias, + subghz_protocol_bin_raw_get_full_byte(instance->data_markup[i].bit_count))) { + FURI_LOG_E(TAG, "Unable to add Data_RAW"); + break; + } + i++; + } + + res = true; + } while(false); + furi_string_free(temp_str); + return res; +} + +bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderBinRAW* instance = context; + + bool res = false; + uint32_t temp_data = 0; + + do { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) { + FURI_LOG_E(TAG, "Missing Bit"); + break; + } + + instance->generic.data_count_bit = (uint16_t)temp_data; + + if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) { + FURI_LOG_E(TAG, "Missing TE"); + break; + } + + temp_data = 0; + uint16_t ind = 0; + uint16_t byte_bias = 0; + uint16_t byte_count = 0; + memset(instance->data_markup, 0x00, BIN_RAW_MAX_MARKUP_COUNT * sizeof(BinRAW_Markup)); + while(flipper_format_read_uint32(flipper_format, "Bit_RAW", (uint32_t*)&temp_data, 1)) { + if(ind >= BIN_RAW_MAX_MARKUP_COUNT) { + FURI_LOG_E(TAG, "Markup overflow"); + break; + } + byte_count += subghz_protocol_bin_raw_get_full_byte(temp_data); + if(byte_count > BIN_RAW_BUF_DATA_SIZE) { + FURI_LOG_E(TAG, "Receive buffer overflow"); + break; + } + + instance->data_markup[ind].bit_count = temp_data; + instance->data_markup[ind].byte_bias = byte_bias; + byte_bias += subghz_protocol_bin_raw_get_full_byte(temp_data); + + if(!flipper_format_read_hex( + flipper_format, + "Data_RAW", + instance->data + instance->data_markup[ind].byte_bias, + subghz_protocol_bin_raw_get_full_byte(temp_data))) { + instance->data_markup[ind].bit_count = 0; + FURI_LOG_E(TAG, "Missing Data_RAW"); + break; + } + ind++; + } + + res = true; + } while(0); + + return res; +} + +void subghz_protocol_decoder_bin_raw_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderBinRAW* instance = context; + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:", + instance->generic.protocol_name, + instance->generic.data_count_bit); + + uint16_t byte_count = subghz_protocol_bin_raw_get_full_byte(instance->generic.data_count_bit); + for(size_t i = 0; (byte_count < 36 ? i < byte_count : i < 36); i++) { + furi_string_cat_printf(output, "%02X", instance->data[i]); + } + + furi_string_cat_printf(output, "\r\nTe:%luus\r\n", instance->te); +} diff --git a/lib/subghz/protocols/bin_raw.h b/lib/subghz/protocols/bin_raw.h new file mode 100644 index 000000000..c63f86ce6 --- /dev/null +++ b/lib/subghz/protocols/bin_raw.h @@ -0,0 +1,111 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_BIN_RAW_NAME "BinRAW" + +typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; +typedef struct SubGhzProtocolEncoderBinRAW SubGhzProtocolEncoderBinRAW; + +extern const SubGhzProtocolDecoder subghz_protocol_bin_raw_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_bin_raw_encoder; +extern const SubGhzProtocol subghz_protocol_bin_raw; + +/** + * Allocate SubGhzProtocolEncoderBinRAW. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderBinRAW* pointer to a SubGhzProtocolEncoderBinRAW instance + */ +void* subghz_protocol_encoder_bin_raw_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderBinRAW. + * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance + */ +void subghz_protocol_encoder_bin_raw_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance + */ +void subghz_protocol_encoder_bin_raw_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderBinRAW instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_bin_raw_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderBinRAW. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderBinRAW* pointer to a SubGhzProtocolDecoderBinRAW instance + */ +void* subghz_protocol_decoder_bin_raw_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderBinRAW. + * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance + */ +void subghz_protocol_decoder_bin_raw_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderBinRAW. + * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance + */ +void subghz_protocol_decoder_bin_raw_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_bin_raw_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_bin_raw_get_hash_data(void* context); + +void subghz_protocol_decoder_bin_raw_data_input_rssi( + SubGhzProtocolDecoderBinRAW* instance, + float rssi); + +/** + * Serialize data SubGhzProtocolDecoderBinRAW. + * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_decoder_bin_raw_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderBinRAW. + * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_bin_raw_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance + * @param output Resulting text + */ +void subghz_protocol_decoder_bin_raw_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index 32f4e9520..9c8e5ee4a 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -196,12 +196,13 @@ static bool break; } - instance->encoder.size_upload = subghz_protocol_blocks_get_upload( + instance->encoder.size_upload = subghz_protocol_blocks_get_upload_from_bit_array( upload_hex_data, upload_hex_count_bit, instance->encoder.upload, instance->encoder.size_upload, - subghz_protocol_chamb_code_const.te_short); + subghz_protocol_chamb_code_const.te_short, + SubGhzProtocolBlockAlignBitLeft); return true; } diff --git a/lib/subghz/protocols/dooya.c b/lib/subghz/protocols/dooya.c new file mode 100644 index 000000000..c70b6d54e --- /dev/null +++ b/lib/subghz/protocols/dooya.c @@ -0,0 +1,447 @@ +#include "dooya.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolDooya" + +#define DOYA_SINGLE_CHANNEL 0xFF + +static const SubGhzBlockConst subghz_protocol_dooya_const = { + .te_short = 366, + .te_long = 733, + .te_delta = 120, + .min_count_bit_for_found = 40, +}; + +struct SubGhzProtocolDecoderDooya { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderDooya { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + DooyaDecoderStepReset = 0, + DooyaDecoderStepFoundStartBit, + DooyaDecoderStepSaveDuration, + DooyaDecoderStepCheckDuration, +} DooyaDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_dooya_decoder = { + .alloc = subghz_protocol_decoder_dooya_alloc, + .free = subghz_protocol_decoder_dooya_free, + + .feed = subghz_protocol_decoder_dooya_feed, + .reset = subghz_protocol_decoder_dooya_reset, + + .get_hash_data = subghz_protocol_decoder_dooya_get_hash_data, + .serialize = subghz_protocol_decoder_dooya_serialize, + .deserialize = subghz_protocol_decoder_dooya_deserialize, + .get_string = subghz_protocol_decoder_dooya_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_dooya_encoder = { + .alloc = subghz_protocol_encoder_dooya_alloc, + .free = subghz_protocol_encoder_dooya_free, + + .deserialize = subghz_protocol_encoder_dooya_deserialize, + .stop = subghz_protocol_encoder_dooya_stop, + .yield = subghz_protocol_encoder_dooya_yield, +}; + +const SubGhzProtocol subghz_protocol_dooya = { + .name = SUBGHZ_PROTOCOL_DOOYA_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | + SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_dooya_decoder, + .encoder = &subghz_protocol_dooya_encoder, +}; + +void* subghz_protocol_encoder_dooya_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderDooya* instance = malloc(sizeof(SubGhzProtocolEncoderDooya)); + + instance->base.protocol = &subghz_protocol_dooya; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 128; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_dooya_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderDooya* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderDooya instance + * @return true On success + */ +static bool subghz_protocol_encoder_dooya_get_upload(SubGhzProtocolEncoderDooya* instance) { + furi_assert(instance); + + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2) + 2; + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + //Send header + if(bit_read(instance->generic.data, 0)) { + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_dooya_const.te_long * 12 + + subghz_protocol_dooya_const.te_long); + } else { + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_dooya_const.te_long * 12 + + subghz_protocol_dooya_const.te_short); + } + + //Send start bit + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_dooya_const.te_short * 13); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_dooya_const.te_long * 2); + + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_dooya_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_dooya_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_dooya_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_dooya_const.te_long); + } + } + return true; +} + +bool subghz_protocol_encoder_dooya_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderDooya* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_dooya_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!subghz_protocol_encoder_dooya_get_upload(instance)) break; + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_dooya_stop(void* context) { + SubGhzProtocolEncoderDooya* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_dooya_yield(void* context) { + SubGhzProtocolEncoderDooya* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_dooya_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderDooya* instance = malloc(sizeof(SubGhzProtocolDecoderDooya)); + instance->base.protocol = &subghz_protocol_dooya; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_dooya_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDooya* instance = context; + free(instance); +} + +void subghz_protocol_decoder_dooya_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDooya* instance = context; + instance->decoder.parser_step = DooyaDecoderStepReset; +} + +void subghz_protocol_decoder_dooya_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderDooya* instance = context; + + switch(instance->decoder.parser_step) { + case DooyaDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_dooya_const.te_long * 12) < + subghz_protocol_dooya_const.te_delta * 20)) { + instance->decoder.parser_step = DooyaDecoderStepFoundStartBit; + } + break; + + case DooyaDecoderStepFoundStartBit: + if(!level) { + if(DURATION_DIFF(duration, subghz_protocol_dooya_const.te_long * 2) < + subghz_protocol_dooya_const.te_delta * 3) { + instance->decoder.parser_step = DooyaDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } else { + instance->decoder.parser_step = DooyaDecoderStepReset; + } + } else if( + DURATION_DIFF(duration, subghz_protocol_dooya_const.te_short * 13) < + subghz_protocol_dooya_const.te_delta * 5) { + break; + } else { + instance->decoder.parser_step = DooyaDecoderStepReset; + } + break; + + case DooyaDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = DooyaDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = DooyaDecoderStepReset; + } + break; + + case DooyaDecoderStepCheckDuration: + if(!level) { + if(duration >= (subghz_protocol_dooya_const.te_long * 4)) { + //add last bit + if(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_dooya_const.te_short) < + subghz_protocol_dooya_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } else if( + DURATION_DIFF(instance->decoder.te_last, subghz_protocol_dooya_const.te_long) < + subghz_protocol_dooya_const.te_delta * 2) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else { + instance->decoder.parser_step = DooyaDecoderStepReset; + break; + } + instance->decoder.parser_step = DooyaDecoderStepFoundStartBit; + if(instance->decoder.decode_count_bit == + subghz_protocol_dooya_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + break; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_dooya_const.te_short) < + subghz_protocol_dooya_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_dooya_const.te_long) < + subghz_protocol_dooya_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = DooyaDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_dooya_const.te_long) < + subghz_protocol_dooya_const.te_delta * 2) && + (DURATION_DIFF(duration, subghz_protocol_dooya_const.te_short) < + subghz_protocol_dooya_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = DooyaDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = DooyaDecoderStepReset; + } + } else { + instance->decoder.parser_step = DooyaDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_somfy_telis_check_remote_controller(SubGhzBlockGeneric* instance) { + /* + * serial s/m ch key + * long press down X * E1DC030533, 40b 111000011101110000000011 0000 0101 0011 0011 + * + * short press down 3 * E1DC030533, 40b 111000011101110000000011 0000 0101 0011 0011 + * 3 * E1DC03053C, 40b 111000011101110000000011 0000 0101 0011 1100 + * + * press stop X * E1DC030555, 40b 111000011101110000000011 0000 0101 0101 0101 + * + * long press up X * E1DC030511, 40b 111000011101110000000011 0000 0101 0001 0001 + * + * short press up 3 * E1DC030511, 40b 111000011101110000000011 0000 0101 0001 0001 + * 3 * E1DC03051E, 40b 111000011101110000000011 0000 0101 0001 1110 + * + * serial: 3 byte serial number + * s/m: single (b0000) / multi (b0001) channel console + * ch: channel if single (always b0101) or multi + * key: 0b00010001 - long press up + * 0b00011110 - short press up + * 0b00110011 - long press down + * 0b00111100 - short press down + * 0b01010101 - press stop + * 0b01111001 - press up + down + * 0b10000000 - press up + stop + * 0b10000001 - press down + stop + * 0b11001100 - press P2 + * +*/ + + instance->serial = (instance->data >> 16); + if((instance->data >> 12) & 0x0F) { + instance->cnt = (instance->data >> 8) & 0x0F; + } else { + instance->cnt = DOYA_SINGLE_CHANNEL; + } + instance->btn = instance->data & 0xFF; +} + +uint8_t subghz_protocol_decoder_dooya_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderDooya* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_dooya_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderDooya* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_dooya_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderDooya* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_dooya_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +/** + * Get button name. + * @param btn Button number, 8 bit + */ +static const char* subghz_protocol_dooya_get_name_button(uint8_t btn) { + const char* btn_name; + switch(btn) { + case 0b00010001: + btn_name = "Up_Long"; + break; + case 0b00011110: + btn_name = "Up_Short"; + break; + case 0b00110011: + btn_name = "Down_Long"; + break; + case 0b00111100: + btn_name = "Down_Short"; + break; + case 0b01010101: + btn_name = "Stop"; + break; + case 0b01111001: + btn_name = "Up+Down"; + break; + case 0b10000000: + btn_name = "Up+Stop"; + break; + case 0b10000001: + btn_name = "Down+Stop"; + break; + case 0b11001100: + btn_name = "P2"; + break; + default: + btn_name = "Unknown"; + break; + } + return btn_name; +} + +void subghz_protocol_decoder_dooya_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderDooya* instance = context; + + subghz_protocol_somfy_telis_check_remote_controller(&instance->generic); + + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:0x%010llX\r\n" + "Sn:0x%08lX\r\n" + "Btn:%s\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + instance->generic.data, + instance->generic.serial, + subghz_protocol_dooya_get_name_button(instance->generic.btn)); + if(instance->generic.cnt == DOYA_SINGLE_CHANNEL) { + furi_string_cat_printf(output, "Ch:Single\r\n"); + } else { + furi_string_cat_printf(output, "Ch:%lu\r\n", instance->generic.cnt); + } +} diff --git a/lib/subghz/protocols/dooya.h b/lib/subghz/protocols/dooya.h new file mode 100644 index 000000000..f0cf843c0 --- /dev/null +++ b/lib/subghz/protocols/dooya.h @@ -0,0 +1,107 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_DOOYA_NAME "Dooya" + +typedef struct SubGhzProtocolDecoderDooya SubGhzProtocolDecoderDooya; +typedef struct SubGhzProtocolEncoderDooya SubGhzProtocolEncoderDooya; + +extern const SubGhzProtocolDecoder subghz_protocol_dooya_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_dooya_encoder; +extern const SubGhzProtocol subghz_protocol_dooya; + +/** + * Allocate SubGhzProtocolEncoderDooya. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderDooya* pointer to a SubGhzProtocolEncoderDooya instance + */ +void* subghz_protocol_encoder_dooya_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderDooya. + * @param context Pointer to a SubGhzProtocolEncoderDooya instance + */ +void subghz_protocol_encoder_dooya_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderDooya instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_dooya_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderDooya instance + */ +void subghz_protocol_encoder_dooya_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderDooya instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_dooya_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderDooya. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderDooya* pointer to a SubGhzProtocolDecoderDooya instance + */ +void* subghz_protocol_decoder_dooya_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderDooya. + * @param context Pointer to a SubGhzProtocolDecoderDooya instance + */ +void subghz_protocol_decoder_dooya_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderDooya. + * @param context Pointer to a SubGhzProtocolDecoderDooya instance + */ +void subghz_protocol_decoder_dooya_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderDooya instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_dooya_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderDooya instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_dooya_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderDooya. + * @param context Pointer to a SubGhzProtocolDecoderDooya instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_decoder_dooya_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderDooya. + * @param context Pointer to a SubGhzProtocolDecoderDooya instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_dooya_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderDooya instance + * @param output Resulting text + */ +void subghz_protocol_decoder_dooya_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index aaf573a57..a0970de4d 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -520,11 +520,14 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur subghz_protocol_keeloq_const.te_delta)) { // Found end TX instance->decoder.parser_step = KeeloqDecoderStepReset; - if(instance->decoder.decode_count_bit >= - subghz_protocol_keeloq_const.min_count_bit_for_found) { + if((instance->decoder.decode_count_bit >= + subghz_protocol_keeloq_const.min_count_bit_for_found) && + (instance->decoder.decode_count_bit <= + subghz_protocol_keeloq_const.min_count_bit_for_found + 2)) { if(instance->generic.data != instance->decoder.decode_data) { instance->generic.data = instance->decoder.decode_data; - instance->generic.data_count_bit = instance->decoder.decode_count_bit; + instance->generic.data_count_bit = + subghz_protocol_keeloq_const.min_count_bit_for_found; if(instance->base.callback) instance->base.callback(&instance->base, instance->base.context); } @@ -541,6 +544,8 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur if(instance->decoder.decode_count_bit < subghz_protocol_keeloq_const.min_count_bit_for_found) { subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else { + instance->decoder.decode_count_bit++; } instance->decoder.parser_step = KeeloqDecoderStepSaveDuration; } else if( @@ -551,6 +556,8 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur if(instance->decoder.decode_count_bit < subghz_protocol_keeloq_const.min_count_bit_for_found) { subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } else { + instance->decoder.decode_count_bit++; } instance->decoder.parser_step = KeeloqDecoderStepSaveDuration; } else { diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c new file mode 100644 index 000000000..5f2a83d77 --- /dev/null +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -0,0 +1,581 @@ +#include "kinggates_stylo_4k.h" +#include "keeloq_common.h" + +#include "../subghz_keystore.h" +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocoKingGates_stylo_4k" + +static const SubGhzBlockConst subghz_protocol_kinggates_stylo_4k_const = { + .te_short = 400, + .te_long = 1100, + .te_delta = 140, + .min_count_bit_for_found = 89, +}; + +struct SubGhzProtocolDecoderKingGates_stylo_4k { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + + uint16_t header_count; + SubGhzKeystore* keystore; +}; + +struct SubGhzProtocolEncoderKingGates_stylo_4k { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; + SubGhzKeystore* keystore; +}; + +typedef enum { + KingGates_stylo_4kDecoderStepReset = 0, + KingGates_stylo_4kDecoderStepCheckPreambula, + KingGates_stylo_4kDecoderStepCheckStartBit, + KingGates_stylo_4kDecoderStepSaveDuration, + KingGates_stylo_4kDecoderStepCheckDuration, +} KingGates_stylo_4kDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_kinggates_stylo_4k_decoder = { + .alloc = subghz_protocol_decoder_kinggates_stylo_4k_alloc, + .free = subghz_protocol_decoder_kinggates_stylo_4k_free, + + .feed = subghz_protocol_decoder_kinggates_stylo_4k_feed, + .reset = subghz_protocol_decoder_kinggates_stylo_4k_reset, + + .get_hash_data = subghz_protocol_decoder_kinggates_stylo_4k_get_hash_data, + .serialize = subghz_protocol_decoder_kinggates_stylo_4k_serialize, + .deserialize = subghz_protocol_decoder_kinggates_stylo_4k_deserialize, + .get_string = subghz_protocol_decoder_kinggates_stylo_4k_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_kinggates_stylo_4k_encoder = { + .alloc = subghz_protocol_encoder_kinggates_stylo_4k_alloc, + .free = subghz_protocol_encoder_kinggates_stylo_4k_free, + + .deserialize = subghz_protocol_encoder_kinggates_stylo_4k_deserialize, + .stop = subghz_protocol_encoder_kinggates_stylo_4k_stop, + .yield = subghz_protocol_encoder_kinggates_stylo_4k_yield, +}; + +const SubGhzProtocol subghz_protocol_kinggates_stylo_4k = { + .name = SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME, + .type = SubGhzProtocolTypeDynamic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_kinggates_stylo_4k_decoder, + .encoder = &subghz_protocol_kinggates_stylo_4k_encoder, +}; + +// +// Encoder +// + +// Pre define function +static void subghz_protocol_kinggates_stylo_4k_remote_controller( + SubGhzBlockGeneric* instance, + SubGhzKeystore* keystore); + +void* subghz_protocol_encoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* environment) { + SubGhzProtocolEncoderKingGates_stylo_4k* instance = + malloc(sizeof(SubGhzProtocolEncoderKingGates_stylo_4k)); + + instance->base.protocol = &subghz_protocol_kinggates_stylo_4k; + instance->generic.protocol_name = instance->base.protocol->name; + instance->keystore = subghz_environment_get_keystore(environment); + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 512; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + + return instance; +} + +void subghz_protocol_encoder_kinggates_stylo_4k_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderKingGates_stylo_4k* instance = context; + free(instance->encoder.upload); + free(instance); +} + +void subghz_protocol_encoder_kinggates_stylo_4k_stop(void* context) { + SubGhzProtocolEncoderKingGates_stylo_4k* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_kinggates_stylo_4k_yield(void* context) { + SubGhzProtocolEncoderKingGates_stylo_4k* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +/** + * Key generation from simple data + * @param instance Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k* instance + * @param btn Button number, 4 bit + */ +static bool subghz_protocol_kinggates_stylo_4k_gen_data( + SubGhzProtocolEncoderKingGates_stylo_4k* instance, + uint8_t btn) { + UNUSED(btn); + uint32_t hop = subghz_protocol_blocks_reverse_key(instance->generic.data_2 >> 4, 32); + uint64_t fix = subghz_protocol_blocks_reverse_key(instance->generic.data, 53); + int res = 0; + uint32_t decrypt = 0; + + for + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { + res = strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k"); + if(res == 0) { + //Simple Learning + decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); + break; + } + } + instance->generic.cnt = decrypt & 0xFFFF; + + if(instance->generic.cnt < 0xFFFF) { + instance->generic.cnt++; + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } + + instance->generic.btn = (fix >> 17) & 0x0F; + instance->generic.serial = ((fix >> 5) & 0xFFFF0000) | (fix & 0xFFFF); + + uint32_t data = (decrypt & 0xFFFF0000) | instance->generic.cnt; + + uint64_t encrypt = 0; + for + M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { + res = strcmp(furi_string_get_cstr(manufacture_code->name), "Kingates_Stylo4k"); + if(res == 0) { + //Simple Learning + encrypt = subghz_protocol_keeloq_common_encrypt(data, manufacture_code->key); + encrypt = subghz_protocol_blocks_reverse_key(encrypt, 32); + instance->generic.data_2 = encrypt << 4; + return true; + } + } + + return false; +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance + * @return true On success + */ +static bool subghz_protocol_encoder_kinggates_stylo_4k_get_upload( + SubGhzProtocolEncoderKingGates_stylo_4k* instance, + uint8_t btn) { + furi_assert(instance); + + // Gen new key + if(subghz_protocol_kinggates_stylo_4k_gen_data(instance, btn)) { + //ToDo if you need to add a callback to automatically update the data on the display + } else { + return false; + } + + size_t index = 0; + + // Start + instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)9500); + + // Send header + for(uint8_t i = 12; i > 0; i--) { + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_short); + } + + // After header + instance->encoder.upload[index - 1].duration = + (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_long * 2; + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_short * 2); + + // Send key fix + for(uint8_t i = 53; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_long); + } else { + //send bit 0 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_short); + } + } + + // Send key hop + for(uint8_t i = 36; i > 0; i--) { + if(bit_read(instance->generic.data_2, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_long); + } else { + //send bit 0 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_short); + } + } + + // Set upload size after generating upload, fix it later + + instance->encoder.size_upload = index; + + return true; +} + +bool subghz_protocol_encoder_kinggates_stylo_4k_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderKingGates_stylo_4k* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + subghz_protocol_kinggates_stylo_4k_remote_controller( + &instance->generic, instance->keystore); + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + + uint8_t key_data[sizeof(uint64_t)] = {0}; + if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Missing Data"); + break; + } + + for(uint8_t i = 0; i < sizeof(uint64_t); i++) { + instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i]; + } + + subghz_protocol_encoder_kinggates_stylo_4k_get_upload(instance, instance->generic.btn); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Key"); + break; + } + + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +// +// Decoder +// +void* subghz_protocol_decoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* environment) { + SubGhzProtocolDecoderKingGates_stylo_4k* instance = + malloc(sizeof(SubGhzProtocolDecoderKingGates_stylo_4k)); + instance->base.protocol = &subghz_protocol_kinggates_stylo_4k; + instance->generic.protocol_name = instance->base.protocol->name; + instance->keystore = subghz_environment_get_keystore(environment); + return instance; +} + +void subghz_protocol_decoder_kinggates_stylo_4k_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; + free(instance); +} + +void subghz_protocol_decoder_kinggates_stylo_4k_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset; +} + +void subghz_protocol_decoder_kinggates_stylo_4k_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; + + switch(instance->decoder.parser_step) { + case KingGates_stylo_4kDecoderStepReset: + if((level) && DURATION_DIFF(duration, subghz_protocol_kinggates_stylo_4k_const.te_short) < + subghz_protocol_kinggates_stylo_4k_const.te_delta) { + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepCheckPreambula; + instance->header_count++; + } + break; + case KingGates_stylo_4kDecoderStepCheckPreambula: + if((!level) && + (DURATION_DIFF(duration, subghz_protocol_kinggates_stylo_4k_const.te_short) < + subghz_protocol_kinggates_stylo_4k_const.te_delta)) { + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset; + break; + } + if((instance->header_count > 2) && + (DURATION_DIFF(duration, subghz_protocol_kinggates_stylo_4k_const.te_long * 2) < + subghz_protocol_kinggates_stylo_4k_const.te_delta * 2)) { + // Found header + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepCheckStartBit; + } else { + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset; + instance->header_count = 0; + } + break; + case KingGates_stylo_4kDecoderStepCheckStartBit: + if((level) && + DURATION_DIFF(duration, subghz_protocol_kinggates_stylo_4k_const.te_short * 2) < + subghz_protocol_kinggates_stylo_4k_const.te_delta * 2) { + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->generic.data_2 = 0; + instance->decoder.decode_count_bit = 0; + instance->header_count = 0; + } + break; + case KingGates_stylo_4kDecoderStepSaveDuration: + if(!level) { + if(duration >= ((uint32_t)subghz_protocol_kinggates_stylo_4k_const.te_long * 3)) { + if(instance->decoder.decode_count_bit == + subghz_protocol_kinggates_stylo_4k_const.min_count_bit_for_found) { + instance->generic.data = instance->generic.data_2; + instance->generic.data_2 = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset; + instance->decoder.decode_data = 0; + instance->generic.data_2 = 0; + instance->decoder.decode_count_bit = 0; + instance->header_count = 0; + break; + } else { + instance->decoder.te_last = duration; + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepCheckDuration; + } + } else { + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset; + instance->header_count = 0; + } + break; + case KingGates_stylo_4kDecoderStepCheckDuration: + if(level) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_kinggates_stylo_4k_const.te_short) < + subghz_protocol_kinggates_stylo_4k_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_kinggates_stylo_4k_const.te_long) < + subghz_protocol_kinggates_stylo_4k_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_kinggates_stylo_4k_const.te_long) < + subghz_protocol_kinggates_stylo_4k_const.te_delta * 2) && + (DURATION_DIFF(duration, subghz_protocol_kinggates_stylo_4k_const.te_short) < + subghz_protocol_kinggates_stylo_4k_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset; + instance->header_count = 0; + } + if(instance->decoder.decode_count_bit == 53) { + instance->generic.data_2 = instance->decoder.decode_data; + instance->decoder.decode_data = 0; + } + } else { + instance->decoder.parser_step = KingGates_stylo_4kDecoderStepReset; + instance->header_count = 0; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + * @param data Input encrypted data + * @param keystore Pointer to a SubGhzKeystore* instance + */ +static void subghz_protocol_kinggates_stylo_4k_remote_controller( + SubGhzBlockGeneric* instance, + SubGhzKeystore* keystore) { + /** + * 9500us 12*(400/400) 2200/800|1-bit|0-bit| + * _ _ _ __ ___ _ + * ________| |_| |_..._| |_____| |_| |___| |..... + * + * 1-bit 400/1100 us + * 0-bit 1100/400 us + * + * The package consists of 89 bits of data, LSB first + * Data - 1C9037F0C80000 CE280BA00 + * S[3] S[2] 1 key S[1] S[0] 2 byte always 0 Hop[3] Hop[2] Hop[1] Hop[0] 0 + * 11100100 10000001 1 0111 11110000 11001000 00000000 00000000 11001110 00101000 00001011 10100000 0000 + * + * Encryption - keeloq Simple Learning + * key C S[3] CNT + * Decrypt - 0xEC270B9C => 0x E C 27 0B9C + * + * + * +*/ + + uint32_t hop = subghz_protocol_blocks_reverse_key(instance->data_2 >> 4, 32); + uint64_t fix = subghz_protocol_blocks_reverse_key(instance->data, 53); + bool ret = false; + uint32_t decrypt = 0; + instance->btn = (fix >> 17) & 0x0F; + instance->serial = ((fix >> 5) & 0xFFFF0000) | (fix & 0xFFFF); + + for + M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) { + if(manufacture_code->type == KEELOQ_LEARNING_SIMPLE) { + decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); + if(((decrypt >> 28) == instance->btn) && (((decrypt >> 24) & 0x0F) == 0x0C) && + (((decrypt >> 16) & 0xFF) == (instance->serial & 0xFF))) { + ret = true; + break; + } + } + } + if(ret) { + instance->cnt = decrypt & 0xFFFF; + } else { + instance->btn = 0; + instance->serial = 0; + instance->cnt = 0; + } +} + +uint8_t subghz_protocol_decoder_kinggates_stylo_4k_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool subghz_protocol_decoder_kinggates_stylo_4k_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; + bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data_2 >> (i * 8)) & 0xFF; + } + + if(res && !flipper_format_write_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Data"); + res = false; + } + return res; + + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_kinggates_stylo_4k_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_kinggates_stylo_4k_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; + if(!flipper_format_read_hex(flipper_format, "Data", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Missing Data"); + break; + } + + for(uint8_t i = 0; i < sizeof(uint64_t); i++) { + instance->generic.data_2 = instance->generic.data_2 << 8 | key_data[i]; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_kinggates_stylo_4k_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderKingGates_stylo_4k* instance = context; + subghz_protocol_kinggates_stylo_4k_remote_controller(&instance->generic, instance->keystore); + + furi_string_cat_printf( + output, + "%s\r\n" + "Key:0x%llX%07llX %dbit\r\n" + "Sn:0x%08lX Btn:0x%01X\r\n" + "Cnt:0x%04lX\r\n", + instance->generic.protocol_name, + instance->generic.data, + instance->generic.data_2, + instance->generic.data_count_bit, + instance->generic.serial, + instance->generic.btn, + instance->generic.cnt); +} \ No newline at end of file diff --git a/lib/subghz/protocols/kinggates_stylo_4k.h b/lib/subghz/protocols/kinggates_stylo_4k.h new file mode 100644 index 000000000..9717f6715 --- /dev/null +++ b/lib/subghz/protocols/kinggates_stylo_4k.h @@ -0,0 +1,110 @@ +#pragma once +#include "base.h" + +#define SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME "KingGates Stylo4k" + +typedef struct SubGhzProtocolDecoderKingGates_stylo_4k SubGhzProtocolDecoderKingGates_stylo_4k; +typedef struct SubGhzProtocolEncoderKingGates_stylo_4k SubGhzProtocolEncoderKingGates_stylo_4k; + +extern const SubGhzProtocolDecoder subghz_protocol_kinggates_stylo_4k_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_kinggates_stylo_4k_encoder; +extern const SubGhzProtocol subghz_protocol_kinggates_stylo_4k; + +/** + * Allocate SubGhzProtocolEncoderKingGates_stylo_4k. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderKingGates_stylo_4k* pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance + */ +void* subghz_protocol_encoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderKingGates_stylo_4k. + * @param context Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance + */ +void subghz_protocol_encoder_kinggates_stylo_4k_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_kinggates_stylo_4k_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance + */ +void subghz_protocol_encoder_kinggates_stylo_4k_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderKingGates_stylo_4k instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_kinggates_stylo_4k_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderKingGates_stylo_4k. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderKingGates_stylo_4k* pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance + */ +void* subghz_protocol_decoder_kinggates_stylo_4k_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderKingGates_stylo_4k. + * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance + */ +void subghz_protocol_decoder_kinggates_stylo_4k_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderKingGates_stylo_4k. + * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance + */ +void subghz_protocol_decoder_kinggates_stylo_4k_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_kinggates_stylo_4k_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_kinggates_stylo_4k_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderKingGates_stylo_4k. + * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_decoder_kinggates_stylo_4k_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderKingGates_stylo_4k. + * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_kinggates_stylo_4k_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderKingGates_stylo_4k instance + * @param output Resulting text + */ +void subghz_protocol_decoder_kinggates_stylo_4k_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/linear_delta3.c b/lib/subghz/protocols/linear_delta3.c new file mode 100644 index 000000000..869edac84 --- /dev/null +++ b/lib/subghz/protocols/linear_delta3.c @@ -0,0 +1,359 @@ +#include "linear_delta3.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +#define TAG "SubGhzProtocolLinearDelta3" + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c" +#define DATA_TO_DIP(dip) \ + (dip & 0x0080 ? '1' : '0'), (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), \ + (dip & 0x0010 ? '1' : '0'), (dip & 0x0008 ? '1' : '0'), (dip & 0x0004 ? '1' : '0'), \ + (dip & 0x0002 ? '1' : '0'), (dip & 0x0001 ? '1' : '0') + +static const SubGhzBlockConst subghz_protocol_linear_delta3_const = { + .te_short = 500, + .te_long = 2000, + .te_delta = 150, + .min_count_bit_for_found = 8, +}; + +struct SubGhzProtocolDecoderLinearDelta3 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; + + uint32_t last_data; +}; + +struct SubGhzProtocolEncoderLinearDelta3 { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + LinearDecoderStepReset = 0, + LinearDecoderStepSaveDuration, + LinearDecoderStepCheckDuration, +} LinearDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_linear_delta3_decoder = { + .alloc = subghz_protocol_decoder_linear_delta3_alloc, + .free = subghz_protocol_decoder_linear_delta3_free, + + .feed = subghz_protocol_decoder_linear_delta3_feed, + .reset = subghz_protocol_decoder_linear_delta3_reset, + + .get_hash_data = subghz_protocol_decoder_linear_delta3_get_hash_data, + .serialize = subghz_protocol_decoder_linear_delta3_serialize, + .deserialize = subghz_protocol_decoder_linear_delta3_deserialize, + .get_string = subghz_protocol_decoder_linear_delta3_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_linear_delta3_encoder = { + .alloc = subghz_protocol_encoder_linear_delta3_alloc, + .free = subghz_protocol_encoder_linear_delta3_free, + + .deserialize = subghz_protocol_encoder_linear_delta3_deserialize, + .stop = subghz_protocol_encoder_linear_delta3_stop, + .yield = subghz_protocol_encoder_linear_delta3_yield, +}; + +const SubGhzProtocol subghz_protocol_linear_delta3 = { + .name = SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_linear_delta3_decoder, + .encoder = &subghz_protocol_linear_delta3_encoder, +}; + +void* subghz_protocol_encoder_linear_delta3_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderLinearDelta3* instance = + malloc(sizeof(SubGhzProtocolEncoderLinearDelta3)); + + instance->base.protocol = &subghz_protocol_linear_delta3; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 16; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_linear_delta3_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderLinearDelta3* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderLinearDelta3 instance + * @return true On success + */ +static bool + subghz_protocol_encoder_linear_delta3_get_upload(SubGhzProtocolEncoderLinearDelta3* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2); + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + //Send key data + for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_linear_delta3_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_linear_delta3_const.te_short * 7); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_linear_delta3_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_linear_delta3_const.te_long); + } + } + //Send end bit + if(bit_read(instance->generic.data, 0)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_linear_delta3_const.te_short); + //Send PT_GUARD + instance->encoder.upload[index] = level_duration_make( + false, (uint32_t)subghz_protocol_linear_delta3_const.te_short * 73); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_linear_delta3_const.te_long); + //Send PT_GUARD + instance->encoder.upload[index] = level_duration_make( + false, (uint32_t)subghz_protocol_linear_delta3_const.te_short * 70); + } + + return true; +} + +bool subghz_protocol_encoder_linear_delta3_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderLinearDelta3* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_linear_delta3_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!subghz_protocol_encoder_linear_delta3_get_upload(instance)) break; + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_linear_delta3_stop(void* context) { + SubGhzProtocolEncoderLinearDelta3* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_linear_delta3_yield(void* context) { + SubGhzProtocolEncoderLinearDelta3* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_linear_delta3_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderLinearDelta3* instance = + malloc(sizeof(SubGhzProtocolDecoderLinearDelta3)); + instance->base.protocol = &subghz_protocol_linear_delta3; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_linear_delta3_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderLinearDelta3* instance = context; + free(instance); +} + +void subghz_protocol_decoder_linear_delta3_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderLinearDelta3* instance = context; + instance->decoder.parser_step = LinearDecoderStepReset; + instance->last_data = 0; +} + +void subghz_protocol_decoder_linear_delta3_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderLinearDelta3* instance = context; + switch(instance->decoder.parser_step) { + case LinearDecoderStepReset: + if((!level) && + (DURATION_DIFF(duration, subghz_protocol_linear_delta3_const.te_short * 70) < + subghz_protocol_linear_delta3_const.te_delta * 24)) { + //Found header Linear + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + instance->decoder.parser_step = LinearDecoderStepSaveDuration; + } + break; + case LinearDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = LinearDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = LinearDecoderStepReset; + } + break; + case LinearDecoderStepCheckDuration: + if(!level) { + if(duration >= (subghz_protocol_linear_delta3_const.te_short * 10)) { + instance->decoder.parser_step = LinearDecoderStepReset; + if(DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_linear_delta3_const.te_short) < + subghz_protocol_linear_delta3_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else if( + DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_linear_delta3_const.te_long) < + subghz_protocol_linear_delta3_const.te_delta) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } + if(instance->decoder.decode_count_bit == + subghz_protocol_linear_delta3_const.min_count_bit_for_found) { + if((instance->last_data == instance->decoder.decode_data) && + instance->last_data) { + instance->generic.serial = 0x0; + instance->generic.btn = 0x0; + + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.parser_step = LinearDecoderStepSaveDuration; + instance->last_data = instance->decoder.decode_data; + } + break; + } + + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_linear_delta3_const.te_short) < + subghz_protocol_linear_delta3_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_linear_delta3_const.te_short * 7) < + subghz_protocol_linear_delta3_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = LinearDecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_linear_delta3_const.te_long) < + subghz_protocol_linear_delta3_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_linear_delta3_const.te_long) < + subghz_protocol_linear_delta3_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = LinearDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = LinearDecoderStepReset; + } + + } else { + instance->decoder.parser_step = LinearDecoderStepReset; + } + break; + } +} + +uint8_t subghz_protocol_decoder_linear_delta3_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderLinearDelta3* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8)); +} + +bool subghz_protocol_decoder_linear_delta3_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderLinearDelta3* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool subghz_protocol_decoder_linear_delta3_deserialize( + void* context, + FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderLinearDelta3* instance = context; + bool ret = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + subghz_protocol_linear_delta3_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void subghz_protocol_decoder_linear_delta3_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderLinearDelta3* instance = context; + + uint32_t data = instance->generic.data & 0xFF; + + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX\r\n" + "DIP:" DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + data, + DATA_TO_DIP(data)); +} diff --git a/lib/subghz/protocols/linear_delta3.h b/lib/subghz/protocols/linear_delta3.h new file mode 100644 index 000000000..2f0a32e68 --- /dev/null +++ b/lib/subghz/protocols/linear_delta3.h @@ -0,0 +1,111 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME "LinearDelta3" + +typedef struct SubGhzProtocolDecoderLinearDelta3 SubGhzProtocolDecoderLinearDelta3; +typedef struct SubGhzProtocolEncoderLinearDelta3 SubGhzProtocolEncoderLinearDelta3; + +extern const SubGhzProtocolDecoder subghz_protocol_linear_delta3_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_linear_delta3_encoder; +extern const SubGhzProtocol subghz_protocol_linear_delta3; + +/** + * Allocate SubGhzProtocolEncoderLinearDelta3. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderLinearDelta3* pointer to a SubGhzProtocolEncoderLinearDelta3 instance + */ +void* subghz_protocol_encoder_linear_delta3_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderLinearDelta3. + * @param context Pointer to a SubGhzProtocolEncoderLinearDelta3 instance + */ +void subghz_protocol_encoder_linear_delta3_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderLinearDelta3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_linear_delta3_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderLinearDelta3 instance + */ +void subghz_protocol_encoder_linear_delta3_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderLinearDelta3 instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_linear_delta3_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderLinearDelta3. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderLinearDelta3* pointer to a SubGhzProtocolDecoderLinearDelta3 instance + */ +void* subghz_protocol_decoder_linear_delta3_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderLinearDelta3. + * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance + */ +void subghz_protocol_decoder_linear_delta3_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderLinearDelta3. + * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance + */ +void subghz_protocol_decoder_linear_delta3_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_linear_delta3_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_linear_delta3_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderLinearDelta3. + * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_decoder_linear_delta3_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderLinearDelta3. + * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_decoder_linear_delta3_deserialize( + void* context, + FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderLinearDelta3 instance + * @param output Resulting text + */ +void subghz_protocol_decoder_linear_delta3_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 5ca95901d..d3a2d6acd 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -14,6 +14,9 @@ #define TAG "SubGhzProtocolNiceFlorS" +#define NICE_ONE_COUNT_BIT 72 +#define NICE_ONE_NAME "Nice One" + static const SubGhzBlockConst subghz_protocol_nice_flor_s_const = { .te_short = 500, .te_long = 1000, @@ -28,6 +31,7 @@ struct SubGhzProtocolDecoderNiceFlorS { SubGhzBlockGeneric generic; const char* nice_flor_s_rainbow_table_file_name; + uint64_t data; }; struct SubGhzProtocolEncoderNiceFlorS { @@ -96,7 +100,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment) TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name); } instance->encoder.repeat = 10; - instance->encoder.size_upload = 1728; //wrong!! upload 186*16 = 2976 - actual size about 1728 + instance->encoder.size_upload = 2400; //wrong!! upload 186*16 = 2976 - actual size about 1728 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; @@ -109,6 +113,8 @@ void subghz_protocol_encoder_nice_flor_s_free(void* context) { free(instance); } +static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, uint8_t hold_bit); + /** * Generating an upload from data. * @param instance Pointer to a SubGhzProtocolEncoderNiceFlorS instance @@ -156,8 +162,8 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( level_duration_make(false, (uint32_t)subghz_protocol_nice_flor_s_const.te_short * 3); //Send key data - for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { - if(bit_read(instance->generic.data, i - 1)) { + for(uint8_t j = 52; j > 0; j--) { + if(bit_read(instance->generic.data, j - 1)) { //send bit 1 instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_nice_flor_s_const.te_long); @@ -171,6 +177,35 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( false, (uint32_t)subghz_protocol_nice_flor_s_const.te_long); } } + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { + uint8_t add_data[10] = {0}; + for(size_t i = 0; i < 7; i++) { + add_data[i] = (instance->generic.data >> (48 - i * 8)) & 0xFF; + } + subghz_protocol_nice_one_get_data(add_data, loops[i], loops[i]); + instance->generic.data_2 = 0; + for(size_t j = 7; j < 10; j++) { + instance->generic.data_2 <<= 8; + instance->generic.data_2 += add_data[j]; + } + + //Send key data + for(uint8_t j = 24; j > 4; j--) { + if(bit_read(instance->generic.data_2, j - 1)) { + //send bit 1 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_nice_flor_s_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_nice_flor_s_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_nice_flor_s_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_nice_flor_s_const.te_long); + } + } + } //Send stop bit instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_nice_flor_s_const.te_short * 3); @@ -193,6 +228,8 @@ bool subghz_protocol_encoder_nice_flor_s_deserialize(void* context, FlipperForma //optional parameter parameter flipper_format_read_uint32( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + // flipper_format_read_uint32( + // flipper_format, "Data", (uint32_t*)&instance->generic.data_2, 1); subghz_protocol_nice_flor_s_remote_controller( &instance->generic, instance->nice_flor_s_rainbow_table_file_name); @@ -212,6 +249,17 @@ bool subghz_protocol_encoder_nice_flor_s_deserialize(void* context, FlipperForma break; } + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint32_t temp = (instance->generic.data_2 >> 4) & 0xFFFFF; + if(!flipper_format_update_uint32(flipper_format, "Data", &temp, 1)) { + FURI_LOG_E(TAG, "Unable to add Data"); + } + } + instance->encoder.is_running = true; res = true; @@ -243,6 +291,64 @@ LevelDuration subghz_protocol_encoder_nice_flor_s_yield(void* context) { return ret; } +/** + * Read bytes from rainbow table + * @param p array[10] P0-P1|P2-P3-P4-P5-P6-P7-P8-P9-P10 + * @return crc + */ +static uint32_t subghz_protocol_nice_one_crc(uint8_t* p) { + uint8_t crc = 0; + uint8_t crc_data = 0xff; + for(uint8_t i = 4; i < 68; i++) { + if(subghz_protocol_blocks_get_bit_array(p, i)) { + crc = crc_data ^ 1; + } else { + crc = crc_data; + } + crc_data >>= 1; + if((crc & 0x01)) { + crc_data ^= 0x97; + } + } + crc = 0; + for(uint8_t i = 0; i < 8; i++) { + crc <<= 1; + if((crc_data >> i) & 0x01) crc = crc | 1; + } + return crc; +} + +/** + * Read bytes from rainbow table + * @param p array[10] P0-P1|P2-P3-P4-P5-P6-P7-XX-XX-XX + * @param num_parcel parcel number 0..15 + * @param hold_bit 0 - the button was only pressed, 1 - the button was held down + */ +static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, uint8_t hold_bit) { + uint8_t k = 0; + uint8_t crc = 0; + p[1] = (p[1] & 0x0f) | ((0x0f ^ (p[0] & 0x0F) ^ num_parcel) << 4); + if(num_parcel < 4) { + k = 0x8f; + } else { + k = 0x80; + } + + if(!hold_bit) { + hold_bit = 0; + } else { + hold_bit = 0x10; + } + k = num_parcel ^ k; + p[7] = k; + p[8] = hold_bit ^ (k << 4); + + crc = subghz_protocol_nice_one_crc(p); + + p[8] |= crc >> 4; + p[9] = crc << 4; +} + /** * Read bytes from rainbow table * @param file_name Full path to rainbow table the file @@ -427,10 +533,14 @@ void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_ subghz_protocol_nice_flor_s_const.te_delta) { //Found STOP bit instance->decoder.parser_step = NiceFlorSDecoderStepReset; - if(instance->decoder.decode_count_bit == - subghz_protocol_nice_flor_s_const.min_count_bit_for_found) { - instance->generic.data = instance->decoder.decode_data; + if((instance->decoder.decode_count_bit == + subghz_protocol_nice_flor_s_const.min_count_bit_for_found) || + (instance->decoder.decode_count_bit == NICE_ONE_COUNT_BIT)) { + instance->generic.data = instance->data; + instance->data = instance->decoder.decode_data; + instance->decoder.decode_data = instance->generic.data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; + if(instance->base.callback) instance->base.callback(&instance->base, instance->base.context); } @@ -464,6 +574,11 @@ void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_ } else { instance->decoder.parser_step = NiceFlorSDecoderStepReset; } + if(instance->decoder.decode_count_bit == + subghz_protocol_nice_flor_s_const.min_count_bit_for_found) { + instance->data = instance->decoder.decode_data; + instance->decoder.decode_data = 0; + } break; } } @@ -477,6 +592,7 @@ static void subghz_protocol_nice_flor_s_remote_controller( SubGhzBlockGeneric* instance, const char* file_name) { /* + * Protocol Nice Flor-S * Packet format Nice Flor-s: START-P0-P1-P2-P3-P4-P5-P6-P7-STOP * P0 (4-bit) - button positional code - 1:0x1, 2:0x2, 3:0x4, 4:0x8; * P1 (4-bit) - batch repetition number, calculated by the formula: @@ -497,6 +613,24 @@ static void subghz_protocol_nice_flor_s_remote_controller( * data => 0x1c5783607f7b3 key serial cnt * decrypt => 0x10436c6820444 => 0x1 0436c682 0444 * + * Protocol Nice One + * Generally repeats the Nice Flor-S protocol, but there are a few changes + * Packet format first 52 bytes repeat Nice Flor-S protocol + * The additional 20 bytes contain the code of the pressed button, + * the button hold bit and the CRC of the entire message. + * START-P0-P1-P2-P3-P4-P5-P6-P7-P8-P9-P10-STOP + * P7 (byte) - if (n<4) k=0x8f : k=0x80; P7= k^n; + * P8 (byte) - if (hold bit) b=0x00 : b=0x10; P8= b^(k<<4) | 4 hi bit crc + * P10 (4-bit) - 4 lo bit crc + * key+b crc + * data => 0x1724A7D9A522F 899 D6 hold bit = 0 - just pressed the button + * data => 0x1424A7D9A522F 8AB 03 hold bit = 1 - button hold + * + * A small button hold counter (0..15) is stored between each press, + * i.e. if 1 press of the button stops counter 6, then the next press + * of the button will start from the value 7 (hold bit = 0), 8 (hold bit = 1)... + * further up to 15 with overflow + * */ if(!file_name) { instance->cnt = 0; @@ -523,7 +657,15 @@ bool subghz_protocol_decoder_nice_flor_s_serialize( SubGhzRadioPreset* preset) { furi_assert(context); SubGhzProtocolDecoderNiceFlorS* instance = context; - return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { + if(res && + !flipper_format_write_uint32(flipper_format, "Data", (uint32_t*)&instance->data, 1)) { + FURI_LOG_E(TAG, "Unable to add Data"); + res = false; + } + } + return res; } bool subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format) { @@ -534,11 +676,25 @@ bool subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperForma if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { break; } - if(instance->generic.data_count_bit != - subghz_protocol_nice_flor_s_const.min_count_bit_for_found) { + if((instance->generic.data_count_bit != + subghz_protocol_nice_flor_s_const.min_count_bit_for_found) && + (instance->generic.data_count_bit != NICE_ONE_COUNT_BIT)) { FURI_LOG_E(TAG, "Wrong number of bits in key"); break; } + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint32_t temp = 0; + if(!flipper_format_read_uint32(flipper_format, "Data", (uint32_t*)&temp, 1)) { + FURI_LOG_E(TAG, "Missing Data"); + break; + } + instance->data = (uint64_t)temp; + } + ret = true; } while(false); return ret; @@ -550,20 +706,33 @@ void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* o subghz_protocol_nice_flor_s_remote_controller( &instance->generic, instance->nice_flor_s_rainbow_table_file_name); - uint32_t code_found_hi = instance->generic.data >> 32; - uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff; - furi_string_cat_printf( - output, - "%s %dbit\r\n" - "Key:0x%lX%08lX\r\n" - "Sn:%05lX\r\n" - "Cnt:%04lX Btn:%02X\r\n", - instance->generic.protocol_name, - instance->generic.data_count_bit, - code_found_hi, - code_found_lo, - instance->generic.serial, - instance->generic.cnt, - instance->generic.btn); -} + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:0x%013llX%llX\r\n" + "Sn:%05lX\r\n" + "Cnt:%04lX Btn:%02X\r\n", + NICE_ONE_NAME, + instance->generic.data_count_bit, + instance->generic.data, + instance->data, + instance->generic.serial, + instance->generic.cnt, + instance->generic.btn); + } else { + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:0x%013llX\r\n" + "Sn:%05lX\r\n" + "Cnt:%04lX Btn:%02X\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + instance->generic.data, + instance->generic.serial, + instance->generic.cnt, + instance->generic.btn); + } +} \ No newline at end of file diff --git a/lib/subghz/protocols/princeton_for_testing.c b/lib/subghz/protocols/princeton_for_testing.c index fa5616020..478d14cdf 100644 --- a/lib/subghz/protocols/princeton_for_testing.c +++ b/lib/subghz/protocols/princeton_for_testing.c @@ -1,6 +1,6 @@ #include "princeton_for_testing.h" -#include "furi_hal.h" +#include #include "../blocks/math.h" /* diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 5f733d6bd..74244c5ff 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -1,21 +1,50 @@ #include "protocol_items.h" const SubGhzProtocol* subghz_protocol_registry_items[] = { - &subghz_protocol_gate_tx, &subghz_protocol_keeloq, &subghz_protocol_star_line, - &subghz_protocol_nice_flo, &subghz_protocol_came, &subghz_protocol_faac_slh, - &subghz_protocol_nice_flor_s, &subghz_protocol_came_twee, &subghz_protocol_came_atomo, - &subghz_protocol_nero_sketch, &subghz_protocol_ido, &subghz_protocol_kia, - &subghz_protocol_hormann, &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis, - &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton, - &subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2, - &subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek, - &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec, - &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2, - &subghz_protocol_honeywell_wdb, &subghz_protocol_magellan, &subghz_protocol_intertechno_v3, - &subghz_protocol_clemsa, &subghz_protocol_ansonic, &subghz_protocol_pocsag, - &subghz_protocol_smc5326, &subghz_protocol_holtek_th12x, + &subghz_protocol_gate_tx, + &subghz_protocol_keeloq, + &subghz_protocol_star_line, + &subghz_protocol_nice_flo, + &subghz_protocol_came, + &subghz_protocol_faac_slh, + &subghz_protocol_nice_flor_s, + &subghz_protocol_came_twee, + &subghz_protocol_came_atomo, + &subghz_protocol_nero_sketch, + &subghz_protocol_ido, + &subghz_protocol_kia, + &subghz_protocol_hormann, + &subghz_protocol_nero_radio, + &subghz_protocol_somfy_telis, + &subghz_protocol_somfy_keytis, + &subghz_protocol_scher_khan, + &subghz_protocol_princeton, + &subghz_protocol_raw, + &subghz_protocol_linear, + &subghz_protocol_secplus_v2, + &subghz_protocol_secplus_v1, + &subghz_protocol_megacode, + &subghz_protocol_holtek, + &subghz_protocol_chamb_code, + &subghz_protocol_power_smart, + &subghz_protocol_marantec, + &subghz_protocol_bett, + &subghz_protocol_doitrand, + &subghz_protocol_phoenix_v2, + &subghz_protocol_honeywell_wdb, + &subghz_protocol_magellan, + &subghz_protocol_intertechno_v3, + &subghz_protocol_clemsa, + &subghz_protocol_ansonic, + &subghz_protocol_smc5326, + &subghz_protocol_holtek_th12x, + &subghz_protocol_linear_delta3, + &subghz_protocol_dooya, + &subghz_protocol_alutech_at_4n, + &subghz_protocol_kinggates_stylo_4k, + &subghz_protocol_bin_raw, }; const SubGhzProtocolRegistry subghz_protocol_registry = { .items = subghz_protocol_registry_items, - .size = COUNT_OF(subghz_protocol_registry_items)}; \ No newline at end of file + .size = COUNT_OF(subghz_protocol_registry_items)}; diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 55a1ea860..b7e082bf5 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -21,6 +21,7 @@ #include "gate_tx.h" #include "raw.h" #include "linear.h" +#include "linear_delta3.h" #include "secplus_v2.h" #include "secplus_v1.h" #include "megacode.h" @@ -36,9 +37,12 @@ #include "intertechno_v3.h" #include "clemsa.h" #include "ansonic.h" -#include "pocsag.h" #include "smc5326.h" #include "holtek_ht12x.h" +#include "dooya.h" +#include "alutech_at_4n.h" +#include "kinggates_stylo_4k.h" +#include "bin_raw.h" #ifdef __cplusplus extern "C" { diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index 393d7f360..01a229047 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -8,16 +8,11 @@ #include "../blocks/generic.h" #include "../blocks/math.h" -#include #include #include -#include #define TAG "SubGhzProtocolRAW" #define SUBGHZ_DOWNLOAD_MAX_SIZE 512 -#define SUBGHZ_AUTO_DETECT_DOWNLOAD_MAX_SIZE 2048 -#define SUBGHZ_AUTO_DETECT_RAW_THRESHOLD -72.0f -#define SUBGHZ_AUTO_DETECT_RAW_POSTROLL_FRAMES 40 static const SubGhzBlockConst subghz_protocol_raw_const = { .te_short = 50, @@ -29,8 +24,6 @@ static const SubGhzBlockConst subghz_protocol_raw_const = { struct SubGhzProtocolDecoderRAW { SubGhzProtocolDecoderBase base; - SubGhzBlockDecoder decoder; - int32_t* upload_raw; uint16_t ind_write; Storage* storage; @@ -39,10 +32,6 @@ struct SubGhzProtocolDecoderRAW { FuriString* file_name; size_t sample_write; bool last_level; - bool auto_mode; - bool has_rssi_above_threshold; - int rssi_threshold; - uint8_t postroll_frames; bool pause; }; @@ -67,8 +56,8 @@ const SubGhzProtocolDecoder subghz_protocol_raw_decoder = { .feed = subghz_protocol_decoder_raw_feed, .reset = subghz_protocol_decoder_raw_reset, - .get_hash_data = subghz_protocol_decoder_raw_get_hash_data, - .serialize = subghz_protocol_decoder_raw_serialize, + .get_hash_data = NULL, + .serialize = NULL, .deserialize = subghz_protocol_decoder_raw_deserialize, .get_string = subghz_protocol_decoder_raw_get_string, }; @@ -213,36 +202,6 @@ void subghz_protocol_raw_save_to_file_stop(SubGhzProtocolDecoderRAW* instance) { instance->file_is_open = RAWFileIsOpenClose; } -void subghz_protocol_decoder_raw_set_rssi_threshold(void* context, int rssi_threshold) { - furi_assert(context); - SubGhzProtocolDecoderRAW* instance = context; - - FURI_LOG_D(TAG, "RSSI set: (%d)", rssi_threshold); - - instance->rssi_threshold = rssi_threshold; - - subghz_protocol_decoder_raw_reset(context); -} - -void subghz_protocol_decoder_raw_set_auto_mode(void* context, bool auto_mode) { - furi_assert(context); - SubGhzProtocolDecoderRAW* instance = context; - instance->auto_mode = auto_mode; - - if(auto_mode) { - if(instance->upload_raw == NULL) { - instance->upload_raw = malloc(SUBGHZ_AUTO_DETECT_DOWNLOAD_MAX_SIZE * sizeof(int32_t)); - } - } else { - if(instance->upload_raw != NULL) { - free(instance->upload_raw); - instance->upload_raw = NULL; - } - } - - subghz_protocol_decoder_raw_reset(context); -} - void subghz_protocol_raw_save_to_file_pause(SubGhzProtocolDecoderRAW* instance, bool pause) { furi_assert(instance); @@ -263,8 +222,6 @@ void* subghz_protocol_decoder_raw_alloc(SubGhzEnvironment* environment) { instance->ind_write = 0; instance->last_level = false; instance->file_is_open = RAWFileIsOpenClose; - instance->postroll_frames = 0; - instance->rssi_threshold = SUBGHZ_AUTO_DETECT_RAW_THRESHOLD; instance->file_name = furi_string_alloc(); return instance; @@ -274,10 +231,6 @@ void subghz_protocol_decoder_raw_free(void* context) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; furi_string_free(instance->file_name); - if(instance->upload_raw != NULL) { - free(instance->upload_raw); - instance->upload_raw = NULL; - } free(instance); } @@ -285,66 +238,23 @@ void subghz_protocol_decoder_raw_reset(void* context) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; instance->ind_write = 0; - instance->has_rssi_above_threshold = false; instance->last_level = false; - instance->postroll_frames = 0; -} - -bool subghz_protocol_decoder_raw_write_data(void* context, bool level, uint32_t duration) { - furi_assert(context); - SubGhzProtocolDecoderRAW* instance = context; - - bool wrote_data = false; - - if(instance->last_level != level) { - instance->last_level = (level ? true : false); - instance->upload_raw[instance->ind_write++] = (level ? duration : -duration); - subghz_protocol_blocks_add_bit(&instance->decoder, (level) ? 1 : 0); - wrote_data = true; - } - - if(instance->ind_write == SUBGHZ_AUTO_DETECT_DOWNLOAD_MAX_SIZE) { - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); - - return false; - } - - return wrote_data; } void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t duration) { furi_assert(context); SubGhzProtocolDecoderRAW* instance = context; - if(instance->upload_raw != NULL && !instance->pause && - duration > subghz_protocol_raw_const.te_short) { - if(instance->auto_mode) { - float rssi = furi_hal_subghz_get_rssi(); - - if(rssi >= instance->rssi_threshold) { - subghz_protocol_decoder_raw_write_data(context, level, duration); - instance->has_rssi_above_threshold = true; - instance->postroll_frames = 0; - } else if(instance->has_rssi_above_threshold) { - subghz_protocol_decoder_raw_write_data(instance, level, duration); - instance->postroll_frames++; - - if(instance->postroll_frames >= SUBGHZ_AUTO_DETECT_RAW_POSTROLL_FRAMES) { - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); - } - } - } else { + if(!instance->pause && (instance->upload_raw != NULL)) { + if(duration > subghz_protocol_raw_const.te_short) { if(instance->last_level != level) { instance->last_level = (level ? true : false); instance->upload_raw[instance->ind_write++] = (level ? duration : -duration); - subghz_protocol_blocks_add_bit(&instance->decoder, (level) ? 1 : 0); } + } - if(instance->ind_write == SUBGHZ_DOWNLOAD_MAX_SIZE) { - subghz_protocol_raw_save_to_file_write(instance); - } + if(instance->ind_write == SUBGHZ_DOWNLOAD_MAX_SIZE) { + subghz_protocol_raw_save_to_file_write(instance); } } } @@ -357,13 +267,6 @@ bool subghz_protocol_decoder_raw_deserialize(void* context, FlipperFormat* flipp return true; } -uint8_t subghz_protocol_decoder_raw_get_hash_data(void* context) { - furi_assert(context); - SubGhzProtocolDecoderRAW* instance = context; - return subghz_protocol_blocks_get_hash_data( - &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); -} - void subghz_protocol_decoder_raw_get_string(void* context, FuriString* output) { furi_assert(context); //SubGhzProtocolDecoderRAW* instance = context; @@ -382,13 +285,6 @@ void* subghz_protocol_encoder_raw_alloc(SubGhzEnvironment* environment) { return instance; } -int subghz_protocol_encoder_get_rssi_threshold(void* context) { - furi_assert(context); - SubGhzProtocolDecoderRAW* instance = context; - - return instance->rssi_threshold; -} - void subghz_protocol_encoder_raw_stop(void* context) { SubGhzProtocolEncoderRAW* instance = context; instance->is_running = false; @@ -446,70 +342,6 @@ void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* } while(false); } -bool subghz_protocol_decoder_raw_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset) { - furi_assert(context); - SubGhzProtocolDecoderRAW* instance = context; - if(instance->auto_mode) { - furi_assert(instance); - bool res = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); - - do { - stream_clean(flipper_format_get_raw_stream(flipper_format)); - if(!flipper_format_write_header_cstr( - flipper_format, SUBGHZ_RAW_FILE_TYPE, SUBGHZ_RAW_FILE_VERSION)) { - FURI_LOG_E(TAG, "Unable to add header"); - break; - } - - if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) { - FURI_LOG_E(TAG, "Unable to add Frequency"); - break; - } - subghz_block_generic_get_preset_name(furi_string_get_cstr(preset->name), temp_str); - if(!flipper_format_write_string_cstr( - flipper_format, "Preset", furi_string_get_cstr(temp_str))) { - FURI_LOG_E(TAG, "Unable to add Preset"); - break; - } - if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { - if(!flipper_format_write_string_cstr( - flipper_format, "Custom_preset_module", "CC1101")) { - FURI_LOG_E(TAG, "Unable to add Custom_preset_module"); - break; - } - if(!flipper_format_write_hex( - flipper_format, "Custom_preset_data", preset->data, preset->data_size)) { - FURI_LOG_E(TAG, "Unable to add Custom_preset_data"); - break; - } - } - if(!flipper_format_write_string_cstr( - flipper_format, "Protocol", instance->base.protocol->name)) { - FURI_LOG_E(TAG, "Unable to add Protocol"); - break; - } - - if(!flipper_format_write_int32( - flipper_format, "RAW_Data", instance->upload_raw, instance->ind_write)) { - FURI_LOG_E(TAG, "Unable to add Raw Data"); - break; - } else { - instance->ind_write = 0; - } - res = true; - } while(false); - furi_string_free(temp_str); - return res; - } else { - return false; - } -} - bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format) { furi_assert(context); SubGhzProtocolEncoderRAW* instance = context; diff --git a/lib/subghz/protocols/raw.h b/lib/subghz/protocols/raw.h index 08efff50e..44c7faec5 100644 --- a/lib/subghz/protocols/raw.h +++ b/lib/subghz/protocols/raw.h @@ -2,8 +2,6 @@ #include "base.h" -#include - #define SUBGHZ_PROTOCOL_RAW_NAME "RAW" #ifdef __cplusplus @@ -31,27 +29,6 @@ bool subghz_protocol_raw_save_to_file_init( const char* dev_name, SubGhzRadioPreset* preset); -/** - * Set SubGhzProtocolDecoderRAW to auto mode, which allows subghz_scene_receiver to capture RAW. - * @param context Pointer to a SubGhzProtocolDecoderRAW instance - * @param auto_mode Whether or not to enable auto mode - */ -void subghz_protocol_decoder_raw_set_auto_mode(void* context, bool auto_mode); - -/** - * Set RSSI threshold ("sensitivity" level). - * @param context Pointer to a SubGhzProtocolDecoderRAW instance - * @param rssi_threshold The desired RSSI threshold - */ -void subghz_protocol_decoder_raw_set_rssi_threshold(void* context, int rssi_threshold); - -/** - * Get RSSI threshold ("sensitivity" level). - * @param context Pointer to a SubGhzProtocolDecoderRAW instance - * @return rssi threshold in db - */ -int subghz_protocol_encoder_get_rssi_threshold(void* context); - /** * Stop writing file to flash * @param instance Pointer to a SubGhzProtocolDecoderRAW instance @@ -84,15 +61,6 @@ void subghz_protocol_decoder_raw_free(void* context); */ void subghz_protocol_decoder_raw_reset(void* context); -/** - * Write raw data to the instance's internal buffer. - * @param context Pointer to a SubGhzProtocolDecoderRAW instance - * @param level Signal level true-high false-low - * @param duration Duration of this level in, us - * @return whether or not data was written - */ -bool subghz_protocol_decoder_raw_write_data(void* context, bool level, uint32_t duration); - /** * Parse a raw sequence of levels and durations received from the air. * @param context Pointer to a SubGhzProtocolDecoderRAW instance @@ -103,19 +71,12 @@ void subghz_protocol_decoder_raw_feed(void* context, bool level, uint32_t durati /** * Deserialize data SubGhzProtocolDecoderRAW. - * @param context Pointer to a SubGhzProtocolDecoderRAW instance - * @param flipper_format Pointer to a FlipperFormat instance + * @param context Pointer to a SubGhzProtocolDecoderRAW instance + * @param flipper_format Pointer to a FlipperFormat instance * @return true On success */ bool subghz_protocol_decoder_raw_deserialize(void* context, FlipperFormat* flipper_format); -/** - * Getting the hash sum of the last randomly received parcel. - * @param context Pointer to a SubGhzProtocolDecoderRAW instance - * @return hash Hash sum - */ -uint8_t subghz_protocol_decoder_raw_get_hash_data(void* context); - /** * Getting a textual representation of the received data. * @param context Pointer to a SubGhzProtocolDecoderRAW instance @@ -167,19 +128,6 @@ void subghz_protocol_raw_file_encoder_worker_set_callback_end( */ void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path); -/** - * Serialize data SubGhzProtocolDecoderRAW. - * @param context Pointer to a SubGhzProtocolDecoderRAW instance - * @param flipper_format Pointer to a FlipperFormat instance - * @param frequency The frequency at which the signal was received, Hz - * @param preset The modulation on which the signal was received, FuriHalSubGhzPreset - * @return true On success - */ -bool subghz_protocol_decoder_raw_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset); - /** * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderRAW instance @@ -191,7 +139,7 @@ bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipp /** * Getting the level and duration of the upload to be loaded into DMA. * @param context Pointer to a SubGhzProtocolEncoderRAW instance - * @return LevelDuration + * @return LevelDuration */ LevelDuration subghz_protocol_encoder_raw_yield(void* context); diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index 9c3afeb46..3ef95db36 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -606,7 +606,7 @@ void subghz_protocol_decoder_secplus_v1_get_string(void* context, FuriString* ou furi_string_cat_printf( output, "Sn:0x%08lX\r\n" - "Cnt:0x%03lX\r\n" + "Cnt:0x%03lX " "Sw_id:0x%X\r\n", instance->generic.serial, instance->generic.cnt, @@ -625,7 +625,7 @@ void subghz_protocol_decoder_secplus_v1_get_string(void* context, FuriString* ou furi_string_cat_printf( output, "Sn:0x%08lX\r\n" - "Cnt:0x%03lX\r\n" + "Cnt:0x%03lX " "Sw_id:0x%X\r\n", instance->generic.serial, instance->generic.cnt, diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index 27a82beab..bcef90dad 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -261,16 +261,16 @@ static bool data = order << 4 | invert; int k = 0; for(int i = 6; i >= 0; i -= 2) { - roll_array[k++] = (data >> i) & 0x03; - if(roll_array[k] == 3) { + roll_array[k] = (data >> i) & 0x03; + if(roll_array[k++] == 3) { FURI_LOG_E(TAG, "Roll_Array FAIL"); return false; } } for(int i = 8; i >= 0; i -= 2) { - roll_array[k++] = (p[2] >> i) & 0x03; - if(roll_array[k] == 3) { + roll_array[k] = (p[2] >> i) & 0x03; + if(roll_array[k++] == 3) { FURI_LOG_E(TAG, "Roll_Array FAIL"); return false; } diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index 63a3e26d2..ab9202cc3 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -55,25 +55,40 @@ const SubGhzProtocolDecoder subghz_protocol_somfy_keytis_decoder = { .get_string = subghz_protocol_decoder_somfy_keytis_get_string, }; -const SubGhzProtocolEncoder subghz_protocol_somfy_keytis_encoder = { - .alloc = NULL, - .free = NULL, - - .deserialize = NULL, - .stop = NULL, - .yield = NULL, -}; - const SubGhzProtocol subghz_protocol_somfy_keytis = { .name = SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME, .type = SubGhzProtocolTypeDynamic, .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM | - SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save, + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, .decoder = &subghz_protocol_somfy_keytis_decoder, .encoder = &subghz_protocol_somfy_keytis_encoder, }; +const SubGhzProtocolEncoder subghz_protocol_somfy_keytis_encoder = { + .alloc = subghz_protocol_encoder_somfy_keytis_alloc, + .free = subghz_protocol_encoder_somfy_keytis_free, + + .deserialize = subghz_protocol_encoder_somfy_keytis_deserialize, + .stop = subghz_protocol_encoder_somfy_keytis_stop, + .yield = subghz_protocol_encoder_somfy_keytis_yield, +}; + +void* subghz_protocol_encoder_somfy_keytis_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderSomfyKeytis* instance = malloc(sizeof(SubGhzProtocolEncoderSomfyKeytis)); + + instance->base.protocol = &subghz_protocol_somfy_keytis; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 512; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + + return instance; +} + void* subghz_protocol_decoder_somfy_keytis_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolDecoderSomfyKeytis* instance = malloc(sizeof(SubGhzProtocolDecoderSomfyKeytis)); @@ -83,6 +98,13 @@ void* subghz_protocol_decoder_somfy_keytis_alloc(SubGhzEnvironment* environment) return instance; } +void subghz_protocol_encoder_somfy_keytis_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderSomfyKeytis* instance = context; + free(instance->encoder.upload); + free(instance); +} + void subghz_protocol_decoder_somfy_keytis_free(void* context) { furi_assert(context); SubGhzProtocolDecoderSomfyKeytis* instance = context; @@ -100,6 +122,330 @@ void subghz_protocol_decoder_somfy_keytis_reset(void* context) { NULL); } +static bool + subghz_protocol_somfy_keytis_gen_data(SubGhzProtocolEncoderSomfyKeytis* instance, uint8_t btn) { + UNUSED(btn); + uint64_t data = instance->generic.data ^ (instance->generic.data >> 8); + instance->generic.btn = (data >> 48) & 0xF; + instance->generic.cnt = (data >> 24) & 0xFFFF; + instance->generic.serial = data & 0xFFFFFF; + + if(instance->generic.cnt < 0xFFFF) { + instance->generic.cnt++; + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } + + uint8_t frame[10]; + frame[0] = (0xA << 4) | instance->generic.btn; + frame[1] = 0xF << 4; + frame[2] = instance->generic.cnt >> 8; + frame[3] = instance->generic.cnt; + frame[4] = instance->generic.serial >> 16; + frame[5] = instance->generic.serial >> 8; + frame[6] = instance->generic.serial; + frame[7] = 0xC4; + frame[8] = 0x00; + frame[9] = 0x19; + + uint8_t checksum = 0; + for(uint8_t i = 0; i < 7; i++) { + checksum = checksum ^ frame[i] ^ (frame[i] >> 4); + } + checksum &= 0xF; + + frame[1] |= checksum; + + for(uint8_t i = 1; i < 7; i++) { + frame[i] ^= frame[i - 1]; + } + data = 0; + for(uint8_t i = 0; i < 7; ++i) { + data <<= 8; + data |= frame[i]; + } + instance->generic.data = data; + data = 0; + for(uint8_t i = 7; i < 10; ++i) { + data <<= 8; + data |= frame[i]; + } + instance->generic.data_2 = data; + return true; +} + +bool subghz_protocol_somfy_keytis_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolEncoderSomfyKeytis* instance = context; + instance->generic.serial = serial; + instance->generic.cnt = cnt; + instance->generic.data_count_bit = 80; + bool res = subghz_protocol_somfy_keytis_gen_data(instance, btn); + if(res) { + res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + } + return res; +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance + * @return true On success + */ +static bool subghz_protocol_encoder_somfy_keytis_get_upload( + SubGhzProtocolEncoderSomfyKeytis* instance, + uint8_t btn) { + furi_assert(instance); + + //gen new key + if(subghz_protocol_somfy_keytis_gen_data(instance, btn)) { + //ToDo if you need to add a callback to automatically update the data on the display + } else { + return false; + } + + size_t index = 0; + + //Send header + //Wake up + instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)9415); // 1 + instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)89565); // 0 + //Hardware sync + for(uint8_t i = 0; i < 12; ++i) { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 4); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 4); // 0 + } + //Software sync + instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)4550); // 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + + //Send key data MSB manchester + + for(uint8_t i = instance->generic.data_count_bit - 24; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration *= 2; // 00 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + } + + } else { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) { + instance->encoder.upload[index - 1].duration *= 2; // 11 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + } else { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + } + } + } + + for(uint8_t i = 24; i > 0; i--) { + if(bit_read(instance->generic.data_2, i - 1)) { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration *= 2; // 00 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + } + + } else { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) { + instance->encoder.upload[index - 1].duration *= 2; // 11 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + } else { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + } + } + } + + //Inter-frame silence + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration += + (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3; + } else { + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3); + } + + for(uint8_t i = 0; i < 2; ++i) { + //Hardware sync + for(uint8_t i = 0; i < 6; ++i) { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 4); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 4); // 0 + } + //Software sync + instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)4550); // 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + + //Send key data MSB manchester + + for(uint8_t i = instance->generic.data_count_bit - 24; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration *= 2; // 00 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + } + + } else { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) { + instance->encoder.upload[index - 1].duration *= 2; // 11 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + } else { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + } + } + } + + for(uint8_t i = 24; i > 0; i--) { + if(bit_read(instance->generic.data_2, i - 1)) { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration *= 2; // 00 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + } + + } else { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) { + instance->encoder.upload[index - 1].duration *= 2; // 11 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + } else { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short); // 0 + } + } + } + //Inter-frame silence + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration += + (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3; + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3); + } + } + + //Inter-frame silence + instance->encoder.upload[index - 1].duration += + (uint32_t)30415 - (uint32_t)subghz_protocol_somfy_keytis_const.te_short * 3; + + size_t size_upload = index; + + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + return true; +} + +bool subghz_protocol_encoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderSomfyKeytis* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_somfy_keytis_get_upload(instance, instance->generic.btn); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Key"); + break; + } + + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_somfy_keytis_stop(void* context) { + SubGhzProtocolEncoderSomfyKeytis* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_somfy_keytis_yield(void* context) { + SubGhzProtocolEncoderSomfyKeytis* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + /** * Сhecksum calculation. * @param data Вata for checksum calculation diff --git a/lib/subghz/protocols/somfy_keytis.h b/lib/subghz/protocols/somfy_keytis.h index 3b5950611..b08da3641 100644 --- a/lib/subghz/protocols/somfy_keytis.h +++ b/lib/subghz/protocols/somfy_keytis.h @@ -11,6 +11,58 @@ extern const SubGhzProtocolDecoder subghz_protocol_somfy_keytis_decoder; extern const SubGhzProtocolEncoder subghz_protocol_somfy_keytis_encoder; extern const SubGhzProtocol subghz_protocol_somfy_keytis; +/** + * Allocate SubGhzProtocolEncoderSomfyKeytis. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderSomfyKeytis* pointer to a SubGhzProtocolEncoderSomfyKeytis instance + */ +void* subghz_protocol_encoder_somfy_keytis_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderSomfyKeytis. + * @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance + */ +void subghz_protocol_encoder_somfy_keytis_free(void* context); + +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 24 bit + * @param btn Button number, 8 bit + * @param cnt Counter value, 16 bit + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_somfy_keytis_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_somfy_keytis_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance + */ +void subghz_protocol_encoder_somfy_keytis_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderSomfyKeytis instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_somfy_keytis_yield(void* context); + /** * Allocate SubGhzProtocolDecoderSomfyKeytis. * @param environment Pointer to a SubGhzEnvironment instance diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 945a88405..96997c581 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -55,24 +55,301 @@ const SubGhzProtocolDecoder subghz_protocol_somfy_telis_decoder = { }; const SubGhzProtocolEncoder subghz_protocol_somfy_telis_encoder = { - .alloc = NULL, - .free = NULL, + .alloc = subghz_protocol_encoder_somfy_telis_alloc, + .free = subghz_protocol_encoder_somfy_telis_free, - .deserialize = NULL, - .stop = NULL, - .yield = NULL, + .deserialize = subghz_protocol_encoder_somfy_telis_deserialize, + .stop = subghz_protocol_encoder_somfy_telis_stop, + .yield = subghz_protocol_encoder_somfy_telis_yield, }; const SubGhzProtocol subghz_protocol_somfy_telis = { .name = SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME, .type = SubGhzProtocolTypeDynamic, .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM | - SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save, + SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, .decoder = &subghz_protocol_somfy_telis_decoder, .encoder = &subghz_protocol_somfy_telis_encoder, }; +void* subghz_protocol_encoder_somfy_telis_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderSomfyTelis* instance = malloc(sizeof(SubGhzProtocolEncoderSomfyTelis)); + + instance->base.protocol = &subghz_protocol_somfy_telis; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 512; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + + return instance; +} + +void subghz_protocol_encoder_somfy_telis_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderSomfyTelis* instance = context; + free(instance->encoder.upload); + free(instance); +} + +static bool + subghz_protocol_somfy_telis_gen_data(SubGhzProtocolEncoderSomfyTelis* instance, uint8_t btn) { + UNUSED(btn); + uint64_t data = instance->generic.data ^ (instance->generic.data >> 8); + instance->generic.btn = (data >> 44) & 0xF; // ctrl + instance->generic.cnt = (data >> 24) & 0xFFFF; // rolling code + instance->generic.serial = data & 0xFFFFFF; // address + + if(instance->generic.cnt < 0xFFFF) { + instance->generic.cnt++; + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } + + uint8_t frame[7]; + frame[0] = data >> 48; + frame[1] = instance->generic.btn << 4; + frame[2] = instance->generic.cnt >> 8; + frame[3] = instance->generic.cnt; + frame[4] = instance->generic.serial >> 16; + frame[5] = instance->generic.serial >> 8; + frame[6] = instance->generic.serial; + + uint8_t checksum = 0; + for(uint8_t i = 0; i < 7; i++) { + checksum = checksum ^ frame[i] ^ (frame[i] >> 4); + } + checksum &= 0xF; + + frame[1] |= checksum; + + for(uint8_t i = 1; i < 7; i++) { + frame[i] ^= frame[i - 1]; + } + data = 0; + for(uint8_t i = 0; i < 7; ++i) { + data <<= 8; + data |= frame[i]; + } + instance->generic.data = data; + return true; +} + +bool subghz_protocol_somfy_telis_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolEncoderSomfyTelis* instance = context; + instance->generic.serial = serial; + instance->generic.cnt = cnt; + instance->generic.data_count_bit = 56; + bool res = subghz_protocol_somfy_telis_gen_data(instance, btn); + if(res) { + res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); + } + return res; +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance + * @return true On success + */ +static bool subghz_protocol_encoder_somfy_telis_get_upload( + SubGhzProtocolEncoderSomfyTelis* instance, + uint8_t btn) { + furi_assert(instance); + + //gen new key + if(subghz_protocol_somfy_telis_gen_data(instance, btn)) { + //ToDo if you need to add a callback to automatically update the data on the display + } else { + return false; + } + + size_t index = 0; + + //Send header + //Wake up + instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)9415); // 1 + instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)89565); // 0 + //Hardware sync + for(uint8_t i = 0; i < 2; ++i) { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_telis_const.te_short * 4); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_telis_const.te_short * 4); // 0 + } + //Software sync + instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)4550); // 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 0 + + //Send key data MSB manchester + + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration *= 2; // 00 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 1 + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 0 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 1 + } + + } else { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) { + instance->encoder.upload[index - 1].duration *= 2; // 11 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 0 + } else { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 0 + } + } + } + + //Inter-frame silence + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration += (uint32_t)30415; + } else { + instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)30415); + } + + //Retransmission + for(uint8_t i = 0; i < 2; i++) { + //Hardware sync + for(uint8_t i = 0; i < 7; ++i) { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_telis_const.te_short * 4); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_telis_const.te_short * 4); // 0 + } + //Software sync + instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)4550); // 1 + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 0 + + //Send key data MSB manchester + + for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) { + if(bit_read(instance->generic.data, i - 1)) { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration *= 2; // 00 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 1 + } else { + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 0 + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 1 + } + + } else { + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_HIGH) { + instance->encoder.upload[index - 1].duration *= 2; // 11 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 0 + } else { + instance->encoder.upload[index++] = level_duration_make( + true, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 1 + instance->encoder.upload[index++] = level_duration_make( + false, (uint32_t)subghz_protocol_somfy_telis_const.te_short); // 0 + } + } + } + + //Inter-frame silence + if(instance->encoder.upload[index - 1].level == LEVEL_DURATION_LEVEL_LOW) { + instance->encoder.upload[index - 1].duration += (uint32_t)30415; + } else { + instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)30415); + } + } + + size_t size_upload = index; + + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + return true; +} + +bool subghz_protocol_encoder_somfy_telis_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderSomfyTelis* instance = context; + bool res = false; + do { + if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { + FURI_LOG_E(TAG, "Deserialize error"); + break; + } + + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + subghz_protocol_encoder_somfy_telis_get_upload(instance, instance->generic.btn); + + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + uint8_t key_data[sizeof(uint64_t)] = {0}; + for(size_t i = 0; i < sizeof(uint64_t); i++) { + key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF; + } + if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) { + FURI_LOG_E(TAG, "Unable to add Key"); + break; + } + + instance->encoder.is_running = true; + + res = true; + } while(false); + + return res; +} + +void subghz_protocol_encoder_somfy_telis_stop(void* context) { + SubGhzProtocolEncoderSomfyTelis* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_somfy_telis_yield(void* context) { + SubGhzProtocolEncoderSomfyTelis* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + void* subghz_protocol_decoder_somfy_telis_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolDecoderSomfyTelis* instance = malloc(sizeof(SubGhzProtocolDecoderSomfyTelis)); @@ -299,9 +576,9 @@ static void subghz_protocol_somfy_telis_check_remote_controller(SubGhzBlockGener */ uint64_t data = instance->data ^ (instance->data >> 8); - instance->btn = (data >> 44) & 0xF; - instance->cnt = (data >> 24) & 0xFFFF; - instance->serial = data & 0xFFFFFF; + instance->btn = (data >> 44) & 0xF; // ctrl + instance->cnt = (data >> 24) & 0xFFFF; // rolling code + instance->serial = data & 0xFFFFFF; // address } /** @@ -309,7 +586,7 @@ static void subghz_protocol_somfy_telis_check_remote_controller(SubGhzBlockGener * @param btn Button number, 4 bit */ static const char* subghz_protocol_somfy_telis_get_name_button(uint8_t btn) { - const char* name_btn[0x10] = { + const char* name_btn[16] = { "Unknown", "My", "Up", @@ -368,7 +645,6 @@ void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* o SubGhzProtocolDecoderSomfyTelis* instance = context; subghz_protocol_somfy_telis_check_remote_controller(&instance->generic); - furi_string_cat_printf( output, "%s %db\r\n" diff --git a/lib/subghz/protocols/somfy_telis.h b/lib/subghz/protocols/somfy_telis.h index a6a9fa5b2..b5e989866 100644 --- a/lib/subghz/protocols/somfy_telis.h +++ b/lib/subghz/protocols/somfy_telis.h @@ -11,6 +11,58 @@ extern const SubGhzProtocolDecoder subghz_protocol_somfy_telis_decoder; extern const SubGhzProtocolEncoder subghz_protocol_somfy_telis_encoder; extern const SubGhzProtocol subghz_protocol_somfy_telis; +/** + * Allocate SubGhzProtocolEncoderSomfyTelis. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderSomfyTelis* pointer to a SubGhzProtocolEncoderSomfyTelis instance + */ +void* subghz_protocol_encoder_somfy_telis_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderSomfyTelis. + * @param context Pointer to a SubGhzProtocolEncoderSomfyTelis instance + */ +void subghz_protocol_encoder_somfy_telis_free(void* context); + +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderSomfyTelis instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 24 bit + * @param btn Button number, 8 bit + * @param cnt Counter value, 16 bit + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_somfy_telis_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + SubGhzRadioPreset* preset); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderSomfyTelis instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool subghz_protocol_encoder_somfy_telis_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderSomfyTelis instance + */ +void subghz_protocol_encoder_somfy_telis_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderSomfyTelis instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_somfy_telis_yield(void* context); + /** * Allocate SubGhzProtocolDecoderSomfyTelis. * @param environment Pointer to a SubGhzEnvironment instance diff --git a/lib/subghz/receiver.c b/lib/subghz/receiver.c index d7b422170..698fe098e 100644 --- a/lib/subghz/receiver.c +++ b/lib/subghz/receiver.c @@ -108,11 +108,6 @@ void subghz_receiver_set_filter(SubGhzReceiver* instance, SubGhzProtocolFlag fil instance->filter = filter; } -SubGhzProtocolFlag subghz_receiver_get_filter(SubGhzReceiver* instance) { - furi_assert(instance); - return instance->filter; -} - SubGhzProtocolDecoderBase* subghz_receiver_search_decoder_base_by_name( SubGhzReceiver* instance, const char* decoder_name) { diff --git a/lib/subghz/receiver.h b/lib/subghz/receiver.h index 15fc455fd..2ef722d1f 100644 --- a/lib/subghz/receiver.h +++ b/lib/subghz/receiver.h @@ -59,13 +59,6 @@ void subghz_receiver_set_rx_callback( */ void subghz_receiver_set_filter(SubGhzReceiver* instance, SubGhzProtocolFlag filter); -/** - * Get the filter of receivers that will work at the moment. - * @param instance Pointer to a SubGhzReceiver instance - * @return filter Filter, SubGhzProtocolFlag - */ -SubGhzProtocolFlag subghz_receiver_get_filter(SubGhzReceiver* instance); - /** * Search for a cattery by his name. * @param instance Pointer to a SubGhzReceiver instance diff --git a/lib/subghz/subghz_keystore.h b/lib/subghz/subghz_keystore.h index 06ae8adae..43f8356d0 100644 --- a/lib/subghz/subghz_keystore.h +++ b/lib/subghz/subghz_keystore.h @@ -77,4 +77,4 @@ bool subghz_keystore_raw_get_data(const char* file_name, size_t offset, uint8_t* #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 733fc35b5..05b6a74ad 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -39,6 +39,7 @@ static const uint32_t subghz_frequency_list[] = { 330000000, 345000000, 348000000, + 350000000, /* 387 - 464 */ 387000000, @@ -60,6 +61,7 @@ static const uint32_t subghz_frequency_list[] = { 438900000, 440175000, 464000000, + 467750000, /* 779 - 928 */ 779000000, @@ -75,10 +77,10 @@ static const uint32_t subghz_frequency_list[] = { }; static const uint32_t subghz_hopper_frequency_list[] = { - 310000000, 315000000, - 318000000, + 330000000, 390000000, + 433420000, 433920000, 868350000, 0, diff --git a/lib/subghz/subghz_tx_rx_worker.c b/lib/subghz/subghz_tx_rx_worker.c index 42124bebc..e380fc967 100644 --- a/lib/subghz/subghz_tx_rx_worker.c +++ b/lib/subghz/subghz_tx_rx_worker.c @@ -70,7 +70,7 @@ bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t* furi_delay_tick(1); } //waiting for reception to complete - while(furi_hal_gpio_read(&gpio_cc1101_g0)) { + while(furi_hal_gpio_read(furi_hal_subghz.cc1101_g0_pin)) { furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "RX cc1101_g0 timeout"); @@ -104,14 +104,16 @@ void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t si furi_hal_subghz_write_packet(data, size); furi_hal_subghz_tx(); //start send instance->status = SubGhzTxRxWorkerStatusTx; - while(!furi_hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be set -> sync transmitted + while(!furi_hal_gpio_read( + furi_hal_subghz.cc1101_g0_pin)) { // Wait for GDO0 to be set -> sync transmitted furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "TX !cc1101_g0 timeout"); break; } } - while(furi_hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be cleared -> end of packet + while(furi_hal_gpio_read( + furi_hal_subghz.cc1101_g0_pin)) { // Wait for GDO0 to be cleared -> end of packet furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "TX cc1101_g0 timeout"); @@ -134,7 +136,7 @@ static int32_t subghz_tx_rx_worker_thread(void* context) { furi_hal_subghz_idle(); furi_hal_subghz_load_preset(FuriHalSubGhzPresetGFSK9_99KbAsync); //furi_hal_subghz_load_preset(FuriHalSubGhzPresetMSK99_97KbAsync); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); furi_hal_subghz_set_frequency_and_path(instance->frequency); furi_hal_subghz_flush_rx(); @@ -233,7 +235,7 @@ bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) { instance->worker_running = true; - if(furi_hal_region_is_frequency_allowed(frequency)) { + if(furi_hal_subghz_is_tx_allowed(frequency)) { instance->frequency = frequency; res = true; } diff --git a/lib/subghz/types.h b/lib/subghz/types.h index 6c34dc728..9d121dc3c 100644 --- a/lib/subghz/types.h +++ b/lib/subghz/types.h @@ -77,6 +77,7 @@ typedef enum { SubGhzProtocolTypeRAW, SubGhzProtocolWeatherStation, SubGhzProtocolCustom, + SubGhzProtocolTypeBinRAW, } SubGhzProtocolType; typedef enum { @@ -90,6 +91,7 @@ typedef enum { SubGhzProtocolFlag_Save = (1 << 7), SubGhzProtocolFlag_Load = (1 << 8), SubGhzProtocolFlag_Send = (1 << 9), + SubGhzProtocolFlag_BinRAW = (1 << 10), } SubGhzProtocolFlag; typedef struct { diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index da6c1115c..9234f1e80 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -21,6 +21,7 @@ env.Append( File("saved_struct.h"), File("version.h"), File("float_tools.h"), + File("value_index.h"), File("tar/tar_archive.h"), File("stream/stream.h"), File("stream/file_stream.h"), diff --git a/lib/update_util/update_operation.c b/lib/update_util/update_operation.c index c6a9ccc5f..6e05b0233 100644 --- a/lib/update_util/update_operation.c +++ b/lib/update_util/update_operation.c @@ -21,8 +21,10 @@ static const char* update_prepare_result_descr[] = { [UpdatePrepareResultStageMissing] = "Missing Stage2 loader", [UpdatePrepareResultStageIntegrityError] = "Corrupted Stage2 loader", [UpdatePrepareResultManifestPointerError] = "Failed to create update pointer file", + [UpdatePrepareResultTargetMismatch] = "Hardware target mismatch", [UpdatePrepareResultOutdatedManifestVersion] = "Update package is too old", [UpdatePrepareResultIntFull] = "Need more free space in internal storage", + [UpdatePrepareResultUnspecifiedError] = "Unknown error", }; const char* update_operation_describe_preparation_result(const UpdatePrepareResult value) { @@ -163,8 +165,9 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) { result = UpdatePrepareResultOutdatedManifestVersion; break; } - - if(furi_hal_version_get_hw_target() != manifest->target) { + /* Only compare hardware target if it is set - pre-production devices accept any firmware*/ + if(furi_hal_version_get_hw_target() && + (furi_hal_version_get_hw_target() != manifest->target)) { result = UpdatePrepareResultTargetMismatch; break; } diff --git a/scripts/FlipperPlaylist.py b/scripts/FlipperPlaylist.py index 4a688f2fb..6db250717 100644 --- a/scripts/FlipperPlaylist.py +++ b/scripts/FlipperPlaylist.py @@ -1,12 +1,14 @@ # Flipper Zero SUB-GHZ Playlist Generator import os import pip + try: from easygui import diropenbox except ImportError: - pip.main(['Install'], "easygui") + pip.main(["Install"], "easygui") from easygui import diropenbox + def main(): folder_path = diropenbox("Select the folder with Subghz files", "Subghz selector") output_path = diropenbox("Select your output location", "Output location") @@ -23,5 +25,6 @@ def main(): playlist_file.close() print("Done!") -if __name__ == '__main__': - main() \ No newline at end of file + +if __name__ == "__main__": + main() diff --git a/scripts/User/decode.py b/scripts/User/decode.py index f6779d967..64072b82f 100644 --- a/scripts/User/decode.py +++ b/scripts/User/decode.py @@ -6,69 +6,85 @@ import os import sys - def padded_hex(i, l): given_int = i given_len = l - hex_result = hex(given_int)[2:] # remove '0x' from beginning of str + hex_result = hex(given_int)[2:] # remove '0x' from beginning of str num_hex_chars = len(hex_result) - extra_zeros = '0' * (given_len - num_hex_chars) # may not get used.. + extra_zeros = "0" * (given_len - num_hex_chars) # may not get used.. - return ('0x' + hex_result if num_hex_chars == given_len else - '?' * given_len if num_hex_chars > given_len else - '0x' + extra_zeros + hex_result if num_hex_chars < given_len else - None) + return ( + "0x" + hex_result + if num_hex_chars == given_len + else "?" * given_len + if num_hex_chars > given_len + else "0x" + extra_zeros + hex_result + if num_hex_chars < given_len + else None + ) -parser = argparse.ArgumentParser(description='Turn cooked Flipper .bm files back into .xbm') -parser.add_argument('infile', metavar='i', - help='Input file') -parser.add_argument('outfile', metavar='o', - help='File to write to') -parser.add_argument('Width', metavar='W', type=int, nargs="?", default="128", - help='Width of the image. Find from meta.txt or directory name') -parser.add_argument('Height', metavar='H', type=int, nargs="?", default="64", - help='Height of the image. Find from meta.txt or directory name') +parser = argparse.ArgumentParser( + description="Turn cooked Flipper .bm files back into .xbm" +) + +parser.add_argument("infile", metavar="i", help="Input file") +parser.add_argument("outfile", metavar="o", help="File to write to") +parser.add_argument( + "Width", + metavar="W", + type=int, + nargs="?", + default="128", + help="Width of the image. Find from meta.txt or directory name", +) +parser.add_argument( + "Height", + metavar="H", + type=int, + nargs="?", + default="64", + help="Height of the image. Find from meta.txt or directory name", +) args = vars(parser.parse_args()) -r = open(args["infile"],"rb") -w = open(args["outfile"],"w") +r = open(args["infile"], "rb") +w = open(args["outfile"], "w") -fileStream=r.read() -filename=os.path.splitext(os.path.basename(args["outfile"]))[0] +fileStream = r.read() +filename = os.path.splitext(os.path.basename(args["outfile"]))[0] -imageWidth=args["Width"] -imageHeight=args["Height"] +imageWidth = args["Width"] +imageHeight = args["Height"] -#remove headers and padding -if(fileStream[0:2] == bytes([0x01,0x00])): - unpad=fileStream[4:] +# remove headers and padding +if fileStream[0:2] == bytes([0x01, 0x00]): + unpad = fileStream[4:] else: - if(fileStream[0:1] == bytes([0x00])): - unpad=fileStream[2:] + if fileStream[0:1] == bytes([0x00]): + unpad = fileStream[2:] - -#lzss decompress +# lzss decompress data_decoded_str = subprocess.check_output( - ["heatshrink", "-d","-w8","-l4"], input=unpad + ["heatshrink", "-d", "-w8", "-l4"], input=unpad ) -#turn it back into xbm +# turn it back into xbm -b=list(data_decoded_str) -c=', '.join(padded_hex(my_int,2) for my_int in b) +b = list(data_decoded_str) +c = ", ".join(padded_hex(my_int, 2) for my_int in b) -width_out = "#define "+ filename+ "_width "+ str(imageWidth) + "\n" -height_out = "#define "+ filename+ "_height "+ str(imageHeight) + "\n" -bytes_out = "static unsigned char "+ filename+ "_bits[] = {"+ str(c) + "};" +width_out = "#define " + filename + "_width " + str(imageWidth) + "\n" +height_out = "#define " + filename + "_height " + str(imageHeight) + "\n" +bytes_out = "static unsigned char " + filename + "_bits[] = {" + str(c) + "};" -data=width_out+height_out+bytes_out +data = width_out + height_out + bytes_out w.write(data) r.close() -w.close() \ No newline at end of file +w.close() diff --git a/scripts/User/encode.py b/scripts/User/encode.py index d2d533ea3..d88ec25f1 100644 --- a/scripts/User/encode.py +++ b/scripts/User/encode.py @@ -6,17 +6,17 @@ import os import sys -parser = argparse.ArgumentParser(description='Turn .xbm files into cooked .bm files for flipper FS') +parser = argparse.ArgumentParser( + description="Turn .xbm files into cooked .bm files for flipper FS" +) -parser.add_argument('infile', metavar='i', - help='Input file') -parser.add_argument('outfile', metavar='o', - help='File to write to') +parser.add_argument("infile", metavar="i", help="Input file") +parser.add_argument("outfile", metavar="o", help="File to write to") args = vars(parser.parse_args()) -r = open(args["infile"],"r") -w = open(args["outfile"],"wb") +r = open(args["infile"], "r") +w = open(args["outfile"], "wb") output = subprocess.check_output(["cat", args["infile"]]) diff --git a/scripts/User/icondecode.py b/scripts/User/icondecode.py index 596545269..c1177bc18 100644 --- a/scripts/User/icondecode.py +++ b/scripts/User/icondecode.py @@ -5,60 +5,82 @@ import io import os import sys + def padded_hex(i, l): given_int = i given_len = l - hex_result = hex(given_int)[2:] # remove '0x' from beginning of str + hex_result = hex(given_int)[2:] # remove '0x' from beginning of str num_hex_chars = len(hex_result) - extra_zeros = '0' * (given_len - num_hex_chars) # may not get used.. + extra_zeros = "0" * (given_len - num_hex_chars) # may not get used.. - return ('0x' + hex_result if num_hex_chars == given_len else - '?' * given_len if num_hex_chars > given_len else - '0x' + extra_zeros + hex_result if num_hex_chars < given_len else - None) + return ( + "0x" + hex_result + if num_hex_chars == given_len + else "?" * given_len + if num_hex_chars > given_len + else "0x" + extra_zeros + hex_result + if num_hex_chars < given_len + else None + ) -parser = argparse.ArgumentParser(description='Turn icon char arrays back into .xbm') +parser = argparse.ArgumentParser(description="Turn icon char arrays back into .xbm") -parser.add_argument('infile', metavar='i', - help='Input file') -parser.add_argument('outfile', metavar='o', - help='File to write to') -parser.add_argument('Width', metavar='W', type=int, nargs="?", default="128", - help='Width of the image. Find from meta.txt or directory name') -parser.add_argument('Height', metavar='H', type=int, nargs="?", default="64", - help='Height of the image. Find from meta.txt or directory name') -parser.add_argument('Trim', metavar='T', type=int, nargs="?", default="8", - help='Number of bytes off the start/header to trim. Multiples of 2 required.') +parser.add_argument("infile", metavar="i", help="Input file") +parser.add_argument("outfile", metavar="o", help="File to write to") +parser.add_argument( + "Width", + metavar="W", + type=int, + nargs="?", + default="128", + help="Width of the image. Find from meta.txt or directory name", +) +parser.add_argument( + "Height", + metavar="H", + type=int, + nargs="?", + default="64", + help="Height of the image. Find from meta.txt or directory name", +) +parser.add_argument( + "Trim", + metavar="T", + type=int, + nargs="?", + default="8", + help="Number of bytes off the start/header to trim. Multiples of 2 required.", +) args = vars(parser.parse_args()) -r = open(args["infile"],"r") -w = open(args["outfile"],"w") -imageWidth=args["Width"] -imageHeight=args["Height"] -trimStart=args["Trim"] +r = open(args["infile"], "r") +w = open(args["outfile"], "w") +imageWidth = args["Width"] +imageHeight = args["Height"] +trimStart = args["Trim"] -output = subprocess.check_output(["cat", args["infile"]]) #yes this is terrible. +output = subprocess.check_output(["cat", args["infile"]]) # yes this is terrible. f = io.StringIO(output.decode().strip()) -data = f.read().strip().replace(";","").replace("{","").replace("}","") +data = f.read().strip().replace(";", "").replace("{", "").replace("}", "") data_str = data.replace(",", "").replace("0x", "") data_bin = bytearray.fromhex(data_str[trimStart:]) data_decoded_str = subprocess.check_output( - ["heatshrink", "-d","-w8","-l4"], input=data_bin + ["heatshrink", "-d", "-w8", "-l4"], input=data_bin ) -b=list(data_decoded_str) +b = list(data_decoded_str) -c=', '.join(padded_hex(my_int,2) for my_int in b) +c = ", ".join(padded_hex(my_int, 2) for my_int in b) -width_out = "#define icon_width "+ str(imageWidth) + "\n" -height_out = "#define icon_height "+ str(imageHeight) + "\n" -bytes_out = "static unsigned char icon_bits[] = {"+ str(c) + "};" +width_out = "#define icon_width " + str(imageWidth) + "\n" +height_out = "#define icon_height " + str(imageHeight) + "\n" +bytes_out = "static unsigned char icon_bits[] = {" + str(c) + "};" -data=width_out+height_out+bytes_out +data = width_out + height_out + bytes_out w.write(data) r.close() diff --git a/scripts/User/iconencode.py b/scripts/User/iconencode.py index 67ba05d1b..e41e597dd 100644 --- a/scripts/User/iconencode.py +++ b/scripts/User/iconencode.py @@ -5,64 +5,81 @@ import io import os import sys + def padded_hex(i, l): given_int = i given_len = l - hex_result = hex(given_int)[2:] # remove '0x' from beginning of str + hex_result = hex(given_int)[2:] # remove '0x' from beginning of str num_hex_chars = len(hex_result) - extra_zeros = '0' * (given_len - num_hex_chars) # may not get used.. + extra_zeros = "0" * (given_len - num_hex_chars) # may not get used.. - return ('0x' + hex_result if num_hex_chars == given_len else - '?' * given_len if num_hex_chars > given_len else - '0x' + extra_zeros + hex_result if num_hex_chars < given_len else - None) + return ( + "0x" + hex_result + if num_hex_chars == given_len + else "?" * given_len + if num_hex_chars > given_len + else "0x" + extra_zeros + hex_result + if num_hex_chars < given_len + else None + ) -parser = argparse.ArgumentParser(description='Turn icon char arrays back into .xbm') +parser = argparse.ArgumentParser(description="Turn icon char arrays back into .xbm") -parser.add_argument('infile', metavar='i', - help='Input file') -parser.add_argument('Width', metavar='W', type=int, nargs="?", default="128", - help='Width of the image. Find from meta.txt or directory name') -parser.add_argument('Height', metavar='H', type=int, nargs="?", default="64", - help='Height of the image. Find from meta.txt or directory name') +parser.add_argument("infile", metavar="i", help="Input file") +parser.add_argument( + "Width", + metavar="W", + type=int, + nargs="?", + default="128", + help="Width of the image. Find from meta.txt or directory name", +) +parser.add_argument( + "Height", + metavar="H", + type=int, + nargs="?", + default="64", + help="Height of the image. Find from meta.txt or directory name", +) args = vars(parser.parse_args()) -r = open(args["infile"],"r") -infile=args["infile"].split(".")[0] +r = open(args["infile"], "r") +infile = args["infile"].split(".")[0] -imageWidth=args["Width"] -imageHeight=args["Height"] -dims=str(imageWidth)+"x"+str(imageHeight) +imageWidth = args["Width"] +imageHeight = args["Height"] +dims = str(imageWidth) + "x" + str(imageHeight) -output = subprocess.check_output(["cat", args["infile"]]) #yes this is terrible. +output = subprocess.check_output(["cat", args["infile"]]) # yes this is terrible. f = io.StringIO(output.decode().strip()) -data = f.read().strip().replace(";","").replace("{","").replace("}","") +data = f.read().strip().replace(";", "").replace("{", "").replace("}", "") data_str = data.replace(",", "").replace("0x", "") data_bin = bytearray.fromhex(data_str) data_encoded_str = subprocess.check_output( - ["heatshrink", "-e","-w8","-l4"], input=data_bin + ["heatshrink", "-e", "-w8", "-l4"], input=data_bin ) -b=list(data_encoded_str) +b = list(data_encoded_str) -c=','.join(padded_hex(my_int,2) for my_int in b) +c = ",".join(padded_hex(my_int, 2) for my_int in b) # a bit ugly. -framename="_I_"+infile+"_"+dims +framename = "_I_" + infile + "_" + dims print(len(b)) -#d=len(b) +# d=len(b) # if b > 255 split 0x1234 into 0x34,0x12 -#d=hex(len(b)) +# d=hex(len(b)) -char_out = "const uint8_t "+framename+"_0[] = {"+ str(c) + ",};" -char_out2 = "const uint8_t "+framename+"[] = {"+framename+"_0};" -#data=bytes_out +char_out = "const uint8_t " + framename + "_0[] = {" + str(c) + ",};" +char_out2 = "const uint8_t " + framename + "[] = {" + framename + "_0};" +# data=bytes_out print(char_out) print(char_out2) -#w.write(data) -#w.close() +# w.write(data) +# w.close() diff --git a/scripts/asset_packer.py b/scripts/asset_packer.py index 54c598ea5..02ed0b94e 100755 --- a/scripts/asset_packer.py +++ b/scripts/asset_packer.py @@ -43,10 +43,51 @@ def convert_bmx(img: "Image.Image | pathlib.Path") -> bytes: return data -def pack(input: "str | pathlib.Path", output: "str | pathlib.Path", logger: typing.Callable): +def pack_anim(src: pathlib.Path, dst: pathlib.Path): + if not (src / "meta.txt").is_file(): + return + dst.mkdir(parents=True, exist_ok=True) + for frame in src.iterdir(): + if not frame.is_file(): + continue + if frame.name == "meta.txt": + shutil.copyfile(src / "meta.txt", dst / "meta.txt") + continue + elif frame.name.startswith("frame_"): + (dst / frame.with_suffix(".bm").name).write_bytes(convert_bm(frame)) + + +def pack_icon_animated(src: pathlib.Path, dst: pathlib.Path): + if not (src / "frame_rate").is_file(): + return + dst.mkdir(parents=True, exist_ok=True) + frame_count = 0 + frame_rate = None + size = None + for frame in src.iterdir(): + if not frame.is_file(): + continue + if frame.name == "frame_rate": + frame_rate = int((src / "frame_rate").read_text()) + continue + elif frame.name.startswith("frame_"): + frame_count += 1 + if not size: + size = Image.open(frame).size + (dst / frame.with_suffix(".bm").name).write_bytes(convert_bm(frame)) + (dst / "meta").write_bytes(struct.pack(" List[str]: + app_def = self.appmgr.get(app_name) + + # Skip app if its target is not supported by the target we are building for + if not self._check_if_app_target_supported(app_name): + self._writer( + f"Skipping {app_name} due to target mismatch (building for {self.hw_target}, app supports {app_def.targets}" + ) + return [] + + return list( + filter( + self._check_if_app_target_supported, + filter(self._is_missing_dep, app_def.provides + app_def.requires), + ) + ) def _process_deps(self): while True: provided = [] - for app in self.appnames: - # print(app) - provided.extend( - filter( - self._is_missing_dep, - self.appmgr.get(app).provides + self.appmgr.get(app).requires, - ) - ) - # print("provides round", provided) + for app_name in self.appnames: + provided.extend(self._get_app_depends(app_name)) + + # print("provides round: ", provided) if len(provided) == 0: break self.appnames.update(provided) @@ -205,7 +224,6 @@ class AppBuildset: def _check_conflicts(self): conflicts = [] for app in self.appnames: - # print(app) if conflict_app_name := list( filter( lambda dep_name: dep_name in self.appnames, @@ -232,6 +250,17 @@ class AppBuildset: f"Unsatisfied dependencies for {', '.join(f'{missing_dep[0]}: {missing_dep[1]}' for missing_dep in unsatisfied)}" ) + def _check_target_match(self): + incompatible = [] + for app in self.appnames: + if not self.appmgr.get(app).supports_hardware_target(self.hw_target): + incompatible.append(app) + + if len(incompatible): + raise AppBuilderException( + f"Apps incompatible with target {self.hw_target}: {', '.join(incompatible)}" + ) + def get_apps_cdefs(self): cdefs = set() for app in self.apps: diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index 96528f4e5..9dbe30720 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -1,5 +1,6 @@ from SCons.Builder import Builder from SCons.Action import Action +from SCons.Errors import StopError from SCons.Warnings import warn, WarningOnByDefault from ansi.color import fg @@ -32,9 +33,13 @@ def LoadAppManifest(env, entry): def PrepareApplicationsBuild(env): - appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps( - env["APPS"], env.subst("f${TARGET_HW}") - ) + try: + appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps( + env["APPS"], env.subst("f${TARGET_HW}") + ) + except Exception as e: + raise StopError(e) + env.Append( SDK_HEADERS=appbuild.get_sdk_headers(), ) diff --git a/scripts/fbt_tools/fbt_help.py b/scripts/fbt_tools/fbt_help.py index 9921588ed..afdb36665 100644 --- a/scripts/fbt_tools/fbt_help.py +++ b/scripts/fbt_tools/fbt_help.py @@ -11,7 +11,7 @@ Building: Build all FAP apps fap_{APPID}, launch_app APPSRC={APPID}: Build FAP app with appid={APPID}; upload & start it over USB - faps_copy: + fap_deploy: Build and upload all FAP apps over USB Flashing & debugging: diff --git a/scripts/fbt_tools/fbt_hwtarget.py b/scripts/fbt_tools/fbt_hwtarget.py new file mode 100644 index 000000000..b4e1e58ac --- /dev/null +++ b/scripts/fbt_tools/fbt_hwtarget.py @@ -0,0 +1,134 @@ +from SCons.Builder import Builder +from SCons.Action import Action +import json + + +class HardwareTargetLoader: + def __init__(self, env, target_scons_dir, target_id): + self.env = env + self.target_scons_dir = target_scons_dir + self.target_dir = self._getTargetDir(target_id) + # self.target_id = target_id + self.layered_target_dirs = [] + + self.include_paths = [] + self.sdk_header_paths = [] + self.startup_script = None + self.linker_script_flash = None + self.linker_script_ram = None + self.linker_script_app = None + self.sdk_symbols = None + self.linker_dependencies = [] + self.excluded_sources = [] + self.excluded_headers = [] + self.excluded_modules = [] + self._processTargetDefinitions(target_id) + + def _getTargetDir(self, target_id): + return self.target_scons_dir.Dir(f"f{target_id}") + + def _loadDescription(self, target_id): + target_json_file = self._getTargetDir(target_id).File("target.json") + if not target_json_file.exists(): + raise Exception(f"Target file {target_json_file} does not exist") + with open(target_json_file.get_abspath(), "r") as f: + vals = json.load(f) + return vals + + def _processTargetDefinitions(self, target_id): + self.layered_target_dirs.append(f"targets/f{target_id}") + + config = self._loadDescription(target_id) + + for path_list in ("include_paths", "sdk_header_paths"): + getattr(self, path_list).extend( + f"#/firmware/targets/f{target_id}/{p}" + for p in config.get(path_list, []) + ) + + self.excluded_sources.extend(config.get("excluded_sources", [])) + self.excluded_headers.extend(config.get("excluded_headers", [])) + self.excluded_modules.extend(config.get("excluded_modules", [])) + + file_attrs = ( + # (name, use_src_node) + ("startup_script", False), + ("linker_script_flash", True), + ("linker_script_ram", True), + ("linker_script_app", True), + ("sdk_symbols", True), + ) + + for attr_name, use_src_node in file_attrs: + if (val := config.get(attr_name)) and not getattr(self, attr_name): + node = self.env.File(f"firmware/targets/f{target_id}/{val}") + if use_src_node: + node = node.srcnode() + setattr(self, attr_name, node) + + for attr_name in ("linker_dependencies",): + if (val := config.get(attr_name)) and not getattr(self, attr_name): + setattr(self, attr_name, val) + + if inherited_target := config.get("inherit", None): + self._processTargetDefinitions(inherited_target) + + def gatherSources(self): + sources = [self.startup_script] + seen_filenames = set(self.excluded_sources) + # print("Layers: ", self.layered_target_dirs) + for target_dir in self.layered_target_dirs: + accepted_sources = list( + filter( + lambda f: f.name not in seen_filenames, + self.env.GlobRecursive("*.c", target_dir), + ) + ) + seen_filenames.update(f.name for f in accepted_sources) + sources.extend(accepted_sources) + # print(f"Found {len(sources)} sources: {list(f.name for f in sources)}") + return sources + + def gatherSdkHeaders(self): + sdk_headers = [] + seen_sdk_headers = set(self.excluded_headers) + for sdk_path in self.sdk_header_paths: + # dirty, but fast - exclude headers from overlayed targets by name + # proper way would be to use relative paths, but names will do for now + for header in self.env.GlobRecursive("*.h", sdk_path, "*_i.h"): + if header.name not in seen_sdk_headers: + seen_sdk_headers.add(header.name) + sdk_headers.append(header) + return sdk_headers + + +def ConfigureForTarget(env, target_id): + target_loader = HardwareTargetLoader(env, env.Dir("#/firmware/targets"), target_id) + env.Replace( + TARGET_CFG=target_loader, + SDK_DEFINITION=target_loader.sdk_symbols, + SKIP_MODULES=target_loader.excluded_modules, + ) + + env.Append( + CPPPATH=target_loader.include_paths, + SDK_HEADERS=target_loader.gatherSdkHeaders(), + ) + + +def ApplyLibFlags(env): + flags_to_apply = env["FW_LIB_OPTS"].get( + env.get("FW_LIB_NAME"), + env["FW_LIB_OPTS"]["Default"], + ) + # print("Flags for ", env.get("FW_LIB_NAME", "Default"), flags_to_apply) + env.MergeFlags(flags_to_apply) + + +def generate(env): + env.AddMethod(ConfigureForTarget) + env.AddMethod(ApplyLibFlags) + + +def exists(env): + return True diff --git a/scripts/fbt_tools/sconsmodular.py b/scripts/fbt_tools/sconsmodular.py index b115706cb..57ae8f055 100644 --- a/scripts/fbt_tools/sconsmodular.py +++ b/scripts/fbt_tools/sconsmodular.py @@ -22,6 +22,8 @@ def BuildModule(env, module): def BuildModules(env, modules): result = [] for module in modules: + if module in env.get("SKIP_MODULES", []): + continue build_res = env.BuildModule(module) # print("module ", module, build_res) if build_res is None: diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index 899a8a615..45ed3e19f 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -35,7 +35,7 @@ class DolphinBubbleAnimation: min_level: int, max_level: int, weight: int, - subpath: str = None + subpath: str = None, ): # Manifest self.name = name @@ -188,7 +188,9 @@ class DolphinBubbleAnimation: def save(self, output_directory: str): if self.subpath: - animation_directory = os.path.join(output_directory, self.subpath, self.name) + animation_directory = os.path.join( + output_directory, self.subpath, self.name + ) else: animation_directory = os.path.join(output_directory, self.name) os.makedirs(animation_directory, exist_ok=True) @@ -294,7 +296,13 @@ class DolphinManifest: # Initialize animation animation = DolphinBubbleAnimation( - name, min_butthurt, max_butthurt, min_level, max_level, weight, subpath + name, + min_butthurt, + max_butthurt, + min_level, + max_level, + weight, + subpath, ) # Load Animation meta and frames diff --git a/scripts/program.py b/scripts/program.py new file mode 100755 index 000000000..c140a9024 --- /dev/null +++ b/scripts/program.py @@ -0,0 +1,459 @@ +#!/usr/bin/env python3 +import typing +import subprocess +import logging +import time +import os +import socket + +from abc import ABC, abstractmethod +from dataclasses import dataclass +from flipper.app import App + + +class Programmer(ABC): + @abstractmethod + def flash(self, bin: str) -> bool: + pass + + @abstractmethod + def probe(self) -> bool: + pass + + @abstractmethod + def get_name(self) -> str: + pass + + @abstractmethod + def set_serial(self, serial: str): + pass + + +@dataclass +class OpenOCDInterface: + name: str + file: str + serial_cmd: str + additional_args: typing.Optional[list[str]] = None + + +class OpenOCDProgrammer(Programmer): + def __init__(self, interface: OpenOCDInterface): + self.interface = interface + self.logger = logging.getLogger("OpenOCD") + self.serial: typing.Optional[str] = None + + def _add_file(self, params: list[str], file: str): + params.append("-f") + params.append(file) + + def _add_command(self, params: list[str], command: str): + params.append("-c") + params.append(command) + + def _add_serial(self, params: list[str], serial: str): + self._add_command(params, f"{self.interface.serial_cmd} {serial}") + + def set_serial(self, serial: str): + self.serial = serial + + def flash(self, bin: str) -> bool: + i = self.interface + + if os.altsep: + bin = bin.replace(os.sep, os.altsep) + + openocd_launch_params = ["openocd"] + self._add_file(openocd_launch_params, i.file) + if self.serial: + self._add_serial(openocd_launch_params, self.serial) + if i.additional_args: + for a in i.additional_args: + self._add_command(openocd_launch_params, a) + self._add_file(openocd_launch_params, "target/stm32wbx.cfg") + self._add_command(openocd_launch_params, "init") + self._add_command(openocd_launch_params, f"program {bin} reset exit 0x8000000") + + # join the list of parameters into a string, but add quote if there are spaces + openocd_launch_params_string = " ".join( + [f'"{p}"' if " " in p else p for p in openocd_launch_params] + ) + + self.logger.debug(f"Launching: {openocd_launch_params_string}") + + process = subprocess.Popen( + openocd_launch_params, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + + while process.poll() is None: + time.sleep(0.25) + print(".", end="", flush=True) + print() + + success = process.returncode == 0 + + if not success: + self.logger.error("OpenOCD failed to flash") + if process.stdout: + self.logger.error(process.stdout.read().decode("utf-8").strip()) + + return success + + def probe(self) -> bool: + i = self.interface + + openocd_launch_params = ["openocd"] + self._add_file(openocd_launch_params, i.file) + if self.serial: + self._add_serial(openocd_launch_params, self.serial) + if i.additional_args: + for a in i.additional_args: + self._add_command(openocd_launch_params, a) + self._add_file(openocd_launch_params, "target/stm32wbx.cfg") + self._add_command(openocd_launch_params, "init") + self._add_command(openocd_launch_params, "exit") + + self.logger.debug(f"Launching: {' '.join(openocd_launch_params)}") + + process = subprocess.Popen( + openocd_launch_params, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + ) + + # Wait for OpenOCD to end and get the return code + process.wait() + found = process.returncode == 0 + + if process.stdout: + self.logger.debug(process.stdout.read().decode("utf-8").strip()) + + return found + + def get_name(self) -> str: + return self.interface.name + + +def blackmagic_find_serial(serial: str): + import serial.tools.list_ports as list_ports + + if serial and os.name == "nt": + if not serial.startswith("\\\\.\\"): + serial = f"\\\\.\\{serial}" + + ports = list(list_ports.grep("blackmagic")) + if len(ports) == 0: + return None + elif len(ports) > 2: + if serial: + ports = list( + filter( + lambda p: p.serial_number == serial + or p.name == serial + or p.device == serial, + ports, + ) + ) + if len(ports) == 0: + return None + + if len(ports) > 2: + raise Exception("More than one Blackmagic probe found") + + # If you're getting any issues with auto lookup, uncomment this + # print("\n".join([f"{p.device} {vars(p)}" for p in ports])) + port = sorted(ports, key=lambda p: f"{p.location}_{p.name}")[0] + + if serial: + if ( + serial != port.serial_number + and serial != port.name + and serial != port.device + ): + return None + + if os.name == "nt": + port.device = f"\\\\.\\{port.device}" + return port.device + + +def _resolve_hostname(hostname): + try: + return socket.gethostbyname(hostname) + except socket.gaierror: + return None + + +def blackmagic_find_networked(serial: str): + if not serial: + serial = "blackmagic.local" + + # remove the tcp: prefix if it's there + if serial.startswith("tcp:"): + serial = serial[4:] + + # remove the port if it's there + if ":" in serial: + serial = serial.split(":")[0] + + if not (probe := _resolve_hostname(serial)): + return None + + return f"tcp:{probe}:2345" + + +class BlackmagicProgrammer(Programmer): + def __init__( + self, + port_resolver, # typing.Callable[typing.Union[str, None], typing.Optional[str]] + name: str, + ): + self.port_resolver = port_resolver + self.name = name + self.logger = logging.getLogger("BlackmagicUSB") + self.port: typing.Optional[str] = None + + def _add_command(self, params: list[str], command: str): + params.append("-ex") + params.append(command) + + def _valid_ip(self, address): + try: + socket.inet_aton(address) + return True + except: + return False + + def set_serial(self, serial: str): + if self._valid_ip(serial): + self.port = f"{serial}:2345" + elif ip := _resolve_hostname(serial): + self.port = f"{ip}:2345" + else: + self.port = serial + + def flash(self, bin: str) -> bool: + if not self.port: + if not self.probe(): + return False + + # We can convert .bin to .elf with objcopy: + # arm-none-eabi-objcopy -I binary -O elf32-littlearm --change-section-address=.data=0x8000000 -B arm -S app.bin app.elf + # But I choose to use the .elf file directly because we are flashing our own firmware and it always has an elf predecessor. + elf = bin.replace(".bin", ".elf") + if not os.path.exists(elf): + self.logger.error( + f"Sorry, but Blackmagic can't flash .bin file, and {elf} doesn't exist" + ) + return False + + # arm-none-eabi-gdb build/f7-firmware-D/firmware.bin + # -ex 'set pagination off' + # -ex 'target extended-remote /dev/cu.usbmodem21201' + # -ex 'set confirm off' + # -ex 'monitor swdp_scan' + # -ex 'attach 1' + # -ex 'set mem inaccessible-by-default off' + # -ex 'load' + # -ex 'compare-sections' + # -ex 'quit' + + gdb_launch_params = ["arm-none-eabi-gdb", elf] + self._add_command(gdb_launch_params, f"target extended-remote {self.port}") + self._add_command(gdb_launch_params, "set pagination off") + self._add_command(gdb_launch_params, "set confirm off") + self._add_command(gdb_launch_params, "monitor swdp_scan") + self._add_command(gdb_launch_params, "attach 1") + self._add_command(gdb_launch_params, "set mem inaccessible-by-default off") + self._add_command(gdb_launch_params, "load") + self._add_command(gdb_launch_params, "compare-sections") + self._add_command(gdb_launch_params, "quit") + + self.logger.debug(f"Launching: {' '.join(gdb_launch_params)}") + + process = subprocess.Popen( + gdb_launch_params, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + + while process.poll() is None: + time.sleep(0.5) + print(".", end="", flush=True) + print() + + if not process.stdout: + return False + + output = process.stdout.read().decode("utf-8").strip() + flashed = "Loading section .text," in output + + # Check flash verification + if "MIS-MATCHED!" in output: + flashed = False + + if "target image does not match the loaded file" in output: + flashed = False + + if not flashed: + self.logger.error("Blackmagic failed to flash") + self.logger.error(output) + + return flashed + + def probe(self) -> bool: + if not (port := self.port_resolver(self.port)): + return False + + self.port = port + return True + + def get_name(self) -> str: + return self.name + + +programmers: list[Programmer] = [ + OpenOCDProgrammer( + OpenOCDInterface( + "cmsis-dap", + "interface/cmsis-dap.cfg", + "cmsis_dap_serial", + ["transport select swd"], + ), + ), + OpenOCDProgrammer( + OpenOCDInterface( + "stlink", "interface/stlink.cfg", "hla_serial", ["transport select hla_swd"] + ), + ), + BlackmagicProgrammer(blackmagic_find_serial, "blackmagic_usb"), +] + +network_programmers = [ + BlackmagicProgrammer(blackmagic_find_networked, "blackmagic_wifi") +] + + +class Main(App): + def init(self): + self.subparsers = self.parser.add_subparsers(help="sub-command help") + self.parser_flash = self.subparsers.add_parser("flash", help="Flash a binary") + self.parser_flash.add_argument( + "bin", + type=str, + help="Binary to flash", + ) + interfaces = [i.get_name() for i in programmers] + interfaces.extend([i.get_name() for i in network_programmers]) + self.parser_flash.add_argument( + "--interface", + choices=interfaces, + type=str, + help="Interface to use", + ) + self.parser_flash.add_argument( + "--serial", + type=str, + help="Serial number or port of the programmer", + ) + self.parser_flash.set_defaults(func=self.flash) + + def _search_interface(self, serial: typing.Optional[str]) -> list[Programmer]: + found_programmers = [] + + for p in programmers: + name = p.get_name() + if serial: + p.set_serial(serial) + self.logger.debug(f"Trying {name} with {serial}") + else: + self.logger.debug(f"Trying {name}") + + if p.probe(): + self.logger.debug(f"Found {name}") + found_programmers += [p] + else: + self.logger.debug(f"Failed to probe {name}") + + return found_programmers + + def _search_network_interface( + self, serial: typing.Optional[str] + ) -> list[Programmer]: + found_programmers = [] + + for p in network_programmers: + name = p.get_name() + + if serial: + p.set_serial(serial) + self.logger.debug(f"Trying {name} with {serial}") + else: + self.logger.debug(f"Trying {name}") + + if p.probe(): + self.logger.debug(f"Found {name}") + found_programmers += [p] + else: + self.logger.debug(f"Failed to probe {name}") + + return found_programmers + + def flash(self): + start_time = time.time() + bin_path = os.path.abspath(self.args.bin) + + if not os.path.exists(bin_path): + self.logger.error(f"Binary file not found: {bin_path}") + return 1 + + if self.args.interface: + i_name = self.args.interface + interfaces = [p for p in programmers if p.get_name() == i_name] + if len(interfaces) == 0: + interfaces = [p for p in network_programmers if p.get_name() == i_name] + else: + self.logger.info(f"Probing for interfaces...") + interfaces = self._search_interface(self.args.serial) + + if len(interfaces) == 0: + # Probe network blackmagic + self.logger.info(f"Probing for network interfaces...") + interfaces = self._search_network_interface(self.args.serial) + + if len(interfaces) == 0: + self.logger.error("No interface found") + return 1 + + if len(interfaces) > 1: + self.logger.error("Multiple interfaces found: ") + self.logger.error( + f"Please specify '--interface={[i.get_name() for i in interfaces]}'" + ) + return 1 + + interface = interfaces[0] + + if self.args.serial: + interface.set_serial(self.args.serial) + self.logger.info( + f"Flashing {bin_path} via {interface.get_name()} with {self.args.serial}" + ) + else: + self.logger.info(f"Flashing {bin_path} via {interface.get_name()}") + + if not interface.flash(bin_path): + self.logger.error(f"Failed to flash via {interface.get_name()}") + return 1 + + flash_time = time.time() - start_time + bin_size = os.path.getsize(bin_path) + self.logger.info(f"Flashed successfully in {flash_time:.2f}s") + self.logger.info(f"Effective speed: {bin_size / flash_time / 1024:.2f} KiB/s") + return 0 + + +if __name__ == "__main__": + Main()() diff --git a/scripts/runfap.py b/scripts/runfap.py index 14d885e8a..9f544fd90 100644 --- a/scripts/runfap.py +++ b/scripts/runfap.py @@ -103,4 +103,4 @@ class Main(App): if __name__ == "__main__": - Main()() \ No newline at end of file + Main()() diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index 0fa120d87..ce261954c 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -166,11 +166,13 @@ class Main(App): ) ) bundle_args.extend(self.other_args) - log_custom_fz_name = ( - environ.get("CUSTOM_FLIPPER_NAME", None) - or "" - ) - if (log_custom_fz_name != "") and (len(log_custom_fz_name) <= 8) and (log_custom_fz_name.isalnum()) and (log_custom_fz_name.isascii()): + log_custom_fz_name = environ.get("CUSTOM_FLIPPER_NAME", None) or "" + if ( + (log_custom_fz_name != "") + and (len(log_custom_fz_name) <= 8) + and (log_custom_fz_name.isalnum()) + and (log_custom_fz_name.isascii()) + ): self.logger.info( f"Flipper Custom Name is set:\n\tName: {log_custom_fz_name} : length - {len(log_custom_fz_name)} chars" ) diff --git a/scripts/version.py b/scripts/version.py index 363df0aeb..ed2e83162 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -11,10 +11,14 @@ from datetime import date, datetime class GitVersion: def __init__(self, source_dir): self.source_dir = source_dir - self.gitlist = [("commit", "rev-parse --short HEAD"), ("branch", "rev-parse --abbrev-ref") , ("branch_num", "rev-list -count HEAD")] + self.gitlist = [ + ("commit", "rev-parse --short HEAD"), + ("branch", "rev-parse --abbrev-ref"), + ("branch_num", "rev-list -count HEAD"), + ] def get_version_info(self): - commit = branch = branch_num = "XFW-0040" + commit = branch = branch_num = "XFW-0041" # We dont use an `or` in commands that we expect to fail. It will serve no function. # We also dont try;exept an entire block of code. This is bad practise. We only try the single part that we expect to fail! @@ -36,20 +40,19 @@ class GitVersion: # If WORKFLOW_BRANCH_OR_TAG is set in environment, is has precedence # (set by CI) - custom_fz_name = ( - os.environ.get("CUSTOM_FLIPPER_NAME", None) - or "" - ) + custom_fz_name = os.environ.get("CUSTOM_FLIPPER_NAME", None) or "" - force_no_dirty = ( - os.environ.get("FORCE_NO_DIRTY", None) - or "" - ) + force_no_dirty = os.environ.get("FORCE_NO_DIRTY", None) or "" - if (force_no_dirty != ""): + if force_no_dirty != "": dirty = False - if (custom_fz_name != "") and (len(custom_fz_name) <= 8) and (custom_fz_name.isalnum()) and (custom_fz_name.isascii()): + if ( + (custom_fz_name != "") + and (len(custom_fz_name) <= 8) + and (custom_fz_name.isalnum()) + and (custom_fz_name.isascii()) + ): return { "GIT_COMMIT": commit, "GIT_BRANCH": "dev", diff --git a/site_scons/cc.scons b/site_scons/cc.scons index 95888dc95..1eb6a3376 100644 --- a/site_scons/cc.scons +++ b/site_scons/cc.scons @@ -44,4 +44,4 @@ ENV.AppendUnique( "-mlittle-endian", "-mthumb", ], -) \ No newline at end of file +) diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 837fd0b85..e38f58ec2 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -79,6 +79,7 @@ vars.AddVariables( default="7", allowed_values=[ "7", + "18", ], ), ( @@ -207,7 +208,7 @@ vars.AddVariables( # "basic_plugins", # Debug # "debug_apps", - ) + ), }, ), ( @@ -243,4 +244,4 @@ vars.AddVariables( ), ) -Return("vars") \ No newline at end of file +Return("vars") diff --git a/site_scons/environ.scons b/site_scons/environ.scons index ab60d4e71..0ffc8a6a2 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -88,4 +88,4 @@ SetOption("max_drift", 1) wrap_tempfile(coreenv, "LINKCOM") wrap_tempfile(coreenv, "ARCOM") -Return("coreenv") \ No newline at end of file +Return("coreenv") diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index ea16d1e78..abe1a4534 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -16,7 +16,7 @@ appenv = ENV["APPENV"] = ENV.Clone( ) appenv.Replace( - LINKER_SCRIPT=appenv.subst("$APP_LINKER_SCRIPT"), + LINKER_SCRIPT_PATH=appenv["APP_LINKER_SCRIPT_PATH"], ) appenv.AppendUnique( @@ -78,17 +78,20 @@ known_extapps = [ if extra_app_list := GetOption("extra_ext_apps"): known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(","))) +incompatible_apps = [] for app in known_extapps: - if not any(map(lambda t: t in app.targets, ["all", appenv.subst("f${TARGET_HW}")])): - warn( - WarningOnByDefault, - f"Can't build '{app.name}' (id '{app.appid}'): target mismatch" - f" (building for {appenv.subst('f${TARGET_HW}')}, app supports {app.targets}", - ) + if not app.supports_hardware_target(appenv.subst("f${TARGET_HW}")): + incompatible_apps.append(app) continue appenv.BuildAppElf(app) +if incompatible_apps: + warn( + WarningOnByDefault, + f"Skipping build of {len(incompatible_apps)} incompatible app(s): " + + ", ".join(f"'{app.name}' (id '{app.appid}')" for app in incompatible_apps), + ) if appenv["FORCE"]: appenv.AlwaysBuild( @@ -152,4 +155,4 @@ if appenv["FORCE"]: appenv.AlwaysBuild(sdk_source, sdk_tree, sdk_apicheck, sdk_apisyms) -Return("extapps") \ No newline at end of file +Return("extapps") diff --git a/site_scons/firmwareopts.scons b/site_scons/firmwareopts.scons index 9f707b4d8..e4cc8db58 100644 --- a/site_scons/firmwareopts.scons +++ b/site_scons/firmwareopts.scons @@ -49,18 +49,15 @@ ENV.AppendUnique( ], ) -ENV.SetDefault( - LINKER_SCRIPT_PATH="firmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", -) if ENV["FIRMWARE_BUILD_CFG"] == "updater": ENV.Append( IMAGE_BASE_ADDRESS="0x20000000", - LINKER_SCRIPT="stm32wb55xx_ram_fw", + LINKER_SCRIPT_PATH=ENV["TARGET_CFG"].linker_script_ram, ) else: ENV.Append( IMAGE_BASE_ADDRESS="0x8000000", - LINKER_SCRIPT="stm32wb55xx_flash", - APP_LINKER_SCRIPT="application_ext", + LINKER_SCRIPT_PATH=ENV["TARGET_CFG"].linker_script_flash, + APP_LINKER_SCRIPT_PATH=ENV["TARGET_CFG"].linker_script_app, ) diff --git a/sonar-project.properties b/sonar-project.properties index 43c6c8dec..30fc27a96 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -10,3 +10,19 @@ sonar.organization=claracrazy # Encoding of the source code. Default is default system encoding #sonar.sourceEncoding=UTF-8 + + +# Ignore some rules +sonar.issue.ignore.multicriteria=c1,c2,c3 + +# Make sure use of "strcpy" is safe here +sonar.issue.ignore.multicriteria.c1.ruleKey=c:S5801 +sonar.issue.ignore.multicriteria.c1.resourceKey=**/*.c + +# Make sure use of "strlen" is safe here +sonar.issue.ignore.multicriteria.c2.ruleKey=c:S5813 +sonar.issue.ignore.multicriteria.c2.resourceKey=**/*.c + +# Make sure that using this pseudorandom number generator "rand" is safe here +sonar.issue.ignore.multicriteria.c3.ruleKey=c:S2245 +sonar.issue.ignore.multicriteria.c3.resourceKey=**/*.c