Merge branch 'release-candidate' into release
							
								
								
									
										77
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @ -32,6 +32,7 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           fetch-depth: 0 |           fetch-depth: 0 | ||||||
|           submodules: true |           submodules: true | ||||||
|  |           ref: ${{ github.event.pull_request.head.sha }} | ||||||
| 
 | 
 | ||||||
|       - name: 'Docker cache' |       - name: 'Docker cache' | ||||||
|         uses: satackey/action-docker-layer-caching@v0.0.11 |         uses: satackey/action-docker-layer-caching@v0.0.11 | ||||||
| @ -48,13 +49,27 @@ jobs: | |||||||
|           test -d artifacts && rm -rf artifacts || true |           test -d artifacts && rm -rf artifacts || true | ||||||
|           mkdir artifacts |           mkdir artifacts | ||||||
|        |        | ||||||
|       - name: 'Generate tag suffix' |       - name: 'Generate suffix and folder name' | ||||||
|         if: startsWith(github.ref, 'refs/tags/') == true |         id: names | ||||||
|         run: echo "SUFFIX=$(git describe --tags --abbrev=0)"  >> $GITHUB_ENV |         run: | | ||||||
|  |           REF=${{ github.ref }} | ||||||
|  |           if [[ ${{ github.event_name }} == 'pull_request' ]]; then | ||||||
|  |             REF=${{ github.head_ref }} | ||||||
|  |           fi | ||||||
|  |           BRANCH_OR_TAG=${REF##*/} | ||||||
|  |           SHA=$(git rev-parse --short HEAD) | ||||||
|            |            | ||||||
|       - name: 'Generate branch suffix' |           if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then | ||||||
|         if: startsWith(github.ref, 'refs/tags/') != true |             SUFFIX=${BRANCH_OR_TAG} | ||||||
|         run: echo "SUFFIX=$(git rev-parse --abbrev-ref HEAD)-$(date +'%d%m%Y')-$(git rev-parse --short HEAD)" >> $GITHUB_ENV |           else | ||||||
|  |             SUFFIX=${BRANCH_OR_TAG}-$(date +'%d%m%Y')-${SHA} | ||||||
|  |           fi | ||||||
|  |            | ||||||
|  |           echo "WORKFLOW_BRANCH_OR_TAG=${BRANCH_OR_TAG}" >> $GITHUB_ENV | ||||||
|  |           echo "::set-output name=artifacts-path::${BRANCH_OR_TAG}" | ||||||
|  |           echo "::set-output name=suffix::${SUFFIX}" | ||||||
|  |           echo "::set-output name=short-hash::${SHA}" | ||||||
|  |           echo "::set-output name=latest-target::${TARGETS[${#TARGETS[@]}-1]}" | ||||||
| 
 | 
 | ||||||
|       - name: 'Build bootloader in docker' |       - name: 'Build bootloader in docker' | ||||||
|         uses: ./.github/actions/docker |         uses: ./.github/actions/docker | ||||||
| @ -95,17 +110,17 @@ jobs: | |||||||
|             for TARGET in ${TARGETS} |             for TARGET in ${TARGETS} | ||||||
|             do |             do | ||||||
|               mv bootloader/.obj/${TARGET}/bootloader.dfu \ |               mv bootloader/.obj/${TARGET}/bootloader.dfu \ | ||||||
|                 artifacts/flipper-z-${TARGET}-bootloader-${SUFFIX}.dfu |                 artifacts/flipper-z-${TARGET}-bootloader-${{steps.names.outputs.suffix}}.dfu | ||||||
|               mv bootloader/.obj/${TARGET}/bootloader.bin \ |               mv bootloader/.obj/${TARGET}/bootloader.bin \ | ||||||
|                 artifacts/flipper-z-${TARGET}-bootloader-${SUFFIX}.bin |                 artifacts/flipper-z-${TARGET}-bootloader-${{steps.names.outputs.suffix}}.bin | ||||||
|               mv bootloader/.obj/${TARGET}/bootloader.elf \ |               mv bootloader/.obj/${TARGET}/bootloader.elf \ | ||||||
|                 artifacts/flipper-z-${TARGET}-bootloader-${SUFFIX}.elf |                 artifacts/flipper-z-${TARGET}-bootloader-${{steps.names.outputs.suffix}}.elf | ||||||
|               mv firmware/.obj/${TARGET}/firmware.dfu \ |               mv firmware/.obj/${TARGET}/firmware.dfu \ | ||||||
|                 artifacts/flipper-z-${TARGET}-firmware-${SUFFIX}.dfu |                 artifacts/flipper-z-${TARGET}-firmware-${{steps.names.outputs.suffix}}.dfu | ||||||
|               mv firmware/.obj/${TARGET}/firmware.bin \ |               mv firmware/.obj/${TARGET}/firmware.bin \ | ||||||
|                 artifacts/flipper-z-${TARGET}-firmware-${SUFFIX}.bin |                 artifacts/flipper-z-${TARGET}-firmware-${{steps.names.outputs.suffix}}.bin | ||||||
|               mv firmware/.obj/${TARGET}/firmware.elf \ |               mv firmware/.obj/${TARGET}/firmware.elf \ | ||||||
|                 artifacts/flipper-z-${TARGET}-firmware-${SUFFIX}.elf |                 artifacts/flipper-z-${TARGET}-firmware-${{steps.names.outputs.suffix}}.elf | ||||||
|             done |             done | ||||||
| 
 | 
 | ||||||
|       - name: 'Generate full dfu file' |       - name: 'Generate full dfu file' | ||||||
| @ -117,7 +132,7 @@ jobs: | |||||||
|             do |             do | ||||||
|               hex2dfu \ |               hex2dfu \ | ||||||
|                 -i firmware/.obj/${TARGET}/full.hex \ |                 -i firmware/.obj/${TARGET}/full.hex \ | ||||||
|                 -o artifacts/flipper-z-${TARGET}-full-${SUFFIX}.dfu \ |                 -o artifacts/flipper-z-${TARGET}-full-${{steps.names.outputs.suffix}}.dfu \ | ||||||
|                 -l "Flipper Zero $(echo $TARGET | tr a-z A-Z)" |                 -l "Flipper Zero $(echo $TARGET | tr a-z A-Z)" | ||||||
|             done |             done | ||||||
| 
 | 
 | ||||||
| @ -127,8 +142,8 @@ jobs: | |||||||
|           for TARGET in ${TARGETS} |           for TARGET in ${TARGETS} | ||||||
|           do |           do | ||||||
|             cp \ |             cp \ | ||||||
|               artifacts/flipper-z-${TARGET}-bootloader-${SUFFIX}.bin \ |               artifacts/flipper-z-${TARGET}-bootloader-${{steps.names.outputs.suffix}}.bin \ | ||||||
|               artifacts/flipper-z-${TARGET}-full-${SUFFIX}.bin |               artifacts/flipper-z-${TARGET}-full-${{steps.names.outputs.suffix}}.bin | ||||||
|           done |           done | ||||||
| 
 | 
 | ||||||
|       - name: 'Full flash asssembly: bootloader padding' |       - name: 'Full flash asssembly: bootloader padding' | ||||||
| @ -136,7 +151,7 @@ jobs: | |||||||
|         run: | |         run: | | ||||||
|           for TARGET in ${TARGETS} |           for TARGET in ${TARGETS} | ||||||
|           do |           do | ||||||
|             truncate -s 32768 artifacts/flipper-z-${TARGET}-full-${SUFFIX}.bin |             truncate -s 32768 artifacts/flipper-z-${TARGET}-full-${{steps.names.outputs.suffix}}.bin | ||||||
|           done |           done | ||||||
| 
 | 
 | ||||||
|       - name: 'Full flash asssembly: append firmware' |       - name: 'Full flash asssembly: append firmware' | ||||||
| @ -145,8 +160,8 @@ jobs: | |||||||
|           for TARGET in ${TARGETS} |           for TARGET in ${TARGETS} | ||||||
|           do |           do | ||||||
|             cat \ |             cat \ | ||||||
|               artifacts/flipper-z-${TARGET}-firmware-${SUFFIX}.bin \ |               artifacts/flipper-z-${TARGET}-firmware-${{steps.names.outputs.suffix}}.bin \ | ||||||
|               >> artifacts/flipper-z-${TARGET}-full-${SUFFIX}.bin |               >> artifacts/flipper-z-${TARGET}-full-${{steps.names.outputs.suffix}}.bin | ||||||
|           done |           done | ||||||
| 
 | 
 | ||||||
|       - name: 'Bundle core2 firmware' |       - name: 'Bundle core2 firmware' | ||||||
| @ -160,17 +175,17 @@ jobs: | |||||||
|             lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/stm32wb5x_FUS_fw_for_fus_0_5_3.bin \ |             lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/stm32wb5x_FUS_fw_for_fus_0_5_3.bin \ | ||||||
|             lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/stm32wb5x_BLE_Stack_full_fw.bin \ |             lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/stm32wb5x_BLE_Stack_full_fw.bin \ | ||||||
|             core2_firmware |             core2_firmware | ||||||
|           tar czpf artifacts/flipper-z-any-core2_firmware-${SUFFIX}.tgz core2_firmware |           tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz core2_firmware | ||||||
| 
 | 
 | ||||||
|       - name: 'Bundle scripts' |       - name: 'Bundle scripts' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||||
|         run: | |         run: | | ||||||
|           tar czpf artifacts/flipper-z-any-scripts-${SUFFIX}.tgz scripts |           tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts | ||||||
| 
 | 
 | ||||||
|       - name: 'Bundle resources' |       - name: 'Bundle resources' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||||
|         run: | |         run: | | ||||||
|           tar czpf artifacts/flipper-z-any-resources-${SUFFIX}.tgz -C assets resources |           tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources | ||||||
| 
 | 
 | ||||||
|       - name: 'Upload artifacts to update server' |       - name: 'Upload artifacts to update server' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||||
| @ -178,7 +193,7 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           switches: -avzP --delete |           switches: -avzP --delete | ||||||
|           path: artifacts/ |           path: artifacts/ | ||||||
|           remote_path: "${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${GITHUB_REF##*/}/" |           remote_path: "${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${{steps.names.outputs.artifacts-path}}/" | ||||||
|           remote_host: ${{ secrets.RSYNC_DEPLOY_HOST }} |           remote_host: ${{ secrets.RSYNC_DEPLOY_HOST }} | ||||||
|           remote_port: ${{ secrets.RSYNC_DEPLOY_PORT }} |           remote_port: ${{ secrets.RSYNC_DEPLOY_PORT }} | ||||||
|           remote_user: ${{ secrets.RSYNC_DEPLOY_USER }} |           remote_user: ${{ secrets.RSYNC_DEPLOY_USER }} | ||||||
| @ -190,3 +205,21 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           args: -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }} |           args: -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }} | ||||||
| 
 | 
 | ||||||
|  |       - name: Find Previous Comment | ||||||
|  |         if: ${{ !github.event.pull_request.head.repo.fork && 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: 'to flash the' | ||||||
|  | 
 | ||||||
|  |       - name: Create or update comment | ||||||
|  |         if: ${{ !github.event.pull_request.head.repo.fork && 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: | | ||||||
|  |             [Click here](https://update.flipperzero.one/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.latest-target}}-full-${{steps.names.outputs.suffix}}.dfu&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}) to flash the `${{steps.names.outputs.short-hash}}` version of this branch via WebUSB. | ||||||
|  |           edit-mode: replace | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								.github/workflows/lint_c.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @ -43,19 +43,19 @@ jobs: | |||||||
|       - name: 'Build docker image' |       - name: 'Build docker image' | ||||||
|         uses: ./.github/actions/docker |         uses: ./.github/actions/docker | ||||||
| 
 | 
 | ||||||
|       - name: 'Check syntax' |       - name: 'Check code formatting' | ||||||
|         id: syntax_check |         id: syntax_check | ||||||
|         uses: ./.github/actions/docker |         uses: ./.github/actions/docker | ||||||
|         with: |         with: | ||||||
|           run: SET_GH_OUTPUT=1 /syntax_check.sh |           run: SET_GH_OUTPUT=1 /syntax_check.sh | ||||||
| 
 | 
 | ||||||
|       - name: Report syntax errors |       - name: Report code formatting errors | ||||||
|         if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request |         if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request | ||||||
|         uses: peter-evans/create-or-update-comment@v1 |         uses: peter-evans/create-or-update-comment@v1 | ||||||
|         with: |         with: | ||||||
|           issue-number: ${{ github.event.pull_request.number }} |           issue-number: ${{ github.event.pull_request.number }} | ||||||
|           body: | |           body: | | ||||||
|             Please fix following syntax errors: |             Please fix following code formatting errors: | ||||||
|             ``` |             ``` | ||||||
|             ${{ steps.syntax_check.outputs.errors }} |             ${{ steps.syntax_check.outputs.errors }} | ||||||
|             ``` |             ``` | ||||||
|  | |||||||
| @ -35,7 +35,6 @@ AccessorApp::AccessorApp() | |||||||
|     : onewire_master{&ibutton_gpio} { |     : onewire_master{&ibutton_gpio} { | ||||||
|     furi_hal_power_insomnia_enter(); |     furi_hal_power_insomnia_enter(); | ||||||
|     notification = static_cast<NotificationApp*>(furi_record_open("notification")); |     notification = static_cast<NotificationApp*>(furi_record_open("notification")); | ||||||
|     notify_init(); |  | ||||||
|     furi_hal_power_enable_otg(); |     furi_hal_power_enable_otg(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -104,17 +103,6 @@ AccessorApp::Scene AccessorApp::get_previous_scene() { | |||||||
| 
 | 
 | ||||||
| /***************************** NOTIFY *******************************/ | /***************************** NOTIFY *******************************/ | ||||||
| 
 | 
 | ||||||
| void AccessorApp::notify_init() { |  | ||||||
|     GPIO_InitTypeDef GPIO_InitStruct = {0}; |  | ||||||
| 
 |  | ||||||
|     GPIO_InitStruct.Pin = PB3_Pin; |  | ||||||
|     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |  | ||||||
|     GPIO_InitStruct.Pull = GPIO_NOPULL; |  | ||||||
|     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; |  | ||||||
|     GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; |  | ||||||
|     HAL_GPIO_Init(PB3_GPIO_Port, &GPIO_InitStruct); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void AccessorApp::notify_green_blink() { | void AccessorApp::notify_green_blink() { | ||||||
|     notification_message(notification, &sequence_blink_green_10); |     notification_message(notification, &sequence_blink_green_10); | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,9 +29,7 @@ public: | |||||||
|     bool switch_to_previous_scene(uint8_t count = 1); |     bool switch_to_previous_scene(uint8_t count = 1); | ||||||
|     Scene get_previous_scene(); |     Scene get_previous_scene(); | ||||||
| 
 | 
 | ||||||
|     void notify_init(); |  | ||||||
|     void notify_green_blink(); |     void notify_green_blink(); | ||||||
| 
 |  | ||||||
|     void notify_success(); |     void notify_success(); | ||||||
| 
 | 
 | ||||||
|     char* get_text_store(); |     char* get_text_store(); | ||||||
|  | |||||||
| @ -148,7 +148,7 @@ const FlipperApplication FLIPPER_APPS[] = { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef APP_SUBGHZ | #ifdef APP_SUBGHZ | ||||||
|     {.app = subghz_app, .name = "Sub-1 GHz", .stack_size = 2048, .icon = &A_Sub1ghz_14}, |     {.app = subghz_app, .name = "Sub-GHz", .stack_size = 2048, .icon = &A_Sub1ghz_14}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef APP_LF_RFID | #ifdef APP_LF_RFID | ||||||
|  | |||||||
| @ -2,20 +2,6 @@ | |||||||
| 
 | 
 | ||||||
| static bool archive_get_filenames(ArchiveApp* archive); | static bool archive_get_filenames(ArchiveApp* archive); | ||||||
| 
 | 
 | ||||||
| static bool is_favorite(ArchiveApp* archive, ArchiveFile_t* file) { |  | ||||||
|     FileInfo file_info; |  | ||||||
|     FS_Error fr; |  | ||||||
|     string_t path; |  | ||||||
| 
 |  | ||||||
|     string_init_printf(path, "%s/%s", get_favorites_path(), string_get_cstr(file->name)); |  | ||||||
| 
 |  | ||||||
|     fr = storage_common_stat(archive->api, string_get_cstr(path), &file_info); |  | ||||||
|     FURI_LOG_I("FAV", "%d", fr); |  | ||||||
| 
 |  | ||||||
|     string_clear(path); |  | ||||||
|     return (fr == FSE_OK || fr == FSE_EXIST); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void update_offset(ArchiveApp* archive) { | static void update_offset(ArchiveApp* archive) { | ||||||
|     furi_assert(archive); |     furi_assert(archive); | ||||||
| 
 | 
 | ||||||
| @ -92,6 +78,7 @@ static void archive_leave_dir(ArchiveApp* archive) { | |||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|     archive_switch_dir(archive, string_get_cstr(archive->browser.path)); |     archive_switch_dir(archive, string_get_cstr(archive->browser.path)); | ||||||
|  |     update_offset(archive); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void archive_enter_dir(ArchiveApp* archive, string_t name) { | static void archive_enter_dir(ArchiveApp* archive, string_t name) { | ||||||
| @ -144,26 +131,200 @@ static void set_file_type(ArchiveFile_t* file, FileInfo* file_info) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool archive_get_filenames(ArchiveApp* archive) { | static void archive_file_append(ArchiveApp* archive, const char* path, string_t string) { | ||||||
|     furi_assert(archive); |     furi_assert(archive); | ||||||
|  |     furi_assert(path); | ||||||
|  |     furi_assert(string); | ||||||
|  | 
 | ||||||
|  |     FileWorker* file_worker = file_worker_alloc(false); | ||||||
|  | 
 | ||||||
|  |     if(!file_worker_open(file_worker, path, FSAM_WRITE, FSOM_OPEN_APPEND)) { | ||||||
|  |         FURI_LOG_E("Archive", "Append open error"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) { | ||||||
|  |         FURI_LOG_E("Archive", "Append write error"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     file_worker_close(file_worker); | ||||||
|  |     file_worker_free(file_worker); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void archive_view_add_item(ArchiveApp* archive, FileInfo* file_info, const char* name) { | ||||||
|  |     furi_assert(archive); | ||||||
|  |     furi_assert(file_info); | ||||||
|  |     furi_assert(name); | ||||||
| 
 | 
 | ||||||
|     ArchiveFile_t item; |     ArchiveFile_t item; | ||||||
|  | 
 | ||||||
|  |     if(filter_by_extension(archive, file_info, name)) { | ||||||
|  |         ArchiveFile_t_init(&item); | ||||||
|  |         string_init_set_str(item.name, name); | ||||||
|  |         set_file_type(&item, file_info); | ||||||
|  | 
 | ||||||
|  |         with_view_model( | ||||||
|  |             archive->view_archive_main, (ArchiveViewModel * model) { | ||||||
|  |                 files_array_push_back(model->files, item); | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |         ArchiveFile_t_clear(&item); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool archive_is_favorite(ArchiveApp* archive, ArchiveFile_t* selected) { | ||||||
|  |     furi_assert(selected); | ||||||
|  |     string_t path; | ||||||
|  |     string_t buffer; | ||||||
|  |     string_init(buffer); | ||||||
|  |     bool found = false; | ||||||
|  | 
 | ||||||
|  |     string_init_printf( | ||||||
|  |         path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(selected->name)); | ||||||
|  | 
 | ||||||
|  |     bool load_result = | ||||||
|  |         file_worker_open(archive->file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_ALWAYS); | ||||||
|  | 
 | ||||||
|  |     if(load_result) { | ||||||
|  |         while(1) { | ||||||
|  |             if(!file_worker_read_until(archive->file_worker, buffer, '\n')) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!string_size(buffer)) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!string_search(buffer, path)) { | ||||||
|  |                 found = true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(buffer); | ||||||
|  |     string_clear(path); | ||||||
|  |     file_worker_close(archive->file_worker); | ||||||
|  | 
 | ||||||
|  |     return found; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool archive_favorites_read(ArchiveApp* archive) { | ||||||
|  |     string_t buffer; | ||||||
|  |     FileInfo file_info; | ||||||
|  |     string_init(buffer); | ||||||
|  | 
 | ||||||
|  |     bool load_result = | ||||||
|  |         file_worker_open(archive->file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||||
|  | 
 | ||||||
|  |     if(load_result) { | ||||||
|  |         while(1) { | ||||||
|  |             if(!file_worker_read_until(archive->file_worker, buffer, '\n')) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!string_size(buffer)) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             archive_view_add_item(archive, &file_info, string_get_cstr(buffer)); | ||||||
|  |             string_clean(buffer); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     string_clear(buffer); | ||||||
|  |     file_worker_close(archive->file_worker); | ||||||
|  | 
 | ||||||
|  |     return load_result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool | ||||||
|  |     archive_favorites_rename(ArchiveApp* archive, ArchiveFile_t* selected, const char* dst) { | ||||||
|  |     furi_assert(selected); | ||||||
|  |     string_t path; | ||||||
|  |     string_t buffer; | ||||||
|  |     string_t temp; | ||||||
|  | 
 | ||||||
|  |     string_init(buffer); | ||||||
|  |     string_init(temp); | ||||||
|  | 
 | ||||||
|  |     string_init_printf( | ||||||
|  |         path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(selected->name)); | ||||||
|  |     bool load_result = | ||||||
|  |         file_worker_open(archive->file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||||
|  | 
 | ||||||
|  |     if(load_result) { | ||||||
|  |         while(1) { | ||||||
|  |             if(!file_worker_read_until(archive->file_worker, buffer, '\n')) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!string_size(buffer)) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             string_printf( | ||||||
|  |                 temp, "%s\r\n", string_search(buffer, path) ? string_get_cstr(buffer) : dst); | ||||||
|  |             archive_file_append(archive, ARCHIVE_FAV_TEMP_PATH, temp); | ||||||
|  |             string_clean(temp); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(temp); | ||||||
|  |     string_clear(buffer); | ||||||
|  |     string_clear(path); | ||||||
|  | 
 | ||||||
|  |     file_worker_close(archive->file_worker); | ||||||
|  |     file_worker_remove(archive->file_worker, ARCHIVE_FAV_PATH); | ||||||
|  |     file_worker_rename(archive->file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); | ||||||
|  | 
 | ||||||
|  |     return load_result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool archive_favorites_delete(ArchiveApp* archive, ArchiveFile_t* selected) { | ||||||
|  |     furi_assert(selected); | ||||||
|  |     string_t path; | ||||||
|  |     string_t buffer; | ||||||
|  |     string_init(buffer); | ||||||
|  | 
 | ||||||
|  |     string_init_printf( | ||||||
|  |         path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(selected->name)); | ||||||
|  | 
 | ||||||
|  |     bool load_result = | ||||||
|  |         file_worker_open(archive->file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||||
|  |     if(load_result) { | ||||||
|  |         while(1) { | ||||||
|  |             if(!file_worker_read_until(archive->file_worker, buffer, '\n')) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!string_size(buffer)) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(string_search(buffer, path)) { | ||||||
|  |                 string_t temp; | ||||||
|  |                 string_init_printf(temp, "%s\r\n", string_get_cstr(buffer)); | ||||||
|  |                 archive_file_append(archive, ARCHIVE_FAV_TEMP_PATH, temp); | ||||||
|  |                 string_clear(temp); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(buffer); | ||||||
|  |     string_clear(path); | ||||||
|  | 
 | ||||||
|  |     file_worker_close(archive->file_worker); | ||||||
|  |     file_worker_remove(archive->file_worker, ARCHIVE_FAV_PATH); | ||||||
|  |     file_worker_rename(archive->file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); | ||||||
|  | 
 | ||||||
|  |     return load_result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool archive_read_dir(ArchiveApp* archive) { | ||||||
|     FileInfo file_info; |     FileInfo file_info; | ||||||
|     File* directory = storage_file_alloc(archive->api); |     File* directory = storage_file_alloc(archive->api); | ||||||
|     char name[MAX_NAME_LEN]; |     char name[MAX_NAME_LEN]; | ||||||
| 
 | 
 | ||||||
|     with_view_model( |  | ||||||
|         archive->view_archive_main, (ArchiveViewModel * model) { |  | ||||||
|             files_array_clean(model->files); |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     if(!storage_dir_open(directory, string_get_cstr(archive->browser.path))) { |     if(!storage_dir_open(directory, string_get_cstr(archive->browser.path))) { | ||||||
|         storage_dir_close(directory); |         storage_dir_close(directory); | ||||||
|         storage_file_free(directory); |         storage_file_free(directory); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     while(1) { |     while(1) { | ||||||
|         if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) { |         if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) { | ||||||
|             break; |             break; | ||||||
| @ -180,31 +341,34 @@ static bool archive_get_filenames(ArchiveApp* archive) { | |||||||
|         if(files_cnt > MAX_FILES) { |         if(files_cnt > MAX_FILES) { | ||||||
|             break; |             break; | ||||||
|         } else if(storage_file_get_error(directory) == FSE_OK) { |         } else if(storage_file_get_error(directory) == FSE_OK) { | ||||||
|             if(filter_by_extension(archive, &file_info, name)) { |             archive_view_add_item(archive, &file_info, name); | ||||||
|                 ArchiveFile_t_init(&item); |  | ||||||
|                 string_init_set(item.name, name); |  | ||||||
|                 set_file_type(&item, &file_info); |  | ||||||
| 
 |  | ||||||
|                 with_view_model( |  | ||||||
|                     archive->view_archive_main, (ArchiveViewModel * model) { |  | ||||||
|                         files_array_push_back(model->files, item); |  | ||||||
|                         return true; |  | ||||||
|                     }); |  | ||||||
| 
 |  | ||||||
|                 ArchiveFile_t_clear(&item); |  | ||||||
|             } |  | ||||||
|         } else { |         } else { | ||||||
|             storage_dir_close(directory); |             storage_dir_close(directory); | ||||||
|             storage_file_free(directory); |             storage_file_free(directory); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     storage_dir_close(directory); |     storage_dir_close(directory); | ||||||
|     storage_file_free(directory); |     storage_file_free(directory); | ||||||
|  | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool archive_get_filenames(ArchiveApp* archive) { | ||||||
|  |     furi_assert(archive); | ||||||
|  |     with_view_model( | ||||||
|  |         archive->view_archive_main, (ArchiveViewModel * model) { | ||||||
|  |             files_array_clean(model->files); | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     if(archive->browser.tab_id != ArchiveTabFavorites) { | ||||||
|  |         archive_read_dir(archive); | ||||||
|  |     } else { | ||||||
|  |         archive_favorites_read(archive); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
| static void archive_exit_callback(ArchiveApp* archive) { | static void archive_exit_callback(ArchiveApp* archive) { | ||||||
|     furi_assert(archive); |     furi_assert(archive); | ||||||
| 
 | 
 | ||||||
| @ -220,24 +384,17 @@ static uint32_t archive_previous_callback(void* context) { | |||||||
| /* file menu */ | /* file menu */ | ||||||
| static void archive_add_to_favorites(ArchiveApp* archive) { | static void archive_add_to_favorites(ArchiveApp* archive) { | ||||||
|     furi_assert(archive); |     furi_assert(archive); | ||||||
| 
 |  | ||||||
|     storage_common_mkdir(archive->api, get_favorites_path()); |  | ||||||
| 
 |  | ||||||
|     string_t buffer_src; |     string_t buffer_src; | ||||||
|     string_t buffer_dst; |  | ||||||
| 
 | 
 | ||||||
|     string_init_printf( |     string_init_printf( | ||||||
|         buffer_src, |         buffer_src, | ||||||
|         "%s/%s", |         "%s/%s\r\n", | ||||||
|         string_get_cstr(archive->browser.path), |         string_get_cstr(archive->browser.path), | ||||||
|         string_get_cstr(archive->browser.name)); |         string_get_cstr(archive->browser.name)); | ||||||
|     string_init_printf( |  | ||||||
|         buffer_dst, "%s/%s", get_favorites_path(), string_get_cstr(archive->browser.name)); |  | ||||||
| 
 | 
 | ||||||
|     storage_common_copy(archive->api, string_get_cstr(buffer_src), string_get_cstr(buffer_dst)); |     archive_file_append(archive, ARCHIVE_FAV_PATH, buffer_src); | ||||||
| 
 | 
 | ||||||
|     string_clear(buffer_src); |     string_clear(buffer_src); | ||||||
|     string_clear(buffer_dst); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void archive_text_input_callback(void* context) { | static void archive_text_input_callback(void* context) { | ||||||
| @ -259,6 +416,7 @@ static void archive_text_input_callback(void* context) { | |||||||
|         string_get_cstr(archive->browser.path), |         string_get_cstr(archive->browser.path), | ||||||
|         archive->browser.text_input_buffer); |         archive->browser.text_input_buffer); | ||||||
| 
 | 
 | ||||||
|  |     string_set(archive->browser.name, archive->browser.text_input_buffer); | ||||||
|     // append extension
 |     // append extension
 | ||||||
| 
 | 
 | ||||||
|     ArchiveFile_t* file; |     ArchiveFile_t* file; | ||||||
| @ -267,18 +425,38 @@ static void archive_text_input_callback(void* context) { | |||||||
|         archive->view_archive_main, (ArchiveViewModel * model) { |         archive->view_archive_main, (ArchiveViewModel * model) { | ||||||
|             file = files_array_get( |             file = files_array_get( | ||||||
|                 model->files, CLAMP(model->idx, files_array_size(model->files) - 1, 0)); |                 model->files, CLAMP(model->idx, files_array_size(model->files) - 1, 0)); | ||||||
|  |             file->fav = archive_is_favorite(archive, file); | ||||||
|  | 
 | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|     string_cat(buffer_dst, known_ext[file->type]); |     string_cat(buffer_dst, known_ext[file->type]); | ||||||
|     storage_common_rename(archive->api, string_get_cstr(buffer_src), string_get_cstr(buffer_dst)); |     storage_common_rename(archive->api, string_get_cstr(buffer_src), string_get_cstr(buffer_dst)); | ||||||
| 
 | 
 | ||||||
|  |     if(file->fav) { | ||||||
|  |         archive_favorites_rename(archive, file, string_get_cstr(buffer_dst)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewMain); |     view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewMain); | ||||||
|  |     archive_get_filenames(archive); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         archive->view_archive_main, (ArchiveViewModel * model) { | ||||||
|  |             model->idx = 0; | ||||||
|  |             while(model->idx < files_array_size(model->files)) { | ||||||
|  |                 ArchiveFile_t* current = files_array_get(model->files, model->idx); | ||||||
|  |                 if(!string_search(current->name, archive->browser.text_input_buffer)) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 ++model->idx; | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     update_offset(archive); | ||||||
| 
 | 
 | ||||||
|     string_clear(buffer_src); |     string_clear(buffer_src); | ||||||
|     string_clear(buffer_dst); |     string_clear(buffer_dst); | ||||||
| 
 |  | ||||||
|     archive_get_filenames(archive); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void archive_enter_text_input(ArchiveApp* archive) { | static void archive_enter_text_input(ArchiveApp* archive) { | ||||||
| @ -314,7 +492,8 @@ static void archive_show_file_menu(ArchiveApp* archive) { | |||||||
|             selected = files_array_get(model->files, model->idx); |             selected = files_array_get(model->files, model->idx); | ||||||
|             model->menu = true; |             model->menu = true; | ||||||
|             model->menu_idx = 0; |             model->menu_idx = 0; | ||||||
|             selected->fav = is_favorite(archive, selected); |             selected->fav = is_known_app(selected->type) ? archive_is_favorite(archive, selected) : | ||||||
|  |                                                            false; | ||||||
| 
 | 
 | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| @ -340,29 +519,22 @@ static void archive_open_app(ArchiveApp* archive, const char* app_name, const ch | |||||||
|     loader_start(archive->loader, app_name, args); |     loader_start(archive->loader, app_name, args); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void archive_delete_file(ArchiveApp* archive, ArchiveFile_t* file, bool fav, bool orig) { | static void archive_delete_file(ArchiveApp* archive, ArchiveFile_t* file) { | ||||||
|     furi_assert(archive); |     furi_assert(archive); | ||||||
|     furi_assert(file); |     furi_assert(file); | ||||||
| 
 | 
 | ||||||
|     string_t path; |     string_t path; | ||||||
|     string_init(path); |     string_init(path); | ||||||
| 
 | 
 | ||||||
|     if(!fav && !orig) { |     string_printf( | ||||||
|         string_printf( |         path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(file->name)); | ||||||
|             path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(file->name)); |  | ||||||
|         storage_common_remove(archive->api, string_get_cstr(path)); |  | ||||||
| 
 | 
 | ||||||
|     } else { // remove from favorites
 |     if(archive_is_favorite(archive, file)) { // remove from favorites
 | ||||||
|         string_printf(path, "%s/%s", get_favorites_path(), string_get_cstr(file->name)); |         archive_favorites_delete(archive, file); | ||||||
|         storage_common_remove(archive->api, string_get_cstr(path)); |  | ||||||
| 
 |  | ||||||
|         if(orig) { // remove original file
 |  | ||||||
|             string_printf( |  | ||||||
|                 path, "%s/%s", get_default_path(file->type), string_get_cstr(file->name)); |  | ||||||
|             storage_common_remove(archive->api, string_get_cstr(path)); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     file_worker_remove(archive->file_worker, string_get_cstr(path)); | ||||||
|  | 
 | ||||||
|     string_clear(path); |     string_clear(path); | ||||||
|     archive_get_filenames(archive); |     archive_get_filenames(archive); | ||||||
| 
 | 
 | ||||||
| @ -375,6 +547,24 @@ static void archive_delete_file(ArchiveApp* archive, ArchiveFile_t* file, bool f | |||||||
|     update_offset(archive); |     update_offset(archive); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void | ||||||
|  |     archive_run_in_app(ArchiveApp* archive, ArchiveFile_t* selected, bool full_path_provided) { | ||||||
|  |     string_t full_path; | ||||||
|  | 
 | ||||||
|  |     if(!full_path_provided) { | ||||||
|  |         string_init_printf( | ||||||
|  |             full_path, | ||||||
|  |             "%s/%s", | ||||||
|  |             string_get_cstr(archive->browser.path), | ||||||
|  |             string_get_cstr(selected->name)); | ||||||
|  |     } else { | ||||||
|  |         string_init_set(full_path, selected->name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     archive_open_app(archive, flipper_app_name[selected->type], string_get_cstr(full_path)); | ||||||
|  |     string_clear(full_path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void archive_file_menu_callback(ArchiveApp* archive) { | static void archive_file_menu_callback(ArchiveApp* archive) { | ||||||
|     furi_assert(archive); |     furi_assert(archive); | ||||||
| 
 | 
 | ||||||
| @ -391,27 +581,17 @@ static void archive_file_menu_callback(ArchiveApp* archive) { | |||||||
|     switch(idx) { |     switch(idx) { | ||||||
|     case 0: |     case 0: | ||||||
|         if(is_known_app(selected->type)) { |         if(is_known_app(selected->type)) { | ||||||
|             string_t full_path; |             archive_run_in_app(archive, selected, false); | ||||||
|             string_init_printf( |  | ||||||
|                 full_path, |  | ||||||
|                 "%s/%s", |  | ||||||
|                 string_get_cstr(archive->browser.path), |  | ||||||
|                 string_get_cstr(selected->name)); |  | ||||||
| 
 |  | ||||||
|             archive_open_app( |  | ||||||
|                 archive, flipper_app_name[selected->type], string_get_cstr(full_path)); |  | ||||||
| 
 |  | ||||||
|             string_clear(full_path); |  | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     case 1: |     case 1: | ||||||
|         if(is_known_app(selected->type)) { |         if(is_known_app(selected->type)) { | ||||||
|             if(!is_favorite(archive, selected)) { |             if(!archive_is_favorite(archive, selected)) { | ||||||
|                 string_set(archive->browser.name, selected->name); |                 string_set(archive->browser.name, selected->name); | ||||||
|                 archive_add_to_favorites(archive); |                 archive_add_to_favorites(archive); | ||||||
|             } else { |             } else { | ||||||
|                 // delete from favorites
 |                 // delete from favorites
 | ||||||
|                 archive_delete_file(archive, selected, true, false); |                 archive_favorites_delete(archive, selected); | ||||||
|             } |             } | ||||||
|             archive_close_file_menu(archive); |             archive_close_file_menu(archive); | ||||||
|         } |         } | ||||||
| @ -424,13 +604,7 @@ static void archive_file_menu_callback(ArchiveApp* archive) { | |||||||
|         break; |         break; | ||||||
|     case 3: |     case 3: | ||||||
|         // confirmation?
 |         // confirmation?
 | ||||||
|         if(is_favorite(archive, selected)) { |         archive_delete_file(archive, selected); | ||||||
|             //delete both fav & original
 |  | ||||||
|             archive_delete_file(archive, selected, true, true); |  | ||||||
|         } else { |  | ||||||
|             archive_delete_file(archive, selected, false, false); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         archive_close_file_menu(archive); |         archive_close_file_menu(archive); | ||||||
| 
 | 
 | ||||||
|         break; |         break; | ||||||
| @ -545,7 +719,13 @@ static bool archive_view_input(InputEvent* event, void* context) { | |||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if(event->type == InputTypeShort) { |                 if(event->type == InputTypeShort) { | ||||||
|                     archive_show_file_menu(archive); |                     if(archive->browser.tab_id == ArchiveTabFavorites) { | ||||||
|  |                         if(is_known_app(selected->type)) { | ||||||
|  |                             archive_run_in_app(archive, selected, true); | ||||||
|  |                         } | ||||||
|  |                     } else { | ||||||
|  |                         archive_show_file_menu(archive); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -559,6 +739,8 @@ static bool archive_view_input(InputEvent* event, void* context) { | |||||||
| void archive_free(ArchiveApp* archive) { | void archive_free(ArchiveApp* archive) { | ||||||
|     furi_assert(archive); |     furi_assert(archive); | ||||||
| 
 | 
 | ||||||
|  |     file_worker_free(archive->file_worker); | ||||||
|  | 
 | ||||||
|     view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewMain); |     view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewMain); | ||||||
|     view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput); |     view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput); | ||||||
|     view_dispatcher_free(archive->view_dispatcher); |     view_dispatcher_free(archive->view_dispatcher); | ||||||
| @ -598,6 +780,7 @@ ArchiveApp* archive_alloc() { | |||||||
|     archive->api = furi_record_open("storage"); |     archive->api = furi_record_open("storage"); | ||||||
|     archive->text_input = text_input_alloc(); |     archive->text_input = text_input_alloc(); | ||||||
|     archive->view_archive_main = view_alloc(); |     archive->view_archive_main = view_alloc(); | ||||||
|  |     archive->file_worker = file_worker_alloc(true); | ||||||
| 
 | 
 | ||||||
|     furi_check(archive->event_queue); |     furi_check(archive->event_queue); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -13,10 +13,13 @@ | |||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| #include "archive_views.h" | #include "archive_views.h" | ||||||
| #include "applications.h" | #include "applications.h" | ||||||
|  | #include "file-worker.h" | ||||||
| 
 | 
 | ||||||
| #define MAX_DEPTH 32 | #define MAX_DEPTH 32 | ||||||
| #define MAX_FILES 100 //temp
 | #define MAX_FILES 100 //temp
 | ||||||
| #define MAX_FILE_SIZE 128 | #define MAX_FILE_SIZE 128 | ||||||
|  | #define ARCHIVE_FAV_PATH "/any/favorites.txt" | ||||||
|  | #define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     ArchiveViewMain, |     ArchiveViewMain, | ||||||
| @ -27,7 +30,7 @@ typedef enum { | |||||||
| static const char* flipper_app_name[] = { | static const char* flipper_app_name[] = { | ||||||
|     [ArchiveFileTypeIButton] = "iButton", |     [ArchiveFileTypeIButton] = "iButton", | ||||||
|     [ArchiveFileTypeNFC] = "NFC", |     [ArchiveFileTypeNFC] = "NFC", | ||||||
|     [ArchiveFileTypeSubOne] = "Sub-1 GHz", |     [ArchiveFileTypeSubGhz] = "Sub-GHz", | ||||||
|     [ArchiveFileTypeLFRFID] = "125 kHz RFID", |     [ArchiveFileTypeLFRFID] = "125 kHz RFID", | ||||||
|     [ArchiveFileTypeIrda] = "Infrared", |     [ArchiveFileTypeIrda] = "Infrared", | ||||||
| }; | }; | ||||||
| @ -35,7 +38,7 @@ static const char* flipper_app_name[] = { | |||||||
| static const char* known_ext[] = { | static const char* known_ext[] = { | ||||||
|     [ArchiveFileTypeIButton] = ".ibtn", |     [ArchiveFileTypeIButton] = ".ibtn", | ||||||
|     [ArchiveFileTypeNFC] = ".nfc", |     [ArchiveFileTypeNFC] = ".nfc", | ||||||
|     [ArchiveFileTypeSubOne] = ".sub", |     [ArchiveFileTypeSubGhz] = ".sub", | ||||||
|     [ArchiveFileTypeLFRFID] = ".rfid", |     [ArchiveFileTypeLFRFID] = ".rfid", | ||||||
|     [ArchiveFileTypeIrda] = ".ir", |     [ArchiveFileTypeIrda] = ".ir", | ||||||
| }; | }; | ||||||
| @ -44,7 +47,7 @@ static const char* tab_default_paths[] = { | |||||||
|     [ArchiveTabFavorites] = "/any/favorites", |     [ArchiveTabFavorites] = "/any/favorites", | ||||||
|     [ArchiveTabIButton] = "/any/ibutton", |     [ArchiveTabIButton] = "/any/ibutton", | ||||||
|     [ArchiveTabNFC] = "/any/nfc", |     [ArchiveTabNFC] = "/any/nfc", | ||||||
|     [ArchiveTabSubOne] = "/any/subghz/saved", |     [ArchiveTabSubGhz] = "/any/subghz/saved", | ||||||
|     [ArchiveTabLFRFID] = "/any/lfrfid", |     [ArchiveTabLFRFID] = "/any/lfrfid", | ||||||
|     [ArchiveTabIrda] = "/any/irda", |     [ArchiveTabIrda] = "/any/irda", | ||||||
|     [ArchiveTabBrowser] = "/any", |     [ArchiveTabBrowser] = "/any", | ||||||
| @ -56,8 +59,8 @@ static inline const char* get_tab_ext(ArchiveTabEnum tab) { | |||||||
|         return known_ext[ArchiveFileTypeIButton]; |         return known_ext[ArchiveFileTypeIButton]; | ||||||
|     case ArchiveTabNFC: |     case ArchiveTabNFC: | ||||||
|         return known_ext[ArchiveFileTypeNFC]; |         return known_ext[ArchiveFileTypeNFC]; | ||||||
|     case ArchiveTabSubOne: |     case ArchiveTabSubGhz: | ||||||
|         return known_ext[ArchiveFileTypeSubOne]; |         return known_ext[ArchiveFileTypeSubGhz]; | ||||||
|     case ArchiveTabLFRFID: |     case ArchiveTabLFRFID: | ||||||
|         return known_ext[ArchiveFileTypeLFRFID]; |         return known_ext[ArchiveFileTypeLFRFID]; | ||||||
|     case ArchiveTabIrda: |     case ArchiveTabIrda: | ||||||
| @ -73,8 +76,8 @@ static inline const char* get_default_path(ArchiveFileTypeEnum type) { | |||||||
|         return tab_default_paths[ArchiveTabIButton]; |         return tab_default_paths[ArchiveTabIButton]; | ||||||
|     case ArchiveFileTypeNFC: |     case ArchiveFileTypeNFC: | ||||||
|         return tab_default_paths[ArchiveTabNFC]; |         return tab_default_paths[ArchiveTabNFC]; | ||||||
|     case ArchiveFileTypeSubOne: |     case ArchiveFileTypeSubGhz: | ||||||
|         return tab_default_paths[ArchiveTabSubOne]; |         return tab_default_paths[ArchiveTabSubGhz]; | ||||||
|     case ArchiveFileTypeLFRFID: |     case ArchiveFileTypeLFRFID: | ||||||
|         return tab_default_paths[ArchiveTabLFRFID]; |         return tab_default_paths[ArchiveTabLFRFID]; | ||||||
|     case ArchiveFileTypeIrda: |     case ArchiveFileTypeIrda: | ||||||
| @ -101,6 +104,13 @@ typedef struct { | |||||||
|     EventType type; |     EventType type; | ||||||
| } AppEvent; | } AppEvent; | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     FavoritesCheck, | ||||||
|  |     FavoritesRead, | ||||||
|  |     FavoritesDelete, | ||||||
|  |     FavoritesRename, | ||||||
|  | } FavActionsEnum; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     ArchiveTabEnum tab_id; |     ArchiveTabEnum tab_id; | ||||||
|     string_t name; |     string_t name; | ||||||
| @ -123,5 +133,6 @@ struct ArchiveApp { | |||||||
|     TextInput* text_input; |     TextInput* text_input; | ||||||
| 
 | 
 | ||||||
|     Storage* api; |     Storage* api; | ||||||
|  |     FileWorker* file_worker; | ||||||
|     ArchiveBrowser browser; |     ArchiveBrowser browser; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ static const char* ArchiveTabNames[] = { | |||||||
|     [ArchiveTabFavorites] = "Favorites", |     [ArchiveTabFavorites] = "Favorites", | ||||||
|     [ArchiveTabIButton] = "iButton", |     [ArchiveTabIButton] = "iButton", | ||||||
|     [ArchiveTabNFC] = "NFC", |     [ArchiveTabNFC] = "NFC", | ||||||
|     [ArchiveTabSubOne] = "SubGhz", |     [ArchiveTabSubGhz] = "Sub-GHz", | ||||||
|     [ArchiveTabLFRFID] = "RFID LF", |     [ArchiveTabLFRFID] = "RFID LF", | ||||||
|     [ArchiveTabIrda] = "Infrared", |     [ArchiveTabIrda] = "Infrared", | ||||||
|     [ArchiveTabBrowser] = "Browser"}; |     [ArchiveTabBrowser] = "Browser"}; | ||||||
| @ -12,7 +12,7 @@ static const char* ArchiveTabNames[] = { | |||||||
| static const Icon* ArchiveItemIcons[] = { | static const Icon* ArchiveItemIcons[] = { | ||||||
|     [ArchiveFileTypeIButton] = &I_ibutt_10px, |     [ArchiveFileTypeIButton] = &I_ibutt_10px, | ||||||
|     [ArchiveFileTypeNFC] = &I_Nfc_10px, |     [ArchiveFileTypeNFC] = &I_Nfc_10px, | ||||||
|     [ArchiveFileTypeSubOne] = &I_sub1_10px, |     [ArchiveFileTypeSubGhz] = &I_sub1_10px, | ||||||
|     [ArchiveFileTypeLFRFID] = &I_125_10px, |     [ArchiveFileTypeLFRFID] = &I_125_10px, | ||||||
|     [ArchiveFileTypeIrda] = &I_ir_10px, |     [ArchiveFileTypeIrda] = &I_ir_10px, | ||||||
|     [ArchiveFileTypeFolder] = &I_dir_10px, |     [ArchiveFileTypeFolder] = &I_dir_10px, | ||||||
| @ -81,21 +81,21 @@ static void draw_list(Canvas* canvas, ArchiveViewModel* model) { | |||||||
|     size_t array_size = files_array_size(model->files); |     size_t array_size = files_array_size(model->files); | ||||||
|     bool scrollbar = array_size > 4; |     bool scrollbar = array_size > 4; | ||||||
| 
 | 
 | ||||||
|     string_t str_buff; |  | ||||||
|     char cstr_buff[MAX_NAME_LEN]; |  | ||||||
|     string_init(str_buff); |  | ||||||
| 
 |  | ||||||
|     for(size_t i = 0; i < MIN(array_size, MENU_ITEMS); ++i) { |     for(size_t i = 0; i < MIN(array_size, MENU_ITEMS); ++i) { | ||||||
|  |         string_t str_buff; | ||||||
|  |         char cstr_buff[MAX_NAME_LEN]; | ||||||
|  | 
 | ||||||
|         size_t idx = CLAMP(i + model->list_offset, array_size, 0); |         size_t idx = CLAMP(i + model->list_offset, array_size, 0); | ||||||
|         ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0)); |         ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0)); | ||||||
| 
 | 
 | ||||||
|         strlcpy(cstr_buff, string_get_cstr(file->name), string_size(file->name) + 1); |         string_init_set(str_buff, file->name); | ||||||
|         if(is_known_app(file->type)) archive_trim_file_ext(cstr_buff); |         string_right(str_buff, string_search_rchar(str_buff, '/') + 1); | ||||||
|         string_set_str(str_buff, cstr_buff); |         strlcpy(cstr_buff, string_get_cstr(str_buff), string_size(str_buff) + 1); | ||||||
| 
 | 
 | ||||||
|         if(is_known_app(file->type)) { |         if(is_known_app(file->type)) archive_trim_file_ext(cstr_buff); | ||||||
|             archive_trim_file_ext(cstr_buff); | 
 | ||||||
|         } |         string_clean(str_buff); | ||||||
|  |         string_set_str(str_buff, cstr_buff); | ||||||
| 
 | 
 | ||||||
|         elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); |         elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); | ||||||
| 
 | 
 | ||||||
| @ -107,7 +107,7 @@ static void draw_list(Canvas* canvas, ArchiveViewModel* model) { | |||||||
| 
 | 
 | ||||||
|         canvas_draw_icon(canvas, 2, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file->type]); |         canvas_draw_icon(canvas, 2, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file->type]); | ||||||
|         canvas_draw_str(canvas, 15, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); |         canvas_draw_str(canvas, 15, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); | ||||||
|         string_clean(str_buff); |         string_clear(str_buff); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(scrollbar) { |     if(scrollbar) { | ||||||
| @ -117,8 +117,6 @@ static void draw_list(Canvas* canvas, ArchiveViewModel* model) { | |||||||
|     if(model->menu) { |     if(model->menu) { | ||||||
|         render_item_menu(canvas, model); |         render_item_menu(canvas, model); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     string_clear(str_buff); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void archive_render_status_bar(Canvas* canvas, ArchiveViewModel* model) { | static void archive_render_status_bar(Canvas* canvas, ArchiveViewModel* model) { | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
| typedef enum { | typedef enum { | ||||||
|     ArchiveFileTypeIButton, |     ArchiveFileTypeIButton, | ||||||
|     ArchiveFileTypeNFC, |     ArchiveFileTypeNFC, | ||||||
|     ArchiveFileTypeSubOne, |     ArchiveFileTypeSubGhz, | ||||||
|     ArchiveFileTypeLFRFID, |     ArchiveFileTypeLFRFID, | ||||||
|     ArchiveFileTypeIrda, |     ArchiveFileTypeIrda, | ||||||
|     ArchiveFileTypeFolder, |     ArchiveFileTypeFolder, | ||||||
| @ -25,7 +25,7 @@ typedef enum { | |||||||
| typedef enum { | typedef enum { | ||||||
|     ArchiveTabFavorites, |     ArchiveTabFavorites, | ||||||
|     ArchiveTabLFRFID, |     ArchiveTabLFRFID, | ||||||
|     ArchiveTabSubOne, |     ArchiveTabSubGhz, | ||||||
|     ArchiveTabNFC, |     ArchiveTabNFC, | ||||||
|     ArchiveTabIButton, |     ArchiveTabIButton, | ||||||
|     ArchiveTabIrda, |     ArchiveTabIrda, | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ void cli_stdout_callback(void* _cookie, const char* data, size_t size) { | |||||||
|     furi_hal_vcp_tx((const uint8_t*)data, size); |     furi_hal_vcp_tx((const uint8_t*)data, size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cli_write(Cli* cli, uint8_t* buffer, size_t size) { | void cli_write(Cli* cli, const uint8_t* buffer, size_t size) { | ||||||
|     return furi_hal_vcp_tx(buffer, size); |     return furi_hal_vcp_tx(buffer, size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -300,6 +300,7 @@ void cli_process_input(Cli* cli) { | |||||||
|     if(c == CliSymbolAsciiTab) { |     if(c == CliSymbolAsciiTab) { | ||||||
|         cli_handle_autocomplete(cli); |         cli_handle_autocomplete(cli); | ||||||
|     } else if(c == CliSymbolAsciiSOH) { |     } else if(c == CliSymbolAsciiSOH) { | ||||||
|  |         osDelay(33); // We are too fast, Minicom is not ready yet
 | ||||||
|         cli_motd(); |         cli_motd(); | ||||||
|         cli_prompt(cli); |         cli_prompt(cli); | ||||||
|     } else if(c == CliSymbolAsciiETX) { |     } else if(c == CliSymbolAsciiETX) { | ||||||
|  | |||||||
| @ -88,7 +88,7 @@ bool cli_cmd_interrupt_received(Cli* cli); | |||||||
|  * @param size - size of buffer in bytes |  * @param size - size of buffer in bytes | ||||||
|  * @return bytes written |  * @return bytes written | ||||||
|  */ |  */ | ||||||
| void cli_write(Cli* cli, uint8_t* buffer, size_t size); | void cli_write(Cli* cli, const uint8_t* buffer, size_t size); | ||||||
| 
 | 
 | ||||||
| /* Read character
 | /* Read character
 | ||||||
|  * @param cli - Cli instance |  * @param cli - Cli instance | ||||||
|  | |||||||
| @ -22,42 +22,6 @@ typedef struct { | |||||||
|     EventType type; |     EventType type; | ||||||
| } KeypadTestEvent; | } KeypadTestEvent; | ||||||
| 
 | 
 | ||||||
| static const char* keypad_test_get_key_name(InputKey key) { |  | ||||||
|     switch(key) { |  | ||||||
|     case InputKeyOk: |  | ||||||
|         return "Ok"; |  | ||||||
|     case InputKeyBack: |  | ||||||
|         return "Back"; |  | ||||||
|     case InputKeyLeft: |  | ||||||
|         return "Left"; |  | ||||||
|     case InputKeyRight: |  | ||||||
|         return "Right"; |  | ||||||
|     case InputKeyUp: |  | ||||||
|         return "Up"; |  | ||||||
|     case InputKeyDown: |  | ||||||
|         return "Down"; |  | ||||||
|     default: |  | ||||||
|         return "Unknown"; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static const char* keypad_test_get_type_name(InputType type) { |  | ||||||
|     switch(type) { |  | ||||||
|     case InputTypePress: |  | ||||||
|         return "Press"; |  | ||||||
|     case InputTypeRelease: |  | ||||||
|         return "Release"; |  | ||||||
|     case InputTypeShort: |  | ||||||
|         return "Short"; |  | ||||||
|     case InputTypeLong: |  | ||||||
|         return "Long"; |  | ||||||
|     case InputTypeRepeat: |  | ||||||
|         return "Repeat"; |  | ||||||
|     default: |  | ||||||
|         return "Unknown"; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void keypad_test_reset_state(KeypadTestState* state) { | static void keypad_test_reset_state(KeypadTestState* state) { | ||||||
|     state->left = 0; |     state->left = 0; | ||||||
|     state->right = 0; |     state->right = 0; | ||||||
| @ -139,8 +103,8 @@ int32_t keypad_test_app(void* p) { | |||||||
|                 FURI_LOG_I( |                 FURI_LOG_I( | ||||||
|                     "KeypadTest", |                     "KeypadTest", | ||||||
|                     "key: %s type: %s", |                     "key: %s type: %s", | ||||||
|                     keypad_test_get_key_name(event.input.key), |                     input_get_key_name(event.input.key), | ||||||
|                     keypad_test_get_type_name(event.input.type)); |                     input_get_type_name(event.input.type)); | ||||||
| 
 | 
 | ||||||
|                 if(event.input.type == InputTypeLong && event.input.key == InputKeyBack) { |                 if(event.input.type == InputTypeLong && event.input.key == InputKeyBack) { | ||||||
|                     release_mutex(&state_mutex, state); |                     release_mutex(&state_mutex, state); | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ struct ViewHolder { | |||||||
| 
 | 
 | ||||||
|     BackCallback back_callback; |     BackCallback back_callback; | ||||||
|     void* back_context; |     void* back_context; | ||||||
|  | 
 | ||||||
|  |     uint8_t ongoing_input; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void view_holder_draw_callback(Canvas* canvas, void* context); | static void view_holder_draw_callback(Canvas* canvas, void* context); | ||||||
| @ -92,6 +94,7 @@ void view_holder_start(ViewHolder* view_holder) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void view_holder_stop(ViewHolder* view_holder) { | void view_holder_stop(ViewHolder* view_holder) { | ||||||
|  |     while(view_holder->ongoing_input) osDelay(1); | ||||||
|     view_port_enabled_set(view_holder->view_port, false); |     view_port_enabled_set(view_holder->view_port, false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -114,6 +117,21 @@ static void view_holder_draw_callback(Canvas* canvas, void* context) { | |||||||
| 
 | 
 | ||||||
| static void view_holder_input_callback(InputEvent* event, void* context) { | static void view_holder_input_callback(InputEvent* event, void* context) { | ||||||
|     ViewHolder* view_holder = context; |     ViewHolder* view_holder = context; | ||||||
|  | 
 | ||||||
|  |     uint8_t key_bit = (1 << event->key); | ||||||
|  |     if(event->type == InputTypePress) { | ||||||
|  |         view_holder->ongoing_input |= key_bit; | ||||||
|  |     } else if(event->type == InputTypeRelease) { | ||||||
|  |         view_holder->ongoing_input &= ~key_bit; | ||||||
|  |     } else if(!(view_holder->ongoing_input & key_bit)) { | ||||||
|  |         FURI_LOG_W( | ||||||
|  |             "ViewHolder", | ||||||
|  |             "non-complementary input, discarding key: %s, type: %s", | ||||||
|  |             input_get_key_name(event->key), | ||||||
|  |             input_get_type_name(event->type)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     bool is_consumed = false; |     bool is_consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(view_holder->view) { |     if(view_holder->view) { | ||||||
|  | |||||||
| @ -2,143 +2,134 @@ | |||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <input/input.h> |  | ||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     const char* name; |     const char* name; | ||||||
|     GpioPin pin; |     const GpioPin* pin; | ||||||
| } GpioItem; | } GpioItem; | ||||||
| 
 | 
 | ||||||
| const GpioItem GPIO_PINS[] = { | static const GpioItem GPIO_PINS[] = { | ||||||
|     {"1.2: PA7", {GPIOA, GPIO_PIN_7}}, |     {"1.2: PA7", &gpio_ext_pa7}, | ||||||
|     {"1.3: PA6", {GPIOA, GPIO_PIN_6}}, |     {"1.3: PA6", &gpio_ext_pa6}, | ||||||
|     {"1.4: PA4", {GPIOA, GPIO_PIN_4}}, |     {"1.4: PA4", &gpio_ext_pa4}, | ||||||
|     {"1.5: PB3", {GPIOB, GPIO_PIN_3}}, |     {"1.5: PB3", &gpio_ext_pb3}, | ||||||
|     {"1.6: PB2", {GPIOB, GPIO_PIN_2}}, |     {"1.6: PB2", &gpio_ext_pb2}, | ||||||
|     {"1.7: PC3", {GPIOC, GPIO_PIN_3}}, |     {"1.7: PC3", &gpio_ext_pc3}, | ||||||
| 
 |     {"2.7: PC1", &gpio_ext_pc1}, | ||||||
|     {"2.7: PC1", {GPIOC, GPIO_PIN_1}}, |     {"2.8: PC0", &gpio_ext_pc0}, | ||||||
|     {"2.8: PC0", {GPIOC, GPIO_PIN_0}}, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | static const size_t GPIO_PINS_COUNT = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); | ||||||
|     EventTypeTick, |  | ||||||
|     EventTypeKey, |  | ||||||
| } EventType; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     union { |  | ||||||
|         InputEvent input; |  | ||||||
|     } value; |  | ||||||
|     EventType type; |  | ||||||
| } AppEvent; |  | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     osMessageQueueId_t input_queue; | ||||||
|     uint8_t gpio_index; |     uint8_t gpio_index; | ||||||
| } State; |     ViewPort* view_port; | ||||||
|  |     Gui* gui; | ||||||
|  |     NotificationApp* notification; | ||||||
|  | } GpioTest; | ||||||
| 
 | 
 | ||||||
| static void render_callback(Canvas* canvas, void* ctx) { | static void gpio_test_render_callback(Canvas* canvas, void* ctx) { | ||||||
|     State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25); |     GpioTest* gpio_test = ctx; | ||||||
| 
 | 
 | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontPrimary); |     canvas_set_font(canvas, FontPrimary); | ||||||
|     canvas_draw_str(canvas, 2, 10, "GPIO Control"); |     canvas_draw_str(canvas, 2, 10, "GPIO Control"); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
|     canvas_draw_str(canvas, 2, 25, GPIO_PINS[state->gpio_index].name); |     canvas_draw_str(canvas, 2, 25, GPIO_PINS[gpio_test->gpio_index].name); | ||||||
| 
 |  | ||||||
|     release_mutex((ValueMutex*)ctx, state); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void input_callback(InputEvent* input_event, void* ctx) { | static void gpio_test_input_callback(InputEvent* input_event, void* ctx) { | ||||||
|     osMessageQueueId_t event_queue = ctx; |     GpioTest* gpio_test = ctx; | ||||||
| 
 | 
 | ||||||
|     AppEvent event; |     osMessageQueuePut(gpio_test->input_queue, input_event, 0, 0); | ||||||
|     event.type = EventTypeKey; | } | ||||||
|     event.value.input = *input_event; | 
 | ||||||
|     osMessageQueuePut(event_queue, &event, 0, 0); | static void gpio_test_configure_pins(GpioMode mode) { | ||||||
|  |     for(size_t i = 0; i < GPIO_PINS_COUNT; i++) { | ||||||
|  |         hal_gpio_write(GPIO_PINS[i].pin, false); | ||||||
|  |         hal_gpio_init(GPIO_PINS[i].pin, mode, GpioPullNo, GpioSpeedLow); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GpioTest* gpio_test_alloc() { | ||||||
|  |     GpioTest* instance = furi_alloc(sizeof(GpioTest)); | ||||||
|  | 
 | ||||||
|  |     gpio_test_configure_pins(GpioModeOutputPushPull); | ||||||
|  | 
 | ||||||
|  |     instance->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL); | ||||||
|  |     furi_check(instance->input_queue); | ||||||
|  | 
 | ||||||
|  |     instance->view_port = view_port_alloc(); | ||||||
|  |     view_port_draw_callback_set(instance->view_port, gpio_test_render_callback, instance); | ||||||
|  |     view_port_input_callback_set(instance->view_port, gpio_test_input_callback, instance); | ||||||
|  | 
 | ||||||
|  |     instance->gui = furi_record_open("gui"); | ||||||
|  |     gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen); | ||||||
|  | 
 | ||||||
|  |     instance->notification = furi_record_open("notification"); | ||||||
|  | 
 | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void gpio_test_free(GpioTest* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("notification"); | ||||||
|  | 
 | ||||||
|  |     view_port_enabled_set(instance->view_port, false); | ||||||
|  |     gui_remove_view_port(instance->gui, instance->view_port); | ||||||
|  |     furi_record_close("gui"); | ||||||
|  | 
 | ||||||
|  |     view_port_free(instance->view_port); | ||||||
|  | 
 | ||||||
|  |     osMessageQueueDelete(instance->input_queue); | ||||||
|  | 
 | ||||||
|  |     gpio_test_configure_pins(GpioModeAnalog); | ||||||
|  | 
 | ||||||
|  |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t gpio_test_app(void* p) { | int32_t gpio_test_app(void* p) { | ||||||
|     osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL); |     GpioTest* gpio_test = gpio_test_alloc(); | ||||||
|     furi_check(event_queue); |  | ||||||
| 
 | 
 | ||||||
|     State _state; |     InputEvent event; | ||||||
|     _state.gpio_index = 0; |     while(osMessageQueueGet(gpio_test->input_queue, &event, NULL, osWaitForever) == osOK) { | ||||||
|  |         if(event.type == InputTypeShort) { | ||||||
|  |             if(event.key == InputKeyBack) { | ||||||
|  |                 notification_message(gpio_test->notification, &sequence_reset_green); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|     ValueMutex state_mutex; |             if(event.key == InputKeyRight) { | ||||||
|     if(!init_mutex(&state_mutex, &_state, sizeof(State))) { |                 if(gpio_test->gpio_index < (GPIO_PINS_COUNT - 1)) { | ||||||
|         printf("[gpio-tester] cannot create mutex\r\n"); |                     gpio_test->gpio_index++; | ||||||
|         return 255; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ViewPort* view_port = view_port_alloc(); |  | ||||||
| 
 |  | ||||||
|     view_port_draw_callback_set(view_port, render_callback, &state_mutex); |  | ||||||
|     view_port_input_callback_set(view_port, input_callback, event_queue); |  | ||||||
| 
 |  | ||||||
|     // Open GUI and register view_port
 |  | ||||||
|     Gui* gui = furi_record_open("gui"); |  | ||||||
|     gui_add_view_port(gui, view_port, GuiLayerFullscreen); |  | ||||||
| 
 |  | ||||||
|     NotificationApp* notification = furi_record_open("notification"); |  | ||||||
| 
 |  | ||||||
|     // configure pin
 |  | ||||||
|     for(uint8_t i = 0; i < sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); i++) { |  | ||||||
|         hal_gpio_init( |  | ||||||
|             (GpioPin*)&GPIO_PINS[i].pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     AppEvent event; |  | ||||||
|     while(1) { |  | ||||||
|         osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever); |  | ||||||
|         State* state = (State*)acquire_mutex_block(&state_mutex); |  | ||||||
| 
 |  | ||||||
|         if(event_status == osOK) { |  | ||||||
|             if(event.type == EventTypeKey) { |  | ||||||
|                 if(event.value.input.type == InputTypeShort && |  | ||||||
|                    event.value.input.key == InputKeyBack) { |  | ||||||
|                     printf("[gpio-tester] bye!\r\n"); |  | ||||||
|                     notification_message(notification, &sequence_reset_green); |  | ||||||
|                     furi_record_close("notification"); |  | ||||||
| 
 |  | ||||||
|                     view_port_enabled_set(view_port, false); |  | ||||||
|                     gui_remove_view_port(gui, view_port); |  | ||||||
|                     view_port_free(view_port); |  | ||||||
| 
 |  | ||||||
|                     return 0; |  | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|                 if(event.value.input.type == InputTypeShort && |             if(event.key == InputKeyLeft) { | ||||||
|                    event.value.input.key == InputKeyRight) { |                 if(gpio_test->gpio_index > 0) { | ||||||
|                     if(state->gpio_index < (sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]) - 1)) { |                     gpio_test->gpio_index--; | ||||||
|                         state->gpio_index++; |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
| 
 |             } | ||||||
|                 if(event.value.input.type == InputTypeShort && |         } else { | ||||||
|                    event.value.input.key == InputKeyLeft) { |             if(event.key == InputKeyOk) { | ||||||
|                     if(state->gpio_index > 0) { |                 if(event.type == InputTypePress) { | ||||||
|                         state->gpio_index--; |                     hal_gpio_write(GPIO_PINS[gpio_test->gpio_index].pin, true); | ||||||
|                     } |                     notification_message(gpio_test->notification, &sequence_set_green_255); | ||||||
|                 } |                 } else if(event.type == InputTypeRelease) { | ||||||
| 
 |                     hal_gpio_write(GPIO_PINS[gpio_test->gpio_index].pin, false); | ||||||
|                 if(event.value.input.key == InputKeyOk) { |                     notification_message(gpio_test->notification, &sequence_reset_green); | ||||||
|                     if(event.value.input.type == InputTypePress) { |  | ||||||
|                         hal_gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, true); |  | ||||||
|                         notification_message(notification, &sequence_set_green_255); |  | ||||||
|                     } else if(event.value.input.type == InputTypeRelease) { |  | ||||||
|                         hal_gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, false); |  | ||||||
|                         notification_message(notification, &sequence_reset_green); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         release_mutex(&state_mutex, state); |         view_port_update(gpio_test->view_port); | ||||||
|         view_port_update(view_port); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     gpio_test_free(gpio_test); | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
| @ -309,12 +309,15 @@ void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) { | |||||||
|     furi_assert(canvas); |     furi_assert(canvas); | ||||||
|     if(canvas->orientation != orientation) { |     if(canvas->orientation != orientation) { | ||||||
|         canvas->orientation = orientation; |         canvas->orientation = orientation; | ||||||
|         if(canvas->orientation == CanvasOrientationHorizontal) |         if(canvas->orientation == CanvasOrientationHorizontal) { | ||||||
|  |             FURI_SWAP(canvas->width, canvas->height); | ||||||
|             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0); |             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0); | ||||||
|         else if(canvas->orientation == CanvasOrientationVertical) |         } else if(canvas->orientation == CanvasOrientationVertical) { | ||||||
|  |             FURI_SWAP(canvas->width, canvas->height); | ||||||
|             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3); |             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3); | ||||||
|         else |         } else { | ||||||
|             furi_assert(0); |             furi_assert(0); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,40 +1,5 @@ | |||||||
| #include "gui_i.h" | #include "gui_i.h" | ||||||
| 
 | 
 | ||||||
| static void gui_rotate_buttons(InputEvent* event) { |  | ||||||
|     switch(event->key) { |  | ||||||
|     case InputKeyUp: |  | ||||||
|         event->key = InputKeyRight; |  | ||||||
|         break; |  | ||||||
|     case InputKeyDown: |  | ||||||
|         event->key = InputKeyLeft; |  | ||||||
|         break; |  | ||||||
|     case InputKeyRight: |  | ||||||
|         event->key = InputKeyDown; |  | ||||||
|         break; |  | ||||||
|     case InputKeyLeft: |  | ||||||
|         event->key = InputKeyUp; |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void gui_setup_fs_orientation(const ViewPort* view_port, Canvas* canvas) { |  | ||||||
|     ViewPortOrientation view_port_orientation = view_port_get_orientation(view_port); |  | ||||||
|     CanvasOrientation canvas_orientation = canvas_get_orientation(canvas); |  | ||||||
|     if(view_port_orientation == ViewPortOrientationHorizontal) { |  | ||||||
|         canvas_frame_set(canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT); |  | ||||||
|         if(canvas_orientation != CanvasOrientationHorizontal) { |  | ||||||
|             canvas_set_orientation(canvas, CanvasOrientationHorizontal); |  | ||||||
|         } |  | ||||||
|     } else if(view_port_orientation == ViewPortOrientationVertical) { |  | ||||||
|         canvas_frame_set(canvas, 0, 0, GUI_DISPLAY_HEIGHT, GUI_DISPLAY_WIDTH); |  | ||||||
|         if(canvas_orientation != CanvasOrientationVertical) { |  | ||||||
|             canvas_set_orientation(canvas, CanvasOrientationVertical); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { | ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { | ||||||
|     // Iterating backward
 |     // Iterating backward
 | ||||||
|     ViewPortArray_it_t it; |     ViewPortArray_it_t it; | ||||||
| @ -66,9 +31,10 @@ void gui_input_events_callback(const void* value, void* ctx) { | |||||||
| 
 | 
 | ||||||
| // Only Fullscreen supports vertical display for now
 | // Only Fullscreen supports vertical display for now
 | ||||||
| bool gui_redraw_fs(Gui* gui) { | bool gui_redraw_fs(Gui* gui) { | ||||||
|  |     canvas_set_orientation(gui->canvas, CanvasOrientationHorizontal); | ||||||
|  |     canvas_frame_set(gui->canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT); | ||||||
|     ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]); |     ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]); | ||||||
|     if(view_port) { |     if(view_port) { | ||||||
|         gui_setup_fs_orientation(view_port, gui->canvas); |  | ||||||
|         view_port_draw(view_port, gui->canvas); |         view_port_draw(view_port, gui->canvas); | ||||||
|         return true; |         return true; | ||||||
|     } else { |     } else { | ||||||
| @ -216,20 +182,53 @@ void gui_input(Gui* gui, InputEvent* input_event) { | |||||||
|     furi_assert(gui); |     furi_assert(gui); | ||||||
|     furi_assert(input_event); |     furi_assert(input_event); | ||||||
| 
 | 
 | ||||||
|  |     // Check input complementarity
 | ||||||
|  |     uint8_t key_bit = (1 << input_event->key); | ||||||
|  |     if(input_event->type == InputTypeRelease) { | ||||||
|  |         gui->ongoing_input &= ~key_bit; | ||||||
|  |     } else if(input_event->type == InputTypePress) { | ||||||
|  |         gui->ongoing_input |= key_bit; | ||||||
|  |     } else if(!(gui->ongoing_input & key_bit)) { | ||||||
|  |         FURI_LOG_W( | ||||||
|  |             "Gui", | ||||||
|  |             "non-complementary input, discarding key: %s type: %s, sequence: %p", | ||||||
|  |             input_get_key_name(input_event->key), | ||||||
|  |             input_get_type_name(input_event->type), | ||||||
|  |             input_event->sequence); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     gui_lock(gui); |     gui_lock(gui); | ||||||
| 
 | 
 | ||||||
|     ViewPort* view_port; |     ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]); | ||||||
| 
 |  | ||||||
|     view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]); |  | ||||||
|     if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerMain]); |     if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerMain]); | ||||||
|     if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerNone]); |     if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerNone]); | ||||||
| 
 | 
 | ||||||
|     if(view_port) { |     if(!(gui->ongoing_input & ~key_bit) && input_event->type == InputTypePress) { | ||||||
|         if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) { |         gui->ongoing_input_view_port = view_port; | ||||||
|             gui_rotate_buttons(input_event); |     } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|  |     if(view_port && view_port == gui->ongoing_input_view_port) { | ||||||
|         view_port_input(view_port, input_event); |         view_port_input(view_port, input_event); | ||||||
|  |     } else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) { | ||||||
|  |         FURI_LOG_W( | ||||||
|  |             "Gui", | ||||||
|  |             "ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", | ||||||
|  |             gui->ongoing_input_view_port, | ||||||
|  |             view_port, | ||||||
|  |             input_get_key_name(input_event->key), | ||||||
|  |             input_get_type_name(input_event->type), | ||||||
|  |             input_event->sequence); | ||||||
|  |         view_port_input(gui->ongoing_input_view_port, input_event); | ||||||
|  |     } else { | ||||||
|  |         FURI_LOG_W( | ||||||
|  |             "Gui", | ||||||
|  |             "ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p", | ||||||
|  |             gui->ongoing_input_view_port, | ||||||
|  |             view_port, | ||||||
|  |             input_get_key_name(input_event->key), | ||||||
|  |             input_get_type_name(input_event->type), | ||||||
|  |             input_event->sequence); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
| @ -251,7 +250,7 @@ void gui_cli_screen_stream_callback(uint8_t* data, size_t size, void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| 
 | 
 | ||||||
|     Gui* gui = context; |     Gui* gui = context; | ||||||
|     uint8_t magic[] = {0xF0, 0xE1, 0xD2, 0xC3}; |     const uint8_t magic[] = {0xF0, 0xE1, 0xD2, 0xC3}; | ||||||
|     cli_write(gui->cli, magic, sizeof(magic)); |     cli_write(gui->cli, magic, sizeof(magic)); | ||||||
|     cli_write(gui->cli, data, size); |     cli_write(gui->cli, data, size); | ||||||
| } | } | ||||||
| @ -329,6 +328,10 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if(gui->ongoing_input_view_port == view_port) { | ||||||
|  |         gui->ongoing_input_view_port = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -35,14 +35,19 @@ struct Gui { | |||||||
|     // Thread and lock
 |     // Thread and lock
 | ||||||
|     osThreadId_t thread; |     osThreadId_t thread; | ||||||
|     osMutexId_t mutex; |     osMutexId_t mutex; | ||||||
|  | 
 | ||||||
|     // Layers and Canvas
 |     // Layers and Canvas
 | ||||||
|     ViewPortArray_t layers[GuiLayerMAX]; |     ViewPortArray_t layers[GuiLayerMAX]; | ||||||
|     Canvas* canvas; |     Canvas* canvas; | ||||||
|     GuiCanvasCommitCallback canvas_callback; |     GuiCanvasCommitCallback canvas_callback; | ||||||
|     void* canvas_callback_context; |     void* canvas_callback_context; | ||||||
|  | 
 | ||||||
|     // Input
 |     // Input
 | ||||||
|     osMessageQueueId_t input_queue; |     osMessageQueueId_t input_queue; | ||||||
|     PubSub* input_events; |     PubSub* input_events; | ||||||
|  |     uint8_t ongoing_input; | ||||||
|  |     ViewPort* ongoing_input_view_port; | ||||||
|  | 
 | ||||||
|     // Cli
 |     // Cli
 | ||||||
|     Cli* cli; |     Cli* cli; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -150,3 +150,15 @@ void widget_add_icon_element(Widget* widget, uint8_t x, uint8_t y, const Icon* i | |||||||
|     WidgetElement* icon_element = widget_element_icon_create(x, y, icon); |     WidgetElement* icon_element = widget_element_icon_create(x, y, icon); | ||||||
|     widget_add_element(widget, icon_element); |     widget_add_element(widget, icon_element); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void widget_add_frame_element( | ||||||
|  |     Widget* widget, | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     uint8_t width, | ||||||
|  |     uint8_t height, | ||||||
|  |     uint8_t radius) { | ||||||
|  |     furi_assert(widget); | ||||||
|  |     WidgetElement* frame_element = widget_element_frame_create(x, y, width, height, radius); | ||||||
|  |     widget_add_element(widget, frame_element); | ||||||
|  | } | ||||||
|  | |||||||
| @ -59,8 +59,24 @@ void widget_add_button_element( | |||||||
| 
 | 
 | ||||||
| /** Add Icon Element
 | /** Add Icon Element
 | ||||||
|  * @param widget Widget instance |  * @param widget Widget instance | ||||||
|  * @param x - x coordinate |  * @param x top left x coordinate | ||||||
|  * @param y - y coordinate |  * @param y top left y coordinate | ||||||
|  * @param icon Icon instance |  * @param icon Icon instance | ||||||
|  */ |  */ | ||||||
| void widget_add_icon_element(Widget* widget, uint8_t x, uint8_t y, const Icon* icon); | void widget_add_icon_element(Widget* widget, uint8_t x, uint8_t y, const Icon* icon); | ||||||
|  | 
 | ||||||
|  | /** Add Frame Element
 | ||||||
|  |  * @param widget Widget instance | ||||||
|  |  * @param x top left x coordinate | ||||||
|  |  * @param y top left y coordinate | ||||||
|  |  * @param width frame width | ||||||
|  |  * @param height frame height | ||||||
|  |  * @param radius frame radius | ||||||
|  |  */ | ||||||
|  | void widget_add_frame_element( | ||||||
|  |     Widget* widget, | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     uint8_t width, | ||||||
|  |     uint8_t height, | ||||||
|  |     uint8_t radius); | ||||||
|  | |||||||
							
								
								
									
										48
									
								
								applications/gui/modules/widget_elements/widget_element_frame.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,48 @@ | |||||||
|  | #include "widget_element_i.h" | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t x; | ||||||
|  |     uint8_t y; | ||||||
|  |     uint8_t width; | ||||||
|  |     uint8_t height; | ||||||
|  |     uint8_t radius; | ||||||
|  | } GuiFrameModel; | ||||||
|  | 
 | ||||||
|  | static void gui_frame_draw(Canvas* canvas, WidgetElement* element) { | ||||||
|  |     furi_assert(canvas); | ||||||
|  |     furi_assert(element); | ||||||
|  |     GuiFrameModel* model = element->model; | ||||||
|  |     canvas_draw_rframe(canvas, model->x, model->y, model->width, model->height, model->radius); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void gui_frame_free(WidgetElement* gui_frame) { | ||||||
|  |     furi_assert(gui_frame); | ||||||
|  | 
 | ||||||
|  |     free(gui_frame->model); | ||||||
|  |     free(gui_frame); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | WidgetElement* widget_element_frame_create( | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     uint8_t width, | ||||||
|  |     uint8_t height, | ||||||
|  |     uint8_t radius) { | ||||||
|  |     // Allocate and init model
 | ||||||
|  |     GuiFrameModel* model = furi_alloc(sizeof(GuiFrameModel)); | ||||||
|  |     model->x = x; | ||||||
|  |     model->y = y; | ||||||
|  |     model->width = width; | ||||||
|  |     model->height = height; | ||||||
|  |     model->radius = radius; | ||||||
|  | 
 | ||||||
|  |     // Allocate and init Element
 | ||||||
|  |     WidgetElement* gui_frame = furi_alloc(sizeof(WidgetElement)); | ||||||
|  |     gui_frame->parent = NULL; | ||||||
|  |     gui_frame->input = NULL; | ||||||
|  |     gui_frame->draw = gui_frame_draw; | ||||||
|  |     gui_frame->free = gui_frame_free; | ||||||
|  |     gui_frame->model = model; | ||||||
|  | 
 | ||||||
|  |     return gui_frame; | ||||||
|  | } | ||||||
| @ -44,5 +44,13 @@ WidgetElement* widget_element_button_create( | |||||||
|     ButtonCallback callback, |     ButtonCallback callback, | ||||||
|     void* context); |     void* context); | ||||||
| 
 | 
 | ||||||
| /* Create icon element element */ | /* Create icon element */ | ||||||
| WidgetElement* widget_element_icon_create(uint8_t x, uint8_t y, const Icon* icon); | WidgetElement* widget_element_icon_create(uint8_t x, uint8_t y, const Icon* icon); | ||||||
|  | 
 | ||||||
|  | /* Create frame element */ | ||||||
|  | WidgetElement* widget_element_frame_create( | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     uint8_t width, | ||||||
|  |     uint8_t height, | ||||||
|  |     uint8_t radius); | ||||||
| @ -1,5 +1,4 @@ | |||||||
| #include "widget_element_i.h" | #include "widget_element_i.h" | ||||||
| #include <m-string.h> |  | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint8_t x; |     uint8_t x; | ||||||
|  | |||||||
| @ -35,11 +35,6 @@ void view_set_previous_callback(View* view, ViewNavigationCallback callback) { | |||||||
|     view->previous_callback = callback; |     view->previous_callback = callback; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void view_set_next_callback(View* view, ViewNavigationCallback callback) { |  | ||||||
|     furi_assert(view); |  | ||||||
|     view->next_callback = callback; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void view_set_enter_callback(View* view, ViewCallback callback) { | void view_set_enter_callback(View* view, ViewCallback callback) { | ||||||
|     furi_assert(view); |     furi_assert(view); | ||||||
|     view->enter_callback = callback; |     view->enter_callback = callback; | ||||||
| @ -169,15 +164,6 @@ uint32_t view_previous(View* view) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint32_t view_next(View* view) { |  | ||||||
|     furi_assert(view); |  | ||||||
|     if(view->next_callback) { |  | ||||||
|         return view->next_callback(view->context); |  | ||||||
|     } else { |  | ||||||
|         return VIEW_IGNORE; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void view_enter(View* view) { | void view_enter(View* view) { | ||||||
|     furi_assert(view); |     furi_assert(view); | ||||||
|     if(view->enter_callback) view->enter_callback(view->context); |     if(view->enter_callback) view->enter_callback(view->context); | ||||||
|  | |||||||
| @ -14,11 +14,6 @@ extern "C" { | |||||||
| #define VIEW_NONE 0xFFFFFFFF | #define VIEW_NONE 0xFFFFFFFF | ||||||
| /* Ignore navigation event */ | /* Ignore navigation event */ | ||||||
| #define VIEW_IGNORE 0xFFFFFFFE | #define VIEW_IGNORE 0xFFFFFFFE | ||||||
| /* Deatch from gui, deallocate Views and ViewDispatcher
 |  | ||||||
|  * BE SUPER CAREFUL, deallocation happens automatically on GUI thread |  | ||||||
|  * You ARE NOT owning ViewDispatcher and Views instances |  | ||||||
|  */ |  | ||||||
| #define VIEW_DESTROY 0xFFFFFFFA |  | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     ViewOrientationHorizontal, |     ViewOrientationHorizontal, | ||||||
| @ -119,12 +114,6 @@ void view_set_custom_callback(View* view, ViewCustomCallback callback); | |||||||
|  */ |  */ | ||||||
| void view_set_previous_callback(View* view, ViewNavigationCallback callback); | void view_set_previous_callback(View* view, ViewNavigationCallback callback); | ||||||
| 
 | 
 | ||||||
| /* Set Navigation Next callback
 |  | ||||||
|  * @param view, pointer to View |  | ||||||
|  * @param callback, input callback |  | ||||||
|  */ |  | ||||||
| void view_set_next_callback(View* view, ViewNavigationCallback callback); |  | ||||||
| 
 |  | ||||||
| /* Set Enter callback
 | /* Set Enter callback
 | ||||||
|  * @param view, pointer to View |  * @param view, pointer to View | ||||||
|  * @param callback, callback |  * @param callback, callback | ||||||
|  | |||||||
							
								
								
									
										91
									
								
								applications/gui/view_dispatcher.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						| @ -37,7 +37,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) { | |||||||
| void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) { | void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) { | ||||||
|     furi_assert(view_dispatcher); |     furi_assert(view_dispatcher); | ||||||
|     furi_assert(view_dispatcher->queue == NULL); |     furi_assert(view_dispatcher->queue == NULL); | ||||||
|     view_dispatcher->queue = osMessageQueueNew(8, sizeof(ViewDispatcherMessage), NULL); |     view_dispatcher->queue = osMessageQueueNew(16, sizeof(ViewDispatcherMessage), NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) { | void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) { | ||||||
| @ -91,6 +91,19 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) { | |||||||
|             view_dispatcher_handle_custom_event(view_dispatcher, message.custom_event); |             view_dispatcher_handle_custom_event(view_dispatcher, message.custom_event); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     // Wait till all input events delivered
 | ||||||
|  |     while(view_dispatcher->ongoing_input) { | ||||||
|  |         osMessageQueueGet(view_dispatcher->queue, &message, NULL, osWaitForever); | ||||||
|  |         if(message.type == ViewDispatcherMessageTypeInput) { | ||||||
|  |             uint8_t key_bit = (1 << message.input.key); | ||||||
|  |             if(message.input.type == InputTypePress) { | ||||||
|  |                 view_dispatcher->ongoing_input |= key_bit; | ||||||
|  |             } else if(message.input.type == InputTypeRelease) { | ||||||
|  |                 view_dispatcher->ongoing_input &= ~key_bit; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void view_dispatcher_stop(ViewDispatcher* view_dispatcher) { | void view_dispatcher_stop(ViewDispatcher* view_dispatcher) { | ||||||
| @ -136,6 +149,10 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_ | |||||||
|     if(view_dispatcher->current_view == view) { |     if(view_dispatcher->current_view == view) { | ||||||
|         view_dispatcher_set_current_view(view_dispatcher, NULL); |         view_dispatcher_set_current_view(view_dispatcher, NULL); | ||||||
|     } |     } | ||||||
|  |     // Check if view is recieving input
 | ||||||
|  |     if(view_dispatcher->ongoing_input_view == view) { | ||||||
|  |         view_dispatcher->ongoing_input_view = NULL; | ||||||
|  |     } | ||||||
|     // Remove view
 |     // Remove view
 | ||||||
|     ViewDict_erase(view_dispatcher->views, view_id); |     ViewDict_erase(view_dispatcher->views, view_id); | ||||||
| 
 | 
 | ||||||
| @ -153,8 +170,6 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi | |||||||
|     if(view_id == VIEW_NONE) { |     if(view_id == VIEW_NONE) { | ||||||
|         view_dispatcher_set_current_view(view_dispatcher, NULL); |         view_dispatcher_set_current_view(view_dispatcher, NULL); | ||||||
|     } else if(view_id == VIEW_IGNORE) { |     } else if(view_id == VIEW_IGNORE) { | ||||||
|     } else if(view_id == VIEW_DESTROY) { |  | ||||||
|         view_dispatcher_free(view_dispatcher); |  | ||||||
|     } else { |     } else { | ||||||
|         View** view_pp = ViewDict_get(view_dispatcher->views, view_id); |         View** view_pp = ViewDict_get(view_dispatcher->views, view_id); | ||||||
|         furi_check(view_pp != NULL); |         furi_check(view_pp != NULL); | ||||||
| @ -202,29 +217,61 @@ void view_dispatcher_input_callback(InputEvent* event, void* context) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* event) { | void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* event) { | ||||||
|     bool is_consumed = false; |     // Check input complementarity
 | ||||||
|     if(view_dispatcher->current_view) { |     uint8_t key_bit = (1 << event->key); | ||||||
|         is_consumed = view_input(view_dispatcher->current_view, event); |     if(event->type == InputTypePress) { | ||||||
|  |         view_dispatcher->ongoing_input |= key_bit; | ||||||
|  |     } else if(event->type == InputTypeRelease) { | ||||||
|  |         view_dispatcher->ongoing_input &= ~key_bit; | ||||||
|  |     } else if(!(view_dispatcher->ongoing_input & key_bit)) { | ||||||
|  |         FURI_LOG_W( | ||||||
|  |             "ViewDispatcher", | ||||||
|  |             "non-complementary input, discarding key: %s, type: %s, sequence: %p", | ||||||
|  |             input_get_key_name(event->key), | ||||||
|  |             input_get_type_name(event->type), | ||||||
|  |             event->sequence); | ||||||
|  |         return; | ||||||
|     } |     } | ||||||
|     if(!is_consumed && event->type == InputTypeShort) { | 
 | ||||||
|         // TODO remove view navigation handlers
 |     // Set ongoing input view if this is event is first press event
 | ||||||
|         uint32_t view_id = VIEW_IGNORE; |     if(!(view_dispatcher->ongoing_input & ~key_bit) && event->type == InputTypePress) { | ||||||
|         if(event->key == InputKeyBack) { |         view_dispatcher->ongoing_input_view = view_dispatcher->current_view; | ||||||
|             view_id = view_previous(view_dispatcher->current_view); |     } | ||||||
|             if((view_id == VIEW_IGNORE) && (view_dispatcher->navigation_event_callback)) { | 
 | ||||||
|                 is_consumed = |     // Deliver event
 | ||||||
|                     view_dispatcher->navigation_event_callback(view_dispatcher->event_context); |     if(view_dispatcher->ongoing_input_view == view_dispatcher->current_view) { | ||||||
|                 if(!is_consumed) { |         bool is_consumed = false; | ||||||
|                     view_dispatcher_stop(view_dispatcher); |         if(view_dispatcher->current_view) { | ||||||
|                     return; |             is_consumed = view_input(view_dispatcher->current_view, event); | ||||||
|  |         } | ||||||
|  |         if(!is_consumed && event->type == InputTypeShort) { | ||||||
|  |             // TODO remove view navigation handlers
 | ||||||
|  |             uint32_t view_id = VIEW_IGNORE; | ||||||
|  |             if(event->key == InputKeyBack) { | ||||||
|  |                 view_id = view_previous(view_dispatcher->current_view); | ||||||
|  |                 if((view_id == VIEW_IGNORE) && (view_dispatcher->navigation_event_callback)) { | ||||||
|  |                     is_consumed = | ||||||
|  |                         view_dispatcher->navigation_event_callback(view_dispatcher->event_context); | ||||||
|  |                     if(!is_consumed) { | ||||||
|  |                         view_dispatcher_stop(view_dispatcher); | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } else if(event->key == InputKeyOk) { |             if(!is_consumed) { | ||||||
|             view_id = view_next(view_dispatcher->current_view); |                 view_dispatcher_switch_to_view(view_dispatcher, view_id); | ||||||
|         } |             } | ||||||
|         if(!is_consumed) { |  | ||||||
|             view_dispatcher_switch_to_view(view_dispatcher, view_id); |  | ||||||
|         } |         } | ||||||
|  |     } else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) { | ||||||
|  |         FURI_LOG_W( | ||||||
|  |             "ViewDispatcher", | ||||||
|  |             "View changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", | ||||||
|  |             view_dispatcher->ongoing_input_view, | ||||||
|  |             view_dispatcher->current_view, | ||||||
|  |             input_get_key_name(event->key), | ||||||
|  |             input_get_type_name(event->type), | ||||||
|  |             event->sequence); | ||||||
|  |         view_input(view_dispatcher->ongoing_input_view, event); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -113,6 +113,7 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_ | |||||||
| /** Switch to View
 | /** Switch to View
 | ||||||
|  * @param view_dispatcher ViewDispatcher instance |  * @param view_dispatcher ViewDispatcher instance | ||||||
|  * @param view_id View id to register |  * @param view_id View id to register | ||||||
|  |  * @warning switching may be delayed till input events complementarity reached | ||||||
|  */ |  */ | ||||||
| void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t view_id); | void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t view_id); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,7 +14,12 @@ struct ViewDispatcher { | |||||||
|     Gui* gui; |     Gui* gui; | ||||||
|     ViewPort* view_port; |     ViewPort* view_port; | ||||||
|     ViewDict_t views; |     ViewDict_t views; | ||||||
|  | 
 | ||||||
|     View* current_view; |     View* current_view; | ||||||
|  | 
 | ||||||
|  |     View* ongoing_input_view; | ||||||
|  |     uint8_t ongoing_input; | ||||||
|  | 
 | ||||||
|     ViewDispatcherCustomEventCallback custom_event_callback; |     ViewDispatcherCustomEventCallback custom_event_callback; | ||||||
|     ViewDispatcherNavigationEventCallback navigation_event_callback; |     ViewDispatcherNavigationEventCallback navigation_event_callback; | ||||||
|     ViewDispatcherTickEventCallback tick_event_callback; |     ViewDispatcherTickEventCallback tick_event_callback; | ||||||
|  | |||||||
| @ -15,7 +15,6 @@ struct View { | |||||||
| 
 | 
 | ||||||
|     ViewModelType model_type; |     ViewModelType model_type; | ||||||
|     ViewNavigationCallback previous_callback; |     ViewNavigationCallback previous_callback; | ||||||
|     ViewNavigationCallback next_callback; |  | ||||||
|     ViewCallback enter_callback; |     ViewCallback enter_callback; | ||||||
|     ViewCallback exit_callback; |     ViewCallback exit_callback; | ||||||
|     ViewOrientation orientation; |     ViewOrientation orientation; | ||||||
| @ -42,9 +41,6 @@ bool view_custom(View* view, uint32_t event); | |||||||
| /* Previous Callback for View dispatcher */ | /* Previous Callback for View dispatcher */ | ||||||
| uint32_t view_previous(View* view); | uint32_t view_previous(View* view); | ||||||
| 
 | 
 | ||||||
| /* Next Callback for View dispatcher */ |  | ||||||
| uint32_t view_next(View* view); |  | ||||||
| 
 |  | ||||||
| /* Enter Callback for View dispatcher */ | /* Enter Callback for View dispatcher */ | ||||||
| void view_enter(View* view); | void view_enter(View* view); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,6 +7,33 @@ | |||||||
| 
 | 
 | ||||||
| // TODO add mutex to view_port ops
 | // TODO add mutex to view_port ops
 | ||||||
| 
 | 
 | ||||||
|  | static void view_port_rotate_buttons(InputEvent* event) { | ||||||
|  |     switch(event->key) { | ||||||
|  |     case InputKeyUp: | ||||||
|  |         event->key = InputKeyRight; | ||||||
|  |         break; | ||||||
|  |     case InputKeyDown: | ||||||
|  |         event->key = InputKeyLeft; | ||||||
|  |         break; | ||||||
|  |     case InputKeyRight: | ||||||
|  |         event->key = InputKeyDown; | ||||||
|  |         break; | ||||||
|  |     case InputKeyLeft: | ||||||
|  |         event->key = InputKeyUp; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) { | ||||||
|  |     if(view_port->orientation == ViewPortOrientationHorizontal) { | ||||||
|  |         canvas_set_orientation(canvas, CanvasOrientationHorizontal); | ||||||
|  |     } else if(view_port->orientation == ViewPortOrientationVertical) { | ||||||
|  |         canvas_set_orientation(canvas, CanvasOrientationVertical); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ViewPort* view_port_alloc() { | ViewPort* view_port_alloc() { | ||||||
|     ViewPort* view_port = furi_alloc(sizeof(ViewPort)); |     ViewPort* view_port = furi_alloc(sizeof(ViewPort)); | ||||||
|     view_port->orientation = ViewPortOrientationHorizontal; |     view_port->orientation = ViewPortOrientationHorizontal; | ||||||
| @ -84,6 +111,7 @@ void view_port_draw(ViewPort* view_port, Canvas* canvas) { | |||||||
|     furi_check(view_port->gui); |     furi_check(view_port->gui); | ||||||
| 
 | 
 | ||||||
|     if(view_port->draw_callback) { |     if(view_port->draw_callback) { | ||||||
|  |         view_port_setup_canvas_orientation(view_port, canvas); | ||||||
|         view_port->draw_callback(canvas, view_port->draw_callback_context); |         view_port->draw_callback(canvas, view_port->draw_callback_context); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -94,6 +122,9 @@ void view_port_input(ViewPort* view_port, InputEvent* event) { | |||||||
|     furi_check(view_port->gui); |     furi_check(view_port->gui); | ||||||
| 
 | 
 | ||||||
|     if(view_port->input_callback) { |     if(view_port->input_callback) { | ||||||
|  |         if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) { | ||||||
|  |             view_port_rotate_buttons(event); | ||||||
|  |         } | ||||||
|         view_port->input_callback(event, view_port->input_callback_context); |         view_port->input_callback(event, view_port->input_callback_context); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,18 +10,20 @@ | |||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| void ibutton_cli(Cli* cli, string_t args, void* context); | void ibutton_cli(Cli* cli, string_t args, void* context); | ||||||
|  | void onewire_cli(Cli* cli, string_t args, void* context); | ||||||
| 
 | 
 | ||||||
| // app cli function
 | // app cli function
 | ||||||
| extern "C" void ibutton_cli_init() { | extern "C" void ibutton_cli_init() { | ||||||
|     Cli* cli = static_cast<Cli*>(furi_record_open("cli")); |     Cli* cli = static_cast<Cli*>(furi_record_open("cli")); | ||||||
|     cli_add_command(cli, "tm", CliCommandFlagDefault, ibutton_cli, cli); |     cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli, cli); | ||||||
|  |     cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli); | ||||||
|     furi_record_close("cli"); |     furi_record_close("cli"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ibutton_cli_print_usage() { | void ibutton_cli_print_usage() { | ||||||
|     printf("Usage:\r\n"); |     printf("Usage:\r\n"); | ||||||
|     printf("tm read\r\n"); |     printf("ikey read\r\n"); | ||||||
|     printf("tm <write | emulate> <key_type> <key_data>\r\n"); |     printf("ikey <write | emulate> <key_type> <key_data>\r\n"); | ||||||
|     printf("\t<key_type> choose from:\r\n"); |     printf("\t<key_type> choose from:\r\n"); | ||||||
|     printf("\tDallas (8 bytes key_data)\r\n"); |     printf("\tDallas (8 bytes key_data)\r\n"); | ||||||
|     printf("\tCyfral (2 bytes key_data)\r\n"); |     printf("\tCyfral (2 bytes key_data)\r\n"); | ||||||
| @ -232,3 +234,51 @@ void ibutton_cli(Cli* cli, string_t args, void* context) { | |||||||
| 
 | 
 | ||||||
|     string_clear(cmd); |     string_clear(cmd); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void onewire_cli_print_usage() { | ||||||
|  |     printf("Usage:\r\n"); | ||||||
|  |     printf("onewire search\r\n"); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void onewire_cli_search(Cli* cli) { | ||||||
|  |     OneWireMaster onewire(&ibutton_gpio); | ||||||
|  |     uint8_t address[8]; | ||||||
|  |     bool done = false; | ||||||
|  | 
 | ||||||
|  |     printf("Search started\r\n"); | ||||||
|  | 
 | ||||||
|  |     onewire.start(); | ||||||
|  |     while(!done) { | ||||||
|  |         if(onewire.search(address, true) != 1) { | ||||||
|  |             printf("Search finished\r\n"); | ||||||
|  |             onewire.reset_search(); | ||||||
|  |             done = true; | ||||||
|  |             return; | ||||||
|  |         } else { | ||||||
|  |             printf("Found: "); | ||||||
|  |             for(uint8_t i = 0; i < 8; i++) { | ||||||
|  |                 printf("%02X", address[i]); | ||||||
|  |             } | ||||||
|  |             printf("\r\n"); | ||||||
|  |         } | ||||||
|  |         delay(100); | ||||||
|  |     } | ||||||
|  |     onewire.stop(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void onewire_cli(Cli* cli, string_t args, void* context) { | ||||||
|  |     string_t cmd; | ||||||
|  |     string_init(cmd); | ||||||
|  | 
 | ||||||
|  |     if(!args_read_string_and_trim(args, cmd)) { | ||||||
|  |         string_clear(cmd); | ||||||
|  |         onewire_cli_print_usage(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(string_cmp_str(cmd, "search") == 0) { | ||||||
|  |         onewire_cli_search(cli); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(cmd); | ||||||
|  | } | ||||||
| @ -23,6 +23,7 @@ inline static void input_timer_stop(osTimerId_t timer_id) { | |||||||
| void input_press_timer_callback(void* arg) { | void input_press_timer_callback(void* arg) { | ||||||
|     InputPinState* input_pin = arg; |     InputPinState* input_pin = arg; | ||||||
|     InputEvent event; |     InputEvent event; | ||||||
|  |     event.sequence = input_pin->counter; | ||||||
|     event.key = input_pin->pin->key; |     event.key = input_pin->pin->key; | ||||||
|     input_pin->press_counter++; |     input_pin->press_counter++; | ||||||
|     if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { |     if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) { | ||||||
| @ -91,6 +92,31 @@ void input_cli_send(Cli* cli, string_t args, void* context) { | |||||||
|     notify_pubsub(&input->event_pubsub, &event); |     notify_pubsub(&input->event_pubsub, &event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const char* input_get_key_name(InputKey key) { | ||||||
|  |     for(size_t i = 0; i < input_pins_count; i++) { | ||||||
|  |         if(input_pins[i].key == key) { | ||||||
|  |             return input_pins[i].name; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return "Unknown"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* input_get_type_name(InputType type) { | ||||||
|  |     switch(type) { | ||||||
|  |     case InputTypePress: | ||||||
|  |         return "Press"; | ||||||
|  |     case InputTypeRelease: | ||||||
|  |         return "Release"; | ||||||
|  |     case InputTypeShort: | ||||||
|  |         return "Short"; | ||||||
|  |     case InputTypeLong: | ||||||
|  |         return "Long"; | ||||||
|  |     case InputTypeRepeat: | ||||||
|  |         return "Repeat"; | ||||||
|  |     } | ||||||
|  |     return "Unknown"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int32_t input_srv() { | int32_t input_srv() { | ||||||
|     input = furi_alloc(sizeof(Input)); |     input = furi_alloc(sizeof(Input)); | ||||||
|     input->thread = osThreadGetId(); |     input->thread = osThreadGetId(); | ||||||
| @ -103,10 +129,9 @@ int32_t input_srv() { | |||||||
|             input->cli, "input_send", CliCommandFlagParallelSafe, input_cli_send, input); |             input->cli, "input_send", CliCommandFlagParallelSafe, input_cli_send, input); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const size_t pin_count = input_pins_count; |     input->pin_states = furi_alloc(input_pins_count * sizeof(InputPinState)); | ||||||
|     input->pin_states = furi_alloc(pin_count * sizeof(InputPinState)); |  | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < pin_count; i++) { |     for(size_t i = 0; i < input_pins_count; i++) { | ||||||
|         GpioPin gpio = {(GPIO_TypeDef*)input_pins[i].port, (uint16_t)input_pins[i].pin}; |         GpioPin gpio = {(GPIO_TypeDef*)input_pins[i].port, (uint16_t)input_pins[i].pin}; | ||||||
|         hal_gpio_add_int_callback(&gpio, input_isr, NULL); |         hal_gpio_add_int_callback(&gpio, input_isr, NULL); | ||||||
|         input->pin_states[i].pin = &input_pins[i]; |         input->pin_states[i].pin = &input_pins[i]; | ||||||
| @ -119,7 +144,7 @@ int32_t input_srv() { | |||||||
| 
 | 
 | ||||||
|     while(1) { |     while(1) { | ||||||
|         bool is_changing = false; |         bool is_changing = false; | ||||||
|         for(size_t i = 0; i < pin_count; i++) { |         for(size_t i = 0; i < input_pins_count; i++) { | ||||||
|             bool state = GPIO_Read(input->pin_states[i]); |             bool state = GPIO_Read(input->pin_states[i]); | ||||||
|             if(input->pin_states[i].debounce > 0 && |             if(input->pin_states[i].debounce > 0 && | ||||||
|                input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) { |                input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) { | ||||||
| @ -131,14 +156,15 @@ int32_t input_srv() { | |||||||
|                 // Common state info
 |                 // Common state info
 | ||||||
|                 InputEvent event; |                 InputEvent event; | ||||||
|                 event.key = input->pin_states[i].pin->key; |                 event.key = input->pin_states[i].pin->key; | ||||||
|                 event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease; |  | ||||||
|                 // Send Press/Release event
 |  | ||||||
|                 notify_pubsub(&input->event_pubsub, &event); |  | ||||||
| 
 | 
 | ||||||
|                 // Short / Long / Repeat timer routine
 |                 // Short / Long / Repeat timer routine
 | ||||||
|                 if(state) { |                 if(state) { | ||||||
|  |                     input->counter++; | ||||||
|  |                     input->pin_states[i].counter = input->counter; | ||||||
|  |                     event.sequence = input->pin_states[i].counter; | ||||||
|                     input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); |                     input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); | ||||||
|                 } else { |                 } else { | ||||||
|  |                     event.sequence = input->pin_states[i].counter; | ||||||
|                     input_timer_stop(input->pin_states[i].press_timer); |                     input_timer_stop(input->pin_states[i].press_timer); | ||||||
|                     if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { |                     if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { | ||||||
|                         event.type = InputTypeShort; |                         event.type = InputTypeShort; | ||||||
| @ -146,6 +172,10 @@ int32_t input_srv() { | |||||||
|                     } |                     } | ||||||
|                     input->pin_states[i].press_counter = 0; |                     input->pin_states[i].press_counter = 0; | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 // Send Press/Release event
 | ||||||
|  |                 event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease; | ||||||
|  |                 notify_pubsub(&input->event_pubsub, &event); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,6 +15,19 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
| /* Input Event, dispatches with PubSub */ | /* Input Event, dispatches with PubSub */ | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     uint32_t sequence; | ||||||
|     InputKey key; |     InputKey key; | ||||||
|     InputType type; |     InputType type; | ||||||
| } InputEvent; | } InputEvent; | ||||||
|  | 
 | ||||||
|  | /** Get human readable input key name
 | ||||||
|  |  * @param key - InputKey | ||||||
|  |  * @return string | ||||||
|  |  */ | ||||||
|  | const char* input_get_key_name(InputKey key); | ||||||
|  | 
 | ||||||
|  | /** Get human readable input type name
 | ||||||
|  |  * @param type - InputType | ||||||
|  |  * @return string | ||||||
|  |  */ | ||||||
|  | const char* input_get_type_name(InputType type); | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ typedef struct { | |||||||
|     volatile uint8_t debounce; |     volatile uint8_t debounce; | ||||||
|     volatile osTimerId_t press_timer; |     volatile osTimerId_t press_timer; | ||||||
|     volatile uint8_t press_counter; |     volatile uint8_t press_counter; | ||||||
|  |     volatile uint32_t counter; | ||||||
| } InputPinState; | } InputPinState; | ||||||
| 
 | 
 | ||||||
| /* Input state */ | /* Input state */ | ||||||
| @ -32,6 +33,7 @@ typedef struct { | |||||||
|     PubSub event_pubsub; |     PubSub event_pubsub; | ||||||
|     InputPinState* pin_states; |     InputPinState* pin_states; | ||||||
|     Cli* cli; |     Cli* cli; | ||||||
|  |     volatile uint32_t counter; | ||||||
| } Input; | } Input; | ||||||
| 
 | 
 | ||||||
| /* Input press timer callback */ | /* Input press timer callback */ | ||||||
|  | |||||||
| @ -383,11 +383,6 @@ int32_t music_player_app(void* p) { | |||||||
|     Gui* gui = furi_record_open("gui"); |     Gui* gui = furi_record_open("gui"); | ||||||
|     gui_add_view_port(gui, view_port, GuiLayerFullscreen); |     gui_add_view_port(gui, view_port, GuiLayerFullscreen); | ||||||
| 
 | 
 | ||||||
|     // open input record
 |  | ||||||
|     PubSub* input_events_record = furi_record_open("input_events"); |  | ||||||
|     // prepare "do nothing" event
 |  | ||||||
|     InputEvent input_event = {InputKeyRight, true}; |  | ||||||
| 
 |  | ||||||
|     // start player thread
 |     // start player thread
 | ||||||
|     // TODO change to fuirac_start
 |     // TODO change to fuirac_start
 | ||||||
|     osThreadAttr_t player_attr = {.name = "music_player_thread", .stack_size = 512}; |     osThreadAttr_t player_attr = {.name = "music_player_thread", .stack_size = 512}; | ||||||
| @ -410,14 +405,8 @@ int32_t music_player_app(void* p) { | |||||||
|                 // press events
 |                 // press events
 | ||||||
|                 if(event.value.input.type == InputTypeShort && |                 if(event.value.input.type == InputTypeShort && | ||||||
|                    event.value.input.key == InputKeyBack) { |                    event.value.input.key == InputKeyBack) { | ||||||
|                     osThreadTerminate(player); |                     release_mutex(&state_mutex, state); | ||||||
|                     hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH); |                     break; | ||||||
|                     view_port_enabled_set(view_port, false); |  | ||||||
|                     gui_remove_view_port(gui, view_port); |  | ||||||
|                     view_port_free(view_port); |  | ||||||
|                     osMessageQueueDelete(event_queue); |  | ||||||
| 
 |  | ||||||
|                     return 0; |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if(event.value.input.type == InputTypePress && |                 if(event.value.input.type == InputTypePress && | ||||||
| @ -442,9 +431,6 @@ int32_t music_player_app(void* p) { | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             } else if(event.type == EventTypeNote) { |             } else if(event.type == EventTypeNote) { | ||||||
|                 // send "do nothing" event to prevent display backlight off
 |  | ||||||
|                 notify_pubsub(input_events_record, &input_event); |  | ||||||
| 
 |  | ||||||
|                 state->note_record = event.value.note_record; |                 state->note_record = event.value.note_record; | ||||||
| 
 | 
 | ||||||
|                 for(size_t i = note_stack_size - 1; i > 0; i--) { |                 for(size_t i = note_stack_size - 1; i > 0; i--) { | ||||||
| @ -460,5 +446,14 @@ int32_t music_player_app(void* p) { | |||||||
|         release_mutex(&state_mutex, state); |         release_mutex(&state_mutex, state); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     osThreadTerminate(player); | ||||||
|  |     hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH); | ||||||
|  |     view_port_enabled_set(view_port, false); | ||||||
|  |     gui_remove_view_port(gui, view_port); | ||||||
|  |     furi_record_close("gui"); | ||||||
|  |     view_port_free(view_port); | ||||||
|  |     osMessageQueueDelete(event_queue); | ||||||
|  |     delete_mutex(&state_mutex); | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										49
									
								
								applications/nfc/helpers/nfc_emv_parser.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,49 @@ | |||||||
|  | #include "nfc_emv_parser.h" | ||||||
|  | 
 | ||||||
|  | #include <file-worker.h> | ||||||
|  | 
 | ||||||
|  | static bool | ||||||
|  |     nfc_emv_parser_get_value(const char* file_path, string_t key, char delimiter, string_t value) { | ||||||
|  |     bool found = false; | ||||||
|  |     FileWorker* file_worker = file_worker_alloc(true); | ||||||
|  | 
 | ||||||
|  |     if(file_worker_open(file_worker, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||||
|  |         if(file_worker_get_value_from_key(file_worker, key, delimiter, value)) { | ||||||
|  |             found = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     file_worker_close(file_worker); | ||||||
|  |     file_worker_free(file_worker); | ||||||
|  |     return found; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name) { | ||||||
|  |     bool result = false; | ||||||
|  |     string_t key; | ||||||
|  |     string_init(key); | ||||||
|  |     for(uint8_t i = 0; i < aid_len; i++) { | ||||||
|  |         string_cat_printf(key, "%02X", aid[i]); | ||||||
|  |     } | ||||||
|  |     result = nfc_emv_parser_get_value("/ext/nfc/emv/aid.nfc", key, ' ', aid_name); | ||||||
|  |     string_clear(key); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name) { | ||||||
|  |     bool result = false; | ||||||
|  |     string_t key; | ||||||
|  |     string_init_printf(key, "%04X", country_code); | ||||||
|  |     result = nfc_emv_parser_get_value("/ext/nfc/emv/country_code.nfc", key, ' ', country_name); | ||||||
|  |     string_clear(key); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name) { | ||||||
|  |     bool result = false; | ||||||
|  |     string_t key; | ||||||
|  |     string_init_printf(key, "%04X", currency_code); | ||||||
|  |     result = nfc_emv_parser_get_value("/ext/nfc/emv/currency_code.nfc", key, ' ', currency_name); | ||||||
|  |     string_clear(key); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								applications/nfc/helpers/nfc_emv_parser.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,27 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <m-string.h> | ||||||
|  | 
 | ||||||
|  | /** Get EMV application name by number
 | ||||||
|  |  * @param aid - AID number array | ||||||
|  |  * @param aid_len - AID length | ||||||
|  |  * @param aid_name - string to keep AID name | ||||||
|  |  * @return - true if AID found, false otherwies | ||||||
|  |  */ | ||||||
|  | bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name); | ||||||
|  | 
 | ||||||
|  | /** Get country name by country code
 | ||||||
|  |  * @param country_code - ISO 3166 country code | ||||||
|  |  * @param country_name - string to keep country name | ||||||
|  |  * @return - true if country found, false otherwies | ||||||
|  |  */ | ||||||
|  | bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name); | ||||||
|  | 
 | ||||||
|  | /** Get currency name by currency code
 | ||||||
|  |  * @param currency_code - ISO 3166 currency code | ||||||
|  |  * @param currency_name - string to keep currency name | ||||||
|  |  * @return - true if currency found, false otherwies | ||||||
|  |  */ | ||||||
|  | bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name); | ||||||
| @ -54,7 +54,7 @@ void nfc_cli_emulate(Cli* cli, string_t args, void* context) { | |||||||
|     printf("Emulating NFC-A Type: T2T UID: CF72D440 SAK: 20 ATQA: 00/04\r\n"); |     printf("Emulating NFC-A Type: T2T UID: CF72D440 SAK: 20 ATQA: 00/04\r\n"); | ||||||
|     printf("Press Ctrl+C to abort\r\n"); |     printf("Press Ctrl+C to abort\r\n"); | ||||||
| 
 | 
 | ||||||
|     NfcDeviceCommomData params = { |     NfcDeviceCommonData params = { | ||||||
|         .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, |         .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, | ||||||
|         .uid_len = 7, |         .uid_len = 7, | ||||||
|         .atqa = {0x44, 0x00}, |         .atqa = {0x44, 0x00}, | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ static const char* nfc_app_folder = "/any/nfc"; | |||||||
| static const char* nfc_app_extension = ".nfc"; | static const char* nfc_app_extension = ".nfc"; | ||||||
| static const char* nfc_app_shadow_extension = ".shd"; | static const char* nfc_app_shadow_extension = ".shd"; | ||||||
| 
 | 
 | ||||||
| static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len) { | static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len, uint8_t delim_len) { | ||||||
|     string_strim(str); |     string_strim(str); | ||||||
|     uint8_t nibble_high = 0; |     uint8_t nibble_high = 0; | ||||||
|     uint8_t nibble_low = 0; |     uint8_t nibble_low = 0; | ||||||
| @ -20,7 +20,7 @@ static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len) { | |||||||
|         if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) && |         if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) && | ||||||
|            hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) { |            hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) { | ||||||
|             buff[i] = (nibble_high << 4) | nibble_low; |             buff[i] = (nibble_high << 4) | nibble_low; | ||||||
|             string_right(str, 3); |             string_right(str, delim_len + 2); | ||||||
|         } else { |         } else { | ||||||
|             parsed = false; |             parsed = false; | ||||||
|             break; |             break; | ||||||
| @ -60,7 +60,7 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string) { | uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string) { | ||||||
|     NfcDeviceCommomData* uid_data = &dev->dev_data.nfc_data; |     NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data; | ||||||
|     string_printf(uid_string, "UID len: %02X UID: ", dev->dev_data.nfc_data.uid_len); |     string_printf(uid_string, "UID len: %02X UID: ", dev->dev_data.nfc_data.uid_len); | ||||||
|     for(uint8_t i = 0; i < uid_data->uid_len; i++) { |     for(uint8_t i = 0; i < uid_data->uid_len; i++) { | ||||||
|         string_cat_printf(uid_string, "%02X ", uid_data->uid[i]); |         string_cat_printf(uid_string, "%02X ", uid_data->uid[i]); | ||||||
| @ -75,28 +75,28 @@ uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string) { | bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string) { | ||||||
|     NfcDeviceCommomData* uid_data = &dev->dev_data.nfc_data; |     NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data; | ||||||
|     bool parsed = false; |     bool parsed = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         // strlen("UID len: ") = 9
 |         // strlen("UID len: ") = 9
 | ||||||
|         string_right(uid_string, 9); |         string_right(uid_string, 9); | ||||||
|         if(!nfc_device_read_hex(uid_string, &uid_data->uid_len, 1)) { |         if(!nfc_device_read_hex(uid_string, &uid_data->uid_len, 1, 1)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // strlen("UID: ") = 5
 |         // strlen("UID: ") = 5
 | ||||||
|         string_right(uid_string, 5); |         string_right(uid_string, 5); | ||||||
|         if(!nfc_device_read_hex(uid_string, uid_data->uid, uid_data->uid_len)) { |         if(!nfc_device_read_hex(uid_string, uid_data->uid, uid_data->uid_len, 1)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // strlen("ATQA: ") = 6
 |         // strlen("ATQA: ") = 6
 | ||||||
|         string_right(uid_string, 6); |         string_right(uid_string, 6); | ||||||
|         if(!nfc_device_read_hex(uid_string, uid_data->atqa, 2)) { |         if(!nfc_device_read_hex(uid_string, uid_data->atqa, 2, 1)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // strlen("SAK: ") = 5
 |         // strlen("SAK: ") = 5
 | ||||||
|         string_right(uid_string, 5); |         string_right(uid_string, 5); | ||||||
|         if(!nfc_device_read_hex(uid_string, &uid_data->sak, 1)) { |         if(!nfc_device_read_hex(uid_string, &uid_data->sak, 1, 1)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         parsed = true; |         parsed = true; | ||||||
| @ -149,13 +149,13 @@ bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string | |||||||
|     do { |     do { | ||||||
|         // strlen("Signature: ") = 11
 |         // strlen("Signature: ") = 11
 | ||||||
|         string_right(mifare_ul_string, 11); |         string_right(mifare_ul_string, 11); | ||||||
|         if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature))) { |         if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature), 1)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // strlen("Version: ") = 9
 |         // strlen("Version: ") = 9
 | ||||||
|         string_right(mifare_ul_string, 9); |         string_right(mifare_ul_string, 9); | ||||||
|         if(!nfc_device_read_hex( |         if(!nfc_device_read_hex( | ||||||
|                mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version))) { |                mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version), 1)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         string_strim(mifare_ul_string); |         string_strim(mifare_ul_string); | ||||||
| @ -184,7 +184,7 @@ bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string | |||||||
|         string_right(mifare_ul_string, ws + 1); |         string_right(mifare_ul_string, ws + 1); | ||||||
|         // Read data
 |         // Read data
 | ||||||
|         for(uint16_t i = 0; i < data->data_size; i += 4) { |         for(uint16_t i = 0; i < data->data_size; i += 4) { | ||||||
|             if(!nfc_device_read_hex(mifare_ul_string, &data->data[i], 4)) { |             if(!nfc_device_read_hex(mifare_ul_string, &data->data[i], 4, 1)) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -208,6 +208,12 @@ uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_ | |||||||
|         string_cat_printf( |         string_cat_printf( | ||||||
|             bank_card_string, "\nExp date: %02X/%02X", data->exp_mon, data->exp_year); |             bank_card_string, "\nExp date: %02X/%02X", data->exp_mon, data->exp_year); | ||||||
|     } |     } | ||||||
|  |     if(data->country_code) { | ||||||
|  |         string_cat_printf(bank_card_string, "\nCountry code: %04X", data->country_code); | ||||||
|  |     } | ||||||
|  |     if(data->currency_code) { | ||||||
|  |         string_cat_printf(bank_card_string, "\nCurrency code: %04X", data->currency_code); | ||||||
|  |     } | ||||||
|     return string_size(bank_card_string); |     return string_size(bank_card_string); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -215,6 +221,7 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string | |||||||
|     NfcEmvData* data = &dev->dev_data.emv_data; |     NfcEmvData* data = &dev->dev_data.emv_data; | ||||||
|     bool parsed = false; |     bool parsed = false; | ||||||
|     int res = 0; |     int res = 0; | ||||||
|  |     uint8_t code[2] = {}; | ||||||
|     memset(data, 0, sizeof(NfcEmvData)); |     memset(data, 0, sizeof(NfcEmvData)); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
| @ -226,7 +233,7 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string | |||||||
|         string_right(bank_card_string, 9); |         string_right(bank_card_string, 9); | ||||||
|         size_t ws = string_search_char(bank_card_string, ':'); |         size_t ws = string_search_char(bank_card_string, ':'); | ||||||
|         string_right(bank_card_string, ws + 1); |         string_right(bank_card_string, ws + 1); | ||||||
|         if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len)) { |         if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len, 1)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         res = sscanf(string_get_cstr(bank_card_string), "Name: %s\n", data->name); |         res = sscanf(string_get_cstr(bank_card_string), "Name: %s\n", data->name); | ||||||
| @ -237,7 +244,7 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string | |||||||
|         string_right(bank_card_string, ws + 1); |         string_right(bank_card_string, ws + 1); | ||||||
|         // strlen("Number: ") = 8
 |         // strlen("Number: ") = 8
 | ||||||
|         string_right(bank_card_string, 8); |         string_right(bank_card_string, 8); | ||||||
|         if(!nfc_device_read_hex(bank_card_string, data->number, sizeof(data->number))) { |         if(!nfc_device_read_hex(bank_card_string, data->number, sizeof(data->number), 1)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         parsed = true; |         parsed = true; | ||||||
| @ -246,8 +253,24 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string | |||||||
|         if(ws != STRING_FAILURE) { |         if(ws != STRING_FAILURE) { | ||||||
|             // strlen("Exp date: ") = 10
 |             // strlen("Exp date: ") = 10
 | ||||||
|             string_right(bank_card_string, 10); |             string_right(bank_card_string, 10); | ||||||
|             nfc_device_read_hex(bank_card_string, &data->exp_mon, 1); |             nfc_device_read_hex(bank_card_string, &data->exp_mon, 1, 1); | ||||||
|             nfc_device_read_hex(bank_card_string, &data->exp_year, 1); |             nfc_device_read_hex(bank_card_string, &data->exp_year, 1, 1); | ||||||
|  |         } | ||||||
|  |         // Check country code presence
 | ||||||
|  |         ws = string_search_str(bank_card_string, "Country code: "); | ||||||
|  |         if(ws != STRING_FAILURE) { | ||||||
|  |             // strlen("Country code: ") = 14
 | ||||||
|  |             string_right(bank_card_string, 14); | ||||||
|  |             nfc_device_read_hex(bank_card_string, code, 2, 0); | ||||||
|  |             data->country_code = code[0] << 8 | code[1]; | ||||||
|  |         } | ||||||
|  |         // Check currency code presence
 | ||||||
|  |         ws = string_search_str(bank_card_string, "Currency code: "); | ||||||
|  |         if(ws != STRING_FAILURE) { | ||||||
|  |             // strlen("Currency code: ") = 15
 | ||||||
|  |             string_right(bank_card_string, 15); | ||||||
|  |             nfc_device_read_hex(bank_card_string, code, 2, 0); | ||||||
|  |             data->currency_code = code[0] << 8 | code[1]; | ||||||
|         } |         } | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ typedef struct { | |||||||
|     uint8_t sak; |     uint8_t sak; | ||||||
|     NfcDeviceType device; |     NfcDeviceType device; | ||||||
|     NfcProtocol protocol; |     NfcProtocol protocol; | ||||||
| } NfcDeviceCommomData; | } NfcDeviceCommonData; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     char name[32]; |     char name[32]; | ||||||
| @ -43,11 +43,12 @@ typedef struct { | |||||||
|     uint8_t number[8]; |     uint8_t number[8]; | ||||||
|     uint8_t exp_mon; |     uint8_t exp_mon; | ||||||
|     uint8_t exp_year; |     uint8_t exp_year; | ||||||
|     char cardholder[32]; |     uint16_t country_code; | ||||||
|  |     uint16_t currency_code; | ||||||
| } NfcEmvData; | } NfcEmvData; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     NfcDeviceCommomData nfc_data; |     NfcDeviceCommonData nfc_data; | ||||||
|     union { |     union { | ||||||
|         NfcEmvData emv_data; |         NfcEmvData emv_data; | ||||||
|         MifareUlData mf_ul_data; |         MifareUlData mf_ul_data; | ||||||
|  | |||||||
| @ -100,7 +100,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { | |||||||
|     rfalNfcDevice* dev_list; |     rfalNfcDevice* dev_list; | ||||||
|     rfalNfcDevice* dev; |     rfalNfcDevice* dev; | ||||||
|     uint8_t dev_cnt; |     uint8_t dev_cnt; | ||||||
|     NfcDeviceCommomData* result = &nfc_worker->dev_data->nfc_data; |     NfcDeviceCommonData* result = &nfc_worker->dev_data->nfc_data; | ||||||
| 
 | 
 | ||||||
|     while(nfc_worker->state == NfcWorkerStateDetect) { |     while(nfc_worker->state == NfcWorkerStateDetect) { | ||||||
|         if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) { |         if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) { | ||||||
| @ -141,7 +141,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_worker_emulate(NfcWorker* nfc_worker) { | void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||||
|     NfcDeviceCommomData* data = &nfc_worker->dev_data->nfc_data; |     NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data; | ||||||
|     while(nfc_worker->state == NfcWorkerStateEmulate) { |     while(nfc_worker->state == NfcWorkerStateEmulate) { | ||||||
|         if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { |         if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { | ||||||
|             FURI_LOG_I(NFC_WORKER_TAG, "Reader detected"); |             FURI_LOG_I(NFC_WORKER_TAG, "Reader detected"); | ||||||
| @ -328,6 +328,12 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                             result->emv_data.exp_mon = emv_app.exp_month; |                             result->emv_data.exp_mon = emv_app.exp_month; | ||||||
|                             result->emv_data.exp_year = emv_app.exp_year; |                             result->emv_data.exp_year = emv_app.exp_year; | ||||||
|                         } |                         } | ||||||
|  |                         if(emv_app.country_code) { | ||||||
|  |                             result->emv_data.country_code = emv_app.country_code; | ||||||
|  |                         } | ||||||
|  |                         if(emv_app.currency_code) { | ||||||
|  |                             result->emv_data.currency_code = emv_app.currency_code; | ||||||
|  |                         } | ||||||
|                         // Notify caller and exit
 |                         // Notify caller and exit
 | ||||||
|                         if(nfc_worker->callback) { |                         if(nfc_worker->callback) { | ||||||
|                             nfc_worker->callback(nfc_worker->context); |                             nfc_worker->callback(nfc_worker->context); | ||||||
| @ -358,7 +364,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { | |||||||
|     uint16_t tx_len = 0; |     uint16_t tx_len = 0; | ||||||
|     uint8_t* rx_buff; |     uint8_t* rx_buff; | ||||||
|     uint16_t* rx_len; |     uint16_t* rx_len; | ||||||
|     NfcDeviceCommomData params = { |     NfcDeviceCommonData params = { | ||||||
|         .uid = {0xCF, 0x72, 0xd4, 0x40}, |         .uid = {0xCF, 0x72, 0xd4, 0x40}, | ||||||
|         .uid_len = 4, |         .uid_len = 4, | ||||||
|         .atqa = {0x00, 0x04}, |         .atqa = {0x00, 0x04}, | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ void nfc_scene_delete_on_enter(void* context) { | |||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); |         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); | ||||||
|     char uid_str[32]; |     char uid_str[32]; | ||||||
|     NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data; | ||||||
|     if(data->uid_len == 4) { |     if(data->uid_len == 4) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             uid_str, |             uid_str, | ||||||
|  | |||||||
							
								
								
									
										33
									
								
								applications/nfc/scenes/nfc_scene_device_info.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| @ -1,6 +1,6 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_DEVICE_INFO_TEXTBOX_CUSTOM_EVENT (0UL) | #define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL) | ||||||
| 
 | 
 | ||||||
| enum { | enum { | ||||||
|     NfcSceneDeviceInfoUid, |     NfcSceneDeviceInfoUid, | ||||||
| @ -8,26 +8,27 @@ enum { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_device_info_widget_callback(GuiButtonType result, void* context) { | void nfc_scene_device_info_widget_callback(GuiButtonType result, void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 |  | ||||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) { | void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 |  | ||||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_device_info_text_box_callback(void* context) { | void nfc_scene_device_info_text_box_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|  |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_send_custom_event( | void nfc_scene_device_info_bank_card_callback(GuiButtonType result, void* context) { | ||||||
|         nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_TEXTBOX_CUSTOM_EVENT); |     Nfc* nfc = context; | ||||||
|  |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_device_info_on_enter(void* context) { | void nfc_scene_device_info_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
| @ -37,7 +38,7 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); |         nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); | ||||||
|     char uid_str[32]; |     char uid_str[32]; | ||||||
|     NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data; | ||||||
|     if(data->uid_len == 4) { |     if(data->uid_len == 4) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             uid_str, |             uid_str, | ||||||
| @ -107,19 +108,23 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|         BankCard* bank_card = nfc->bank_card; |         BankCard* bank_card = nfc->bank_card; | ||||||
|         bank_card_set_name(bank_card, emv_data->name); |         bank_card_set_name(bank_card, emv_data->name); | ||||||
|         bank_card_set_number(bank_card, emv_data->number); |         bank_card_set_number(bank_card, emv_data->number); | ||||||
|         if(!strcmp(emv_data->name, "")) { |         bank_card_set_back_callback(bank_card, nfc_scene_device_info_bank_card_callback, nfc); | ||||||
|             bank_card_set_cardholder_name(bank_card, emv_data->cardholder); |  | ||||||
|         } |  | ||||||
|         if(emv_data->exp_mon) { |         if(emv_data->exp_mon) { | ||||||
|             bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year); |             bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year); | ||||||
|         } |         } | ||||||
|  |         if(emv_data->country_code) { | ||||||
|  |             bank_card_set_country_name(bank_card, emv_data->country_code); | ||||||
|  |         } | ||||||
|  |         if(emv_data->currency_code) { | ||||||
|  |             bank_card_set_currency_name(bank_card, emv_data->currency_code); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); |     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { | const bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
|     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo); |     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ const void nfc_scene_emulate_uid_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
|     NfcDeviceCommomData* data = &nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data; | ||||||
| 
 | 
 | ||||||
|     if(strcmp(nfc->dev.dev_name, "")) { |     if(strcmp(nfc->dev.dev_name, "")) { | ||||||
|         nfc_text_store_set(nfc, "%s", nfc->dev.dev_name); |         nfc_text_store_set(nfc, "%s", nfc->dev.dev_name); | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { | |||||||
|     notification_message(nfc->notifications, &sequence_success); |     notification_message(nfc->notifications, &sequence_success); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     NfcDeviceCommomData* data = (NfcDeviceCommomData*)&nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* data = (NfcDeviceCommonData*)&nfc->dev.dev_data.nfc_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); |     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "More"); |     dialog_ex_set_right_button_text(dialog_ex, "More"); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include "../helpers/nfc_emv_parser.h" | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | ||||||
| 
 | 
 | ||||||
| @ -12,7 +13,7 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) { | |||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     NfcDeviceCommomData* nfc_data = &nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data; | ||||||
|     NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; |     NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); |     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||||
| @ -21,9 +22,12 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) { | |||||||
|     dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); |     dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); | ||||||
|     // Display UID and AID
 |     // Display UID and AID
 | ||||||
|     string_t aid; |     string_t aid; | ||||||
|     string_init_printf(aid, "AID:"); |     string_init(aid); | ||||||
|     for(uint8_t i = 0; i < emv_data->aid_len; i++) { |     bool aid_found = nfc_emv_parser_get_aid_name(emv_data->aid, emv_data->aid_len, aid); | ||||||
|         string_cat_printf(aid, " %02X", emv_data->aid[i]); |     if(!aid_found) { | ||||||
|  |         for(uint8_t i = 0; i < emv_data->aid_len; i++) { | ||||||
|  |             string_cat_printf(aid, " %02X", emv_data->aid[i]); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     nfc_text_store_set( |     nfc_text_store_set( | ||||||
|         nfc, |         nfc, | ||||||
|  | |||||||
| @ -16,6 +16,8 @@ const void nfc_scene_read_emv_data_on_enter(void* context) { | |||||||
|     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); |     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||||
|  |     // Clear emv data
 | ||||||
|  |     memset(&nfc->dev.dev_data.emv_data, 0, sizeof(nfc->dev.dev_data.emv_data)); | ||||||
|     // Start worker
 |     // Start worker
 | ||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, |         nfc->worker, | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include "../helpers/nfc_emv_parser.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_emv_data_success_widget_callback(GuiButtonType result, void* context) { | void nfc_scene_read_emv_data_success_widget_callback(GuiButtonType result, void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
| @ -9,12 +10,15 @@ void nfc_scene_read_emv_data_success_widget_callback(GuiButtonType result, void* | |||||||
| void nfc_scene_read_emv_data_success_on_enter(void* context) { | void nfc_scene_read_emv_data_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
|     NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; |     NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; | ||||||
|     NfcDeviceCommomData* nfc_data = &nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data; | ||||||
| 
 | 
 | ||||||
|     // Clear device name
 |     // Clear device name
 | ||||||
|     nfc_device_set_name(&nfc->dev, ""); |     nfc_device_set_name(&nfc->dev, ""); | ||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|  |     // Add frame
 | ||||||
|  |     widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6); | ||||||
|  |     // Add buttons
 | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, |         nfc->widget, | ||||||
|         GuiButtonTypeLeft, |         GuiButtonTypeLeft, | ||||||
| @ -27,8 +31,10 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { | |||||||
|         "Save", |         "Save", | ||||||
|         nfc_scene_read_emv_data_success_widget_callback, |         nfc_scene_read_emv_data_success_widget_callback, | ||||||
|         nfc); |         nfc); | ||||||
|  |     // Add card name
 | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev.dev_data.emv_data.name); |         nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev.dev_data.emv_data.name); | ||||||
|  |     // Add cad number
 | ||||||
|     char pan_str[32]; |     char pan_str[32]; | ||||||
|     snprintf( |     snprintf( | ||||||
|         pan_str, |         pan_str, | ||||||
| @ -43,9 +49,41 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { | |||||||
|         emv_data->number[6], |         emv_data->number[6], | ||||||
|         emv_data->number[7]); |         emv_data->number[7]); | ||||||
|     widget_add_string_element(nfc->widget, 64, 13, AlignCenter, AlignTop, FontSecondary, pan_str); |     widget_add_string_element(nfc->widget, 64, 13, AlignCenter, AlignTop, FontSecondary, pan_str); | ||||||
|  |     // Parse country code
 | ||||||
|  |     string_t country_name; | ||||||
|  |     string_init(country_name); | ||||||
|  |     if((emv_data->country_code) && | ||||||
|  |        nfc_emv_parser_get_country_name(emv_data->country_code, country_name)) { | ||||||
|  |         string_t disp_country; | ||||||
|  |         string_init_printf(disp_country, "Reg:%s", country_name); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             nfc->widget, 7, 23, AlignLeft, AlignTop, FontSecondary, string_get_cstr(disp_country)); | ||||||
|  |         string_clear(disp_country); | ||||||
|  |     } | ||||||
|  |     string_clear(country_name); | ||||||
|  |     // Parse currency code
 | ||||||
|  |     string_t currency_name; | ||||||
|  |     string_init(currency_name); | ||||||
|  |     if((emv_data->currency_code) && | ||||||
|  |        nfc_emv_parser_get_currency_name(emv_data->currency_code, currency_name)) { | ||||||
|  |         string_t disp_currency; | ||||||
|  |         string_init_printf(disp_currency, "Cur:%s", currency_name); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             nfc->widget, | ||||||
|  |             121, | ||||||
|  |             23, | ||||||
|  |             AlignRight, | ||||||
|  |             AlignTop, | ||||||
|  |             FontSecondary, | ||||||
|  |             string_get_cstr(disp_currency)); | ||||||
|  |         string_clear(disp_currency); | ||||||
|  |     } | ||||||
|  |     string_clear(currency_name); | ||||||
|  |     // Add ATQA
 | ||||||
|     char atqa_str[16]; |     char atqa_str[16]; | ||||||
|     snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); |     snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); | ||||||
|     widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str); |     widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str); | ||||||
|  |     // Add UID
 | ||||||
|     char uid_str[32]; |     char uid_str[32]; | ||||||
|     snprintf( |     snprintf( | ||||||
|         uid_str, |         uid_str, | ||||||
| @ -56,9 +94,11 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { | |||||||
|         nfc_data->uid[2], |         nfc_data->uid[2], | ||||||
|         nfc_data->uid[3]); |         nfc_data->uid[3]); | ||||||
|     widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str); |     widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str); | ||||||
|  |     // Add SAK
 | ||||||
|     char sak_str[16]; |     char sak_str[16]; | ||||||
|     snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak); |     snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak); | ||||||
|     widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str); |     widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str); | ||||||
|  |     // Add expiration date
 | ||||||
|     if(emv_data->exp_mon) { |     if(emv_data->exp_mon) { | ||||||
|         char exp_str[16]; |         char exp_str[16]; | ||||||
|         snprintf( |         snprintf( | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ const void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | |||||||
|     notification_message(nfc->notifications, &sequence_success); |     notification_message(nfc->notifications, &sequence_success); | ||||||
| 
 | 
 | ||||||
|     // Setup dialog view
 |     // Setup dialog view
 | ||||||
|     NfcDeviceCommomData* data = (NfcDeviceCommomData*)&nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* data = (NfcDeviceCommonData*)&nfc->dev.dev_data.nfc_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); |     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "More"); |     dialog_ex_set_right_button_text(dialog_ex, "More"); | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "bank_card.h" | #include "bank_card.h" | ||||||
| #include <gui/modules/widget.h> | #include "../helpers/nfc_emv_parser.h" | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| 
 | 
 | ||||||
| struct BankCard { | struct BankCard { | ||||||
| @ -43,10 +43,20 @@ void bank_card_set_number(BankCard* bank_card, uint8_t* number) { | |||||||
|     for(uint8_t i = 0; i < 8; i += 2) { |     for(uint8_t i = 0; i < 8; i += 2) { | ||||||
|         string_cat_printf(num_str, "%02X%02X ", number[i], number[i + 1]); |         string_cat_printf(num_str, "%02X%02X ", number[i], number[i + 1]); | ||||||
|     } |     } | ||||||
|  |     // Add number
 | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         bank_card->widget, 25, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(num_str)); |         bank_card->widget, 64, 32, AlignCenter, AlignTop, FontSecondary, string_get_cstr(num_str)); | ||||||
|     widget_add_icon_element(bank_card->widget, 6, 20, &I_EMV_Chip_14x11); |  | ||||||
|     string_clear(num_str); |     string_clear(num_str); | ||||||
|  |     // Add icon
 | ||||||
|  |     widget_add_icon_element(bank_card->widget, 8, 15, &I_Detailed_chip_17x13); | ||||||
|  |     // Add frame
 | ||||||
|  |     widget_add_frame_element(bank_card->widget, 0, 0, 128, 64, 6); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void bank_card_set_back_callback(BankCard* bank_card, ButtonCallback callback, void* context) { | ||||||
|  |     furi_assert(bank_card); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     widget_add_button_element(bank_card->widget, GuiButtonTypeLeft, "Back", callback, context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) { | void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) { | ||||||
| @ -57,8 +67,42 @@ void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) { | |||||||
|         bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str); |         bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bank_card_set_cardholder_name(BankCard* bank_card, char* name) { | void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code) { | ||||||
|     furi_assert(bank_card); |     furi_assert(bank_card); | ||||||
|     furi_assert(name); |     string_t country_name; | ||||||
|     widget_add_string_element(bank_card->widget, 6, 37, AlignLeft, AlignTop, FontSecondary, name); |     string_init(country_name); | ||||||
|  |     if(nfc_emv_parser_get_country_name(country_code, country_name)) { | ||||||
|  |         string_t disp_country; | ||||||
|  |         string_init_printf(disp_country, "Reg:%s", country_name); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             bank_card->widget, | ||||||
|  |             120, | ||||||
|  |             18, | ||||||
|  |             AlignRight, | ||||||
|  |             AlignTop, | ||||||
|  |             FontSecondary, | ||||||
|  |             string_get_cstr(disp_country)); | ||||||
|  |         string_clear(disp_country); | ||||||
|  |     } | ||||||
|  |     string_clear(country_name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code) { | ||||||
|  |     furi_assert(bank_card); | ||||||
|  |     string_t currency_name; | ||||||
|  |     string_init(currency_name); | ||||||
|  |     if(nfc_emv_parser_get_currency_name(currency_code, currency_name)) { | ||||||
|  |         string_t disp_currency; | ||||||
|  |         string_init_printf(disp_currency, "Cur:%s", currency_name); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             bank_card->widget, | ||||||
|  |             31, | ||||||
|  |             18, | ||||||
|  |             AlignLeft, | ||||||
|  |             AlignTop, | ||||||
|  |             FontSecondary, | ||||||
|  |             string_get_cstr(disp_currency)); | ||||||
|  |         string_clear(disp_currency); | ||||||
|  |     } | ||||||
|  |     string_clear(currency_name); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,11 +1,10 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
|  | #include <gui/modules/widget.h> | ||||||
| 
 | 
 | ||||||
| typedef struct BankCard BankCard; | typedef struct BankCard BankCard; | ||||||
| 
 | 
 | ||||||
| typedef void (*BankCardBackCallback)(void); |  | ||||||
| 
 |  | ||||||
| BankCard* bank_card_alloc(); | BankCard* bank_card_alloc(); | ||||||
| 
 | 
 | ||||||
| void bank_card_free(BankCard* bank_card); | void bank_card_free(BankCard* bank_card); | ||||||
| @ -14,10 +13,14 @@ void bank_card_clear(BankCard* bank_card); | |||||||
| 
 | 
 | ||||||
| View* bank_card_get_view(BankCard* bank_card); | View* bank_card_get_view(BankCard* bank_card); | ||||||
| 
 | 
 | ||||||
|  | void bank_card_set_back_callback(BankCard* bank_card, ButtonCallback callback, void* context); | ||||||
|  | 
 | ||||||
| void bank_card_set_name(BankCard* bank_card, char* name); | void bank_card_set_name(BankCard* bank_card, char* name); | ||||||
| 
 | 
 | ||||||
| void bank_card_set_number(BankCard* bank_card, uint8_t* number); | void bank_card_set_number(BankCard* bank_card, uint8_t* number); | ||||||
| 
 | 
 | ||||||
| void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year); | void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year); | ||||||
| 
 | 
 | ||||||
| void bank_card_set_cardholder_name(BankCard* bank_card, char* name); | void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code); | ||||||
|  | 
 | ||||||
|  | void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code); | ||||||
|  | |||||||
| @ -1,19 +0,0 @@ | |||||||
| #include "../subghz_i.h" |  | ||||||
| 
 |  | ||||||
| const void subghz_scene_analyze_on_enter(void* context) { |  | ||||||
|     SubGhz* subghz = context; |  | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewAnalyze); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const bool subghz_scene_analyze_on_event(void* context, SceneManagerEvent event) { |  | ||||||
|     SubGhz* subghz = context; |  | ||||||
|     if(event.type == SceneManagerEventTypeTick) { |  | ||||||
|         notification_message(subghz->notifications, &sequence_blink_blue_10); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const void subghz_scene_analyze_on_exit(void* context) { |  | ||||||
|     // SubGhz* subghz = context;
 |  | ||||||
| } |  | ||||||
| @ -1,13 +1,12 @@ | |||||||
| ADD_SCENE(subghz, start, Start) | ADD_SCENE(subghz, start, Start) | ||||||
| ADD_SCENE(subghz, analyze, Analyze) |  | ||||||
| ADD_SCENE(subghz, read, Read) |  | ||||||
| ADD_SCENE(subghz, receiver, Receiver) | ADD_SCENE(subghz, receiver, Receiver) | ||||||
| ADD_SCENE(subghz, save_name, SaveName) | ADD_SCENE(subghz, save_name, SaveName) | ||||||
| ADD_SCENE(subghz, save_success, SaveSuccess) | ADD_SCENE(subghz, save_success, SaveSuccess) | ||||||
| ADD_SCENE(subghz, saved, Saved) | ADD_SCENE(subghz, saved, Saved) | ||||||
| ADD_SCENE(subghz, transmitter, Transmitter) | ADD_SCENE(subghz, transmitter, Transmitter) | ||||||
| ADD_SCENE(subghz, static, Static) | ADD_SCENE(subghz, no_man, NoMan) | ||||||
| ADD_SCENE(subghz, test, Test) | ADD_SCENE(subghz, test, Test) | ||||||
|  | ADD_SCENE(subghz, test_static, TestStatic) | ||||||
| ADD_SCENE(subghz, test_carrier, TestCarrier) | ADD_SCENE(subghz, test_carrier, TestCarrier) | ||||||
| ADD_SCENE(subghz, test_packet, TestPacket) | ADD_SCENE(subghz, test_packet, TestPacket) | ||||||
| ADD_SCENE(subghz, set_type, SetType) | ADD_SCENE(subghz, set_type, SetType) | ||||||
|  | |||||||
							
								
								
									
										48
									
								
								applications/subghz/scenes/subghz_scene_no_man.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,48 @@ | |||||||
|  | #include "../subghz_i.h" | ||||||
|  | 
 | ||||||
|  | #define SCENE_NO_MAN_CUSTOM_EVENT (11UL) | ||||||
|  | 
 | ||||||
|  | void subghz_scene_no_man_popup_callback(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_NO_MAN_CUSTOM_EVENT); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void subghz_scene_no_man_on_enter(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  | 
 | ||||||
|  |     // Setup view
 | ||||||
|  |     Popup* popup = subghz->popup; | ||||||
|  |     popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51); | ||||||
|  |     popup_set_header(popup, "No manufactory key", 13, 8, AlignLeft, AlignBottom); | ||||||
|  |     popup_set_timeout(popup, 1500); | ||||||
|  |     popup_set_context(popup, subghz); | ||||||
|  |     popup_set_callback(popup, subghz_scene_no_man_popup_callback); | ||||||
|  |     popup_enable_timeout(popup); | ||||||
|  |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) { | ||||||
|  |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneStart); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void subghz_scene_no_man_on_exit(void* context) { | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     Popup* popup = subghz->popup; | ||||||
|  |     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); | ||||||
|  |     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); | ||||||
|  |     popup_set_icon(popup, 0, 0, NULL); | ||||||
|  |     popup_set_callback(popup, NULL); | ||||||
|  |     popup_set_context(popup, NULL); | ||||||
|  |     popup_set_timeout(popup, 0); | ||||||
|  |     popup_disable_timeout(popup); | ||||||
|  | } | ||||||
| @ -1,62 +0,0 @@ | |||||||
| #include "../subghz_i.h" |  | ||||||
| 
 |  | ||||||
| #define GUBGHZ_READ_CUSTOM_EVENT (10UL) |  | ||||||
| 
 |  | ||||||
| void subghz_read_protocol_callback(SubGhzProtocolCommon* parser, void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubGhz* subghz = context; |  | ||||||
|     subghz->protocol_result = parser; |  | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, GUBGHZ_READ_CUSTOM_EVENT); |  | ||||||
| } |  | ||||||
| void subghz_scene_read_callback(DialogExResult result, void* context) { |  | ||||||
|     SubGhz* subghz = context; |  | ||||||
|     view_dispatcher_send_custom_event(subghz->view_dispatcher, result); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const void subghz_scene_read_on_enter(void* context) { |  | ||||||
|     SubGhz* subghz = context; |  | ||||||
| 
 |  | ||||||
|     // Setup view
 |  | ||||||
|     DialogEx* dialog_ex = subghz->dialog_ex; |  | ||||||
| 
 |  | ||||||
|     dialog_ex_set_header(dialog_ex, "SubGhz 433.92", 36, 6, AlignLeft, AlignCenter); |  | ||||||
|     dialog_ex_set_icon(dialog_ex, 10, 12, &I_RFIDDolphinReceive_97x61); |  | ||||||
| 
 |  | ||||||
|     //Start CC1101 rx
 |  | ||||||
|     subghz_begin(FuriHalSubGhzPresetOokAsync); |  | ||||||
|     subghz_rx(433920000); |  | ||||||
| 
 |  | ||||||
|     furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->worker); |  | ||||||
|     subghz_worker_start(subghz->worker); |  | ||||||
|     subghz_protocol_enable_dump(subghz->protocol, subghz_read_protocol_callback, subghz); |  | ||||||
| 
 |  | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewDialogEx); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const bool subghz_scene_read_on_event(void* context, SceneManagerEvent event) { |  | ||||||
|     SubGhz* subghz = context; |  | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |  | ||||||
|         if(event.event == GUBGHZ_READ_CUSTOM_EVENT) { |  | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver); |  | ||||||
|             notification_message(subghz->notifications, &sequence_success); |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |  | ||||||
|         notification_message(subghz->notifications, &sequence_blink_blue_10); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const void subghz_scene_read_on_exit(void* context) { |  | ||||||
|     SubGhz* subghz = context; |  | ||||||
| 
 |  | ||||||
|     // Stop CC1101
 |  | ||||||
|     subghz_worker_stop(subghz->worker); |  | ||||||
|     furi_hal_subghz_stop_async_rx(); |  | ||||||
|     subghz_end(); |  | ||||||
| 
 |  | ||||||
|     DialogEx* dialog_ex = subghz->dialog_ex; |  | ||||||
|     dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); |  | ||||||
|     dialog_ex_set_icon(dialog_ex, 0, 0, NULL); |  | ||||||
| } |  | ||||||
| @ -13,7 +13,9 @@ const void subghz_scene_receiver_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     subghz_receiver_set_callback(subghz_receiver, subghz_scene_receiver_callback, subghz); |     subghz_receiver_set_callback(subghz_receiver, subghz_scene_receiver_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     subghz_receiver_set_protocol(subghz_receiver, subghz->protocol_result); |     subghz_receiver_set_protocol(subghz_receiver, subghz->protocol_result, subghz->protocol); | ||||||
|  |     subghz_receiver_set_worker(subghz_receiver, subghz->worker); | ||||||
|  |     subghz->state_notifications = NOTIFICATION_RX_STATE; | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -21,12 +23,57 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzReceverEventSave) { |         switch(event.event) { | ||||||
|  |         case SubghzReceverEventSave: | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver); | ||||||
|  |             subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver); | ||||||
|  |             subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzReceverEventBack) { |             break; | ||||||
|  |         case SubghzReceverEventBack: | ||||||
|             scene_manager_previous_scene(subghz->scene_manager); |             scene_manager_previous_scene(subghz->scene_manager); | ||||||
|             return true; |             return true; | ||||||
|  |             break; | ||||||
|  |         case SubghzReceverEventSendStart: | ||||||
|  |             subghz->state_notifications = NOTIFICATION_TX_STATE; | ||||||
|  |             subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver); | ||||||
|  |             subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver); | ||||||
|  |             subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver); | ||||||
|  |             subghz_transmitter_tx_start(subghz); | ||||||
|  |             return true; | ||||||
|  |             break; | ||||||
|  |         case SubghzReceverEventSendStop: | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             subghz_transmitter_tx_stop(subghz); | ||||||
|  |             return true; | ||||||
|  |             break; | ||||||
|  |         case SubghzReceverEventMain: | ||||||
|  |             subghz->state_notifications = NOTIFICATION_RX_STATE; | ||||||
|  |             return true; | ||||||
|  |             break; | ||||||
|  |         case SubghzReceverEventConfig: | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             return true; | ||||||
|  |             break; | ||||||
|  |         case SubghzReceverEventSendHistoryFull: | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             return true; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|  |         switch(subghz->state_notifications) { | ||||||
|  |         case NOTIFICATION_TX_STATE: | ||||||
|  |             notification_message(subghz->notifications, &sequence_blink_red_10); | ||||||
|  |             break; | ||||||
|  |         case NOTIFICATION_RX_STATE: | ||||||
|  |             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return false; |     return false; | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ const void subghz_scene_save_name_on_enter(void* context) { | |||||||
|     set_random_name(subghz->text_store, sizeof(subghz->text_store)); |     set_random_name(subghz->text_store, sizeof(subghz->text_store)); | ||||||
|     dev_name_empty = true; |     dev_name_empty = true; | ||||||
| 
 | 
 | ||||||
|     text_input_set_header_text(text_input, "Name the KEY"); |     text_input_set_header_text(text_input, "Name signal"); | ||||||
|     text_input_set_result_callback( |     text_input_set_result_callback( | ||||||
|         text_input, |         text_input, | ||||||
|         subghz_scene_save_name_text_input_callback, |         subghz_scene_save_name_text_input_callback, | ||||||
|  | |||||||
| @ -25,8 +25,12 @@ const bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent e | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) { |         if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) { | ||||||
|             return scene_manager_search_and_switch_to_previous_scene( |             if(!scene_manager_search_and_switch_to_previous_scene( | ||||||
|                 subghz->scene_manager, SubGhzSceneStart); |                    subghz->scene_manager, SubGhzSceneReceiver)) { | ||||||
|  |                 scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                     subghz->scene_manager, SubGhzSceneStart); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return false; |     return false; | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| const void subghz_scene_saved_on_enter(void* context) { | const void subghz_scene_saved_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if(subghz_saved_protocol_select(subghz)) { |     if(subghz_load_protocol_from_file(subghz)) { | ||||||
|         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); |         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); | ||||||
|     } else { |     } 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); | ||||||
|  | |||||||
| @ -32,31 +32,31 @@ const void subghz_scene_set_type_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         "Pricenton", |         "Princeton_433", | ||||||
|         SubmenuIndexPricenton, |         SubmenuIndexPricenton, | ||||||
|         subghz_scene_set_type_submenu_callback, |         subghz_scene_set_type_submenu_callback, | ||||||
|         subghz); |         subghz); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         "Nice Flo 12bit", |         "Nice Flo 12bit_433", | ||||||
|         SubmenuIndexNiceFlo12bit, |         SubmenuIndexNiceFlo12bit, | ||||||
|         subghz_scene_set_type_submenu_callback, |         subghz_scene_set_type_submenu_callback, | ||||||
|         subghz); |         subghz); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         "Nice Flo 24bit", |         "Nice Flo 24bit_433", | ||||||
|         SubmenuIndexNiceFlo24bit, |         SubmenuIndexNiceFlo24bit, | ||||||
|         subghz_scene_set_type_submenu_callback, |         subghz_scene_set_type_submenu_callback, | ||||||
|         subghz); |         subghz); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         "CAME 12bit", |         "CAME 12bit_433", | ||||||
|         SubmenuIndexCAME12bit, |         SubmenuIndexCAME12bit, | ||||||
|         subghz_scene_set_type_submenu_callback, |         subghz_scene_set_type_submenu_callback, | ||||||
|         subghz); |         subghz); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         "CAME 24bit", |         "CAME 24bit_433", | ||||||
|         SubmenuIndexCAME24bit, |         SubmenuIndexCAME24bit, | ||||||
|         subghz_scene_set_type_submenu_callback, |         subghz_scene_set_type_submenu_callback, | ||||||
|         subghz); |         subghz); | ||||||
| @ -64,13 +64,13 @@ const void subghz_scene_set_type_on_enter(void* context) { | |||||||
|     //     subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
 |     //     subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
 | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         "Gate TX", |         "Gate TX_433", | ||||||
|         SubmenuIndexGateTX, |         SubmenuIndexGateTX, | ||||||
|         subghz_scene_set_type_submenu_callback, |         subghz_scene_set_type_submenu_callback, | ||||||
|         subghz); |         subghz); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, |         subghz->submenu, | ||||||
|         "DoorHan", |         "DoorHan_433", | ||||||
|         SubmenuIndexDoorHan, |         SubmenuIndexDoorHan, | ||||||
|         subghz_scene_set_type_submenu_callback, |         subghz_scene_set_type_submenu_callback, | ||||||
|         subghz); |         subghz); | ||||||
| @ -146,11 +146,15 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event | |||||||
|                 subghz->protocol_result->serial = key & 0x0FFFFFFF; |                 subghz->protocol_result->serial = key & 0x0FFFFFFF; | ||||||
|                 subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 |                 subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
 | ||||||
|                 subghz->protocol_result->cnt = 0x0003; |                 subghz->protocol_result->cnt = 0x0003; | ||||||
|                 subghz_protocol_keeloq_set_manufacture_name(subghz->protocol_result, "DoorHan"); |                 if(subghz_protocol_keeloq_set_manufacture_name( | ||||||
|                 subghz->protocol_result->code_last_found = |                        subghz->protocol_result, "DoorHan")) { | ||||||
|                     subghz_protocol_keeloq_gen_key(subghz->protocol_result); |                     subghz->protocol_result->code_last_found = | ||||||
| 
 |                         subghz_protocol_keeloq_gen_key(subghz->protocol_result); | ||||||
|                 generated_protocol = true; |                     generated_protocol = true; | ||||||
|  |                 } else { | ||||||
|  |                     generated_protocol = false; | ||||||
|  |                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNoMan); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
| @ -159,6 +163,8 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(generated_protocol) { |         if(generated_protocol) { | ||||||
|  |             subghz->frequency = subghz_frequencies[subghz_frequencies_433_92]; | ||||||
|  |             subghz->preset = FuriHalSubGhzPresetOok650Async; | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,10 +1,8 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexAnalyze, |  | ||||||
|     SubmenuIndexRead, |     SubmenuIndexRead, | ||||||
|     SubmenuIndexSaved, |     SubmenuIndexSaved, | ||||||
|     SubmenuIndexStatic, |  | ||||||
|     SubmenuIndexTest, |     SubmenuIndexTest, | ||||||
|     SubmenuIndexAddManualy, |     SubmenuIndexAddManualy, | ||||||
| }; | }; | ||||||
| @ -19,12 +17,6 @@ const void subghz_scene_start_on_enter(void* context) { | |||||||
|     if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) { |     if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) { | ||||||
|         subghz->state_notifications = NOTIFICATION_IDLE_STATE; |         subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|     } |     } | ||||||
|     submenu_add_item( |  | ||||||
|         subghz->submenu, |  | ||||||
|         "Analyze", |  | ||||||
|         SubmenuIndexAnalyze, |  | ||||||
|         subghz_scene_start_submenu_callback, |  | ||||||
|         subghz); |  | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz); |         subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
| @ -35,8 +27,6 @@ const void subghz_scene_start_on_enter(void* context) { | |||||||
|         SubmenuIndexAddManualy, |         SubmenuIndexAddManualy, | ||||||
|         subghz_scene_start_submenu_callback, |         subghz_scene_start_submenu_callback, | ||||||
|         subghz); |         subghz); | ||||||
|     submenu_add_item( |  | ||||||
|         subghz->submenu, "Static", SubmenuIndexStatic, subghz_scene_start_submenu_callback, subghz); |  | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); |         subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); | ||||||
| 
 | 
 | ||||||
| @ -50,15 +40,10 @@ const bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexAnalyze) { |         if(event.event == SubmenuIndexRead) { | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAnalyze); |  | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneAnalyze); |  | ||||||
|             return true; |  | ||||||
|         } else if(event.event == SubmenuIndexRead) { |  | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead); |                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRead); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver); | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubmenuIndexSaved) { |         } else if(event.event == SubmenuIndexSaved) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
| @ -70,11 +55,6 @@ const bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManualy); |                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAddManualy); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType); | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubmenuIndexStatic) { |  | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexStatic); |  | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStatic); |  | ||||||
|             return true; |  | ||||||
|         } else if(event.event == SubmenuIndexTest) { |         } else if(event.event == SubmenuIndexTest) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest); |                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest); | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexCarrier, |     SubmenuIndexCarrier, | ||||||
|     SubmenuIndexPacket, |     SubmenuIndexPacket, | ||||||
|  |     SubmenuIndexStatic, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void subghz_scene_test_submenu_callback(void* context, uint32_t index) { | void subghz_scene_test_submenu_callback(void* context, uint32_t index) { | ||||||
| @ -21,6 +22,8 @@ const void subghz_scene_test_on_enter(void* context) { | |||||||
|         subghz); |         subghz); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, "Packet", SubmenuIndexPacket, subghz_scene_test_submenu_callback, subghz); |         subghz->submenu, "Packet", SubmenuIndexPacket, subghz_scene_test_submenu_callback, subghz); | ||||||
|  |     submenu_add_item( | ||||||
|  |         subghz->submenu, "Static", SubmenuIndexStatic, subghz_scene_test_submenu_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTest)); |         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTest)); | ||||||
| @ -42,6 +45,11 @@ const bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 subghz->scene_manager, SubGhzSceneTest, SubmenuIndexPacket); |                 subghz->scene_manager, SubGhzSceneTest, SubmenuIndexPacket); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestPacket); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestPacket); | ||||||
|             return true; |             return true; | ||||||
|  |         } else if(event.event == SubmenuIndexStatic) { | ||||||
|  |             scene_manager_set_scene_state( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneTest, SubmenuIndexStatic); | ||||||
|  |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestStatic); | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return false; |     return false; | ||||||
|  | |||||||
| @ -1,15 +1,15 @@ | |||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| 
 | 
 | ||||||
| const void subghz_scene_static_on_enter(void* context) { | const void subghz_scene_test_static_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewStatic); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewStatic); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const bool subghz_scene_static_on_event(void* context, SceneManagerEvent event) { | const bool subghz_scene_test_static_on_event(void* context, SceneManagerEvent event) { | ||||||
|     // SubGhz* subghz = context;
 |     // SubGhz* subghz = context;
 | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const void subghz_scene_static_on_exit(void* context) { | const void subghz_scene_test_static_on_exit(void* context) { | ||||||
|     // SubGhz* subghz = context;
 |     // SubGhz* subghz = context;
 | ||||||
| } | } | ||||||
| @ -13,6 +13,7 @@ const void subghz_scene_transmitter_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     subghz_transmitter_set_callback(subghz_transmitter, subghz_scene_transmitter_callback, subghz); |     subghz_transmitter_set_callback(subghz_transmitter, subghz_scene_transmitter_callback, subghz); | ||||||
|     subghz_transmitter_set_protocol(subghz_transmitter, subghz->protocol_result); |     subghz_transmitter_set_protocol(subghz_transmitter, subghz->protocol_result); | ||||||
|  |     subghz_transmitter_set_frequency_preset(subghz_transmitter, subghz->frequency, subghz->preset); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); | ||||||
| 
 | 
 | ||||||
| @ -30,12 +31,18 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev | |||||||
|         } else if(event.event == SubghzTransmitterEventSendStop) { |         } else if(event.event == SubghzTransmitterEventSendStop) { | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|             subghz_transmitter_tx_stop(subghz); |             subghz_transmitter_tx_stop(subghz); | ||||||
|  |             subghz_sleep(); | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzTransmitterEventBack) { |         } else if(event.event == SubghzTransmitterEventBack) { | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|             scene_manager_search_and_switch_to_previous_scene( |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|                 subghz->scene_manager, SubGhzSceneStart); |                 subghz->scene_manager, SubGhzSceneStart); | ||||||
|             return true; |             return true; | ||||||
|  |         } else if(event.event == SubghzTransmitterEventNoMan) { | ||||||
|  |             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||||
|  |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                 subghz->scene_manager, SubGhzSceneNoMan); | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         if(subghz->state_notifications == NOTIFICATION_TX_STATE) { |         if(subghz->state_notifications == NOTIFICATION_TX_STATE) { | ||||||
|  | |||||||
| @ -70,13 +70,6 @@ SubGhz* subghz_alloc() { | |||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, SubGhzViewMenu, submenu_get_view(subghz->submenu)); |         subghz->view_dispatcher, SubGhzViewMenu, submenu_get_view(subghz->submenu)); | ||||||
| 
 | 
 | ||||||
|     // Analyze
 |  | ||||||
|     subghz->subghz_analyze = subghz_analyze_alloc(); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         subghz->view_dispatcher, |  | ||||||
|         SubGhzViewAnalyze, |  | ||||||
|         subghz_analyze_get_view(subghz->subghz_analyze)); |  | ||||||
| 
 |  | ||||||
|     // Receiver
 |     // Receiver
 | ||||||
|     subghz->subghz_receiver = subghz_receiver_alloc(); |     subghz->subghz_receiver = subghz_receiver_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -121,9 +114,11 @@ SubGhz* subghz_alloc() { | |||||||
|         subghz_test_packet_get_view(subghz->subghz_test_packet)); |         subghz_test_packet_get_view(subghz->subghz_test_packet)); | ||||||
| 
 | 
 | ||||||
|     // Static send
 |     // Static send
 | ||||||
|     subghz->subghz_static = subghz_static_alloc(); |     subghz->subghz_test_static = subghz_test_static_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, SubGhzViewStatic, subghz_static_get_view(subghz->subghz_static)); |         subghz->view_dispatcher, | ||||||
|  |         SubGhzViewStatic, | ||||||
|  |         subghz_test_static_get_view(subghz->subghz_test_static)); | ||||||
| 
 | 
 | ||||||
|     //init Worker & Protocol
 |     //init Worker & Protocol
 | ||||||
|     subghz->worker = subghz_worker_alloc(); |     subghz->worker = subghz_worker_alloc(); | ||||||
| @ -134,8 +129,8 @@ SubGhz* subghz_alloc() { | |||||||
|         subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); |         subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); | ||||||
|     subghz_worker_set_context(subghz->worker, subghz->protocol); |     subghz_worker_set_context(subghz->worker, subghz->protocol); | ||||||
| 
 | 
 | ||||||
|     subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/assets/subghz/keeloq_mfcodes"); |     subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/subghz/keeloq_mfcodes"); | ||||||
|     subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/assets/subghz/nice_floor_s_rx"); |     subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/subghz/nice_floor_s_rx"); | ||||||
| 
 | 
 | ||||||
|     //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
 |     //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
 | ||||||
| 
 | 
 | ||||||
| @ -155,11 +150,7 @@ void subghz_free(SubGhz* subghz) { | |||||||
| 
 | 
 | ||||||
|     // Static
 |     // Static
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic); | ||||||
|     subghz_static_free(subghz->subghz_static); |     subghz_test_static_free(subghz->subghz_test_static); | ||||||
| 
 |  | ||||||
|     // Analyze
 |  | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewAnalyze); |  | ||||||
|     subghz_analyze_free(subghz->subghz_analyze); |  | ||||||
| 
 | 
 | ||||||
|     // Receiver
 |     // Receiver
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver); | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
|     frequency = furi_hal_subghz_set_frequency_and_path(frequency); |     frequency = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
| 
 | 
 | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||||
| @ -79,7 +79,7 @@ void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
|     frequency = furi_hal_subghz_set_frequency_and_path(frequency); |     frequency = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
|     printf("Receiving at frequency %lu Hz\r\n", frequency); |     printf("Receiving at frequency %lu Hz\r\n", frequency); | ||||||
|     printf("Press CTRL+C to stop\r\n"); |     printf("Press CTRL+C to stop\r\n"); | ||||||
| @ -134,12 +134,12 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) { | |||||||
|     protocol->common.code_last_found = key; |     protocol->common.code_last_found = key; | ||||||
|     protocol->common.code_last_count_bit = 24; |     protocol->common.code_last_count_bit = 24; | ||||||
| 
 | 
 | ||||||
|     SubGhzProtocolEncoderCommon* encoder = subghz_protocol_encoder_common_alloc(); |     SubGhzProtocolCommonEncoder* encoder = subghz_protocol_encoder_common_alloc(); | ||||||
|     encoder->repeat = repeat; |     encoder->repeat = repeat; | ||||||
| 
 | 
 | ||||||
|     subghz_protocol_princeton_send_key(protocol, encoder); |     subghz_protocol_princeton_send_key(protocol, encoder); | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
|     frequency = furi_hal_subghz_set_frequency_and_path(frequency); |     frequency = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
|     furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, encoder); |     furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, encoder); | ||||||
| 
 | 
 | ||||||
| @ -206,13 +206,13 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) { | |||||||
|     furi_check(instance->stream); |     furi_check(instance->stream); | ||||||
| 
 | 
 | ||||||
|     SubGhzProtocol* protocol = subghz_protocol_alloc(); |     SubGhzProtocol* protocol = subghz_protocol_alloc(); | ||||||
|     subghz_protocol_load_keeloq_file(protocol, "/ext/assets/subghz/keeloq_mfcodes"); |     subghz_protocol_load_keeloq_file(protocol, "/ext/subghz/keeloq_mfcodes"); | ||||||
|     subghz_protocol_load_nice_flor_s_file(protocol, "/ext/assets/subghz/nice_floor_s_rx"); |     subghz_protocol_load_nice_flor_s_file(protocol, "/ext/subghz/nice_floor_s_rx"); | ||||||
|     subghz_protocol_enable_dump_text(protocol, subghz_cli_command_rx_text_callback, instance); |     subghz_protocol_enable_dump_text(protocol, subghz_cli_command_rx_text_callback, instance); | ||||||
| 
 | 
 | ||||||
|     // Configure radio
 |     // Configure radio
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
|     frequency = furi_hal_subghz_set_frequency_and_path(frequency); |     frequency = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										164
									
								
								applications/subghz/subghz_history.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,164 @@ | |||||||
|  | #include "subghz_history.h" | ||||||
|  | #include <lib/subghz/protocols/subghz_protocol_keeloq.h> | ||||||
|  | #include <lib/subghz/protocols/subghz_protocol_star_line.h> | ||||||
|  | #include <lib/subghz/protocols/subghz_protocol_princeton.h> | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include <m-string.h> | ||||||
|  | 
 | ||||||
|  | #define SUBGHZ_HISTORY_MAX 50 | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzHistoryStruct SubGhzHistoryStruct; | ||||||
|  | 
 | ||||||
|  | struct SubGhzHistoryStruct { | ||||||
|  |     const char* name; | ||||||
|  |     const char* manufacture_name; | ||||||
|  |     uint8_t type_protocol; | ||||||
|  |     uint8_t code_count_bit; | ||||||
|  |     uint64_t code_found; | ||||||
|  |     uint16_t te; | ||||||
|  |     FuriHalSubGhzPreset preset; | ||||||
|  |     uint32_t real_frequency; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SubGhzHistory { | ||||||
|  |     uint32_t last_update_timestamp; | ||||||
|  |     uint16_t last_index_write; | ||||||
|  |     uint64_t code_last_found; | ||||||
|  |     SubGhzHistoryStruct history[SUBGHZ_HISTORY_MAX]; | ||||||
|  |     SubGhzProtocolCommonLoad data; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | SubGhzHistory* subghz_history_alloc(void) { | ||||||
|  |     SubGhzHistory* instance = furi_alloc(sizeof(SubGhzHistory)); | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_history_free(SubGhzHistory* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     free(instance); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_history_set_frequency_preset( | ||||||
|  |     SubGhzHistory* instance, | ||||||
|  |     uint16_t idx, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return; | ||||||
|  |     instance->history[idx].preset = preset; | ||||||
|  |     instance->history[idx].real_frequency = frequency; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     return instance->history[idx].real_frequency; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     return instance->history[idx].preset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_history_clean(SubGhzHistory* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     instance->last_index_write = 0; | ||||||
|  |     instance->code_last_found = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t subghz_history_get_item(SubGhzHistory* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     return instance->last_index_write; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     return instance->history[idx].type_protocol; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     return instance->history[idx].name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     instance->data.code_found = instance->history[idx].code_found; | ||||||
|  |     instance->data.code_count_bit = instance->history[idx].code_count_bit; | ||||||
|  |     instance->data.param1 = instance->history[idx].te; | ||||||
|  |     return &instance->data; | ||||||
|  | } | ||||||
|  | bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     if(instance->last_index_write == SUBGHZ_HISTORY_MAX) { | ||||||
|  |         if(output != NULL) string_printf(output, "Memory is FULL"); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     if(output != NULL) | ||||||
|  |         string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) { | ||||||
|  |     if(instance->history[idx].code_count_bit < 33) { | ||||||
|  |         string_printf( | ||||||
|  |             output, | ||||||
|  |             "%s %lX", | ||||||
|  |             instance->history[idx].name, | ||||||
|  |             (uint32_t)(instance->history[idx].code_found & 0xFFFFFFFF)); | ||||||
|  |     } else { | ||||||
|  |         string_t str_buff; | ||||||
|  |         string_init(str_buff); | ||||||
|  |         if(strcmp(instance->history[idx].name, "KeeLoq") == 0) { | ||||||
|  |             string_set(str_buff, "KL "); | ||||||
|  |             string_cat(str_buff, instance->history[idx].manufacture_name); | ||||||
|  |         } else if(strcmp(instance->history[idx].name, "Star Line") == 0) { | ||||||
|  |             string_set(str_buff, "SL "); | ||||||
|  |             string_cat(str_buff, instance->history[idx].manufacture_name); | ||||||
|  |         } else { | ||||||
|  |             string_set(str_buff, instance->history[idx].name); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         string_printf( | ||||||
|  |             output, | ||||||
|  |             "%s %lX%08lX", | ||||||
|  |             string_get_cstr(str_buff), | ||||||
|  |             (uint32_t)(instance->history[idx].code_found >> 32), | ||||||
|  |             (uint32_t)(instance->history[idx].code_found & 0xFFFFFFFF)); | ||||||
|  |         string_clear(str_buff); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_history_add_to_history(SubGhzHistory* instance, void* context) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzProtocolCommon* protocol = context; | ||||||
|  | 
 | ||||||
|  |     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return; | ||||||
|  |     if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) && | ||||||
|  |        ((millis() - instance->last_update_timestamp) < 500)) { | ||||||
|  |         instance->last_update_timestamp = millis(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF; | ||||||
|  |     instance->last_update_timestamp = millis(); | ||||||
|  | 
 | ||||||
|  |     instance->history[instance->last_index_write].te = 0; | ||||||
|  |     instance->history[instance->last_index_write].manufacture_name = NULL; | ||||||
|  |     instance->history[instance->last_index_write].name = protocol->name; | ||||||
|  |     instance->history[instance->last_index_write].code_count_bit = protocol->code_last_count_bit; | ||||||
|  |     instance->history[instance->last_index_write].code_found = protocol->code_last_found; | ||||||
|  |     if(strcmp(protocol->name, "KeeLoq") == 0) { | ||||||
|  |         instance->history[instance->last_index_write].manufacture_name = | ||||||
|  |             subghz_protocol_keeloq_find_and_get_manufacture_name(protocol); | ||||||
|  |     } else if(strcmp(protocol->name, "Star Line") == 0) { | ||||||
|  |         instance->history[instance->last_index_write].manufacture_name = | ||||||
|  |             subghz_protocol_star_line_find_and_get_manufacture_name(protocol); | ||||||
|  |     } else if(strcmp(protocol->name, "Princeton") == 0) { | ||||||
|  |         instance->history[instance->last_index_write].te = | ||||||
|  |             subghz_protocol_princeton_get_te(protocol); | ||||||
|  |     } | ||||||
|  |     instance->history[instance->last_index_write].type_protocol = protocol->type_protocol; | ||||||
|  | 
 | ||||||
|  |     instance->last_index_write++; | ||||||
|  | } | ||||||
							
								
								
									
										106
									
								
								applications/subghz/subghz_history.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,106 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <lib/subghz/protocols/subghz_protocol_common.h> | ||||||
|  | 
 | ||||||
|  | typedef struct SubGhzHistory SubGhzHistory; | ||||||
|  | 
 | ||||||
|  | /** Allocate SubGhzHistory
 | ||||||
|  |  *  | ||||||
|  |  * @return SubGhzHistory*  | ||||||
|  |  */ | ||||||
|  | SubGhzHistory* subghz_history_alloc(void); | ||||||
|  | 
 | ||||||
|  | /** Free SubGhzHistory
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzHistory instance | ||||||
|  |  */ | ||||||
|  | void subghz_history_free(SubGhzHistory* instance); | ||||||
|  | 
 | ||||||
|  | /** Clear history
 | ||||||
|  |  *  | ||||||
|  |  * @param instance - SubGhzHistory instance | ||||||
|  |  */ | ||||||
|  | void subghz_history_clean(SubGhzHistory* instance); | ||||||
|  | 
 | ||||||
|  | /** Set frequency and preset to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @param frequency - frequency Hz | ||||||
|  |  * @param preset    - FuriHalSubGhzPreset preset | ||||||
|  |  */ | ||||||
|  | void subghz_history_set_frequency_preset( | ||||||
|  |     SubGhzHistory* instance, | ||||||
|  |     uint16_t idx, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | 
 | ||||||
|  | /** Get frequency to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @return frequency - frequency Hz | ||||||
|  |  */ | ||||||
|  | uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get preset to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @return preset    - FuriHalSubGhzPreset preset | ||||||
|  |  */ | ||||||
|  | FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get history index write 
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @return idx      - current record index   | ||||||
|  |  */ | ||||||
|  | uint16_t subghz_history_get_item(SubGhzHistory* instance); | ||||||
|  | 
 | ||||||
|  | /** Get type protocol to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @return type      - type protocol   | ||||||
|  |  */ | ||||||
|  | uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get name protocol to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index   | ||||||
|  |  * @return name      - const char* name protocol   | ||||||
|  |  */ | ||||||
|  | const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get string item menu to history[idx]
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param output    - string_t output | ||||||
|  |  * @param idx       - record index | ||||||
|  |  */ | ||||||
|  | void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx); | ||||||
|  | 
 | ||||||
|  | /** Get string the remaining number of records to history
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param output    - string_t output | ||||||
|  |  * @return bool - is FUUL | ||||||
|  |  */ | ||||||
|  | bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output); | ||||||
|  | 
 | ||||||
|  | /** Add protocol to history
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param context    - SubGhzProtocolCommon context | ||||||
|  |  */ | ||||||
|  | void subghz_history_add_to_history(SubGhzHistory* instance, void* context); | ||||||
|  | 
 | ||||||
|  | /** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
 | ||||||
|  |  *  | ||||||
|  |  * @param instance  - SubGhzHistory instance | ||||||
|  |  * @param idx       - record index | ||||||
|  |  * @return SubGhzProtocolCommonLoad* | ||||||
|  |  */ | ||||||
|  | SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); | ||||||
| @ -8,6 +8,7 @@ | |||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| #include "file-worker.h" | #include "file-worker.h" | ||||||
| #include "../notification/notification.h" | #include "../notification/notification.h" | ||||||
|  | #include "views/subghz_receiver.h" | ||||||
| 
 | 
 | ||||||
| void subghz_begin(FuriHalSubGhzPreset preset) { | void subghz_begin(FuriHalSubGhzPreset preset) { | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
| @ -16,30 +17,59 @@ void subghz_begin(FuriHalSubGhzPreset preset) { | |||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_rx(uint32_t frequency) { | uint32_t subghz_rx(void* context, uint32_t frequency) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzWorker* worker = context; | ||||||
|  | 
 | ||||||
|     furi_hal_subghz_idle(); |     furi_hal_subghz_idle(); | ||||||
|     furi_hal_subghz_set_frequency_and_path(frequency); |     uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
|     furi_hal_subghz_flush_rx(); |     furi_hal_subghz_flush_rx(); | ||||||
|     furi_hal_subghz_rx(); |     furi_hal_subghz_rx(); | ||||||
|  | 
 | ||||||
|  |     furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, worker); | ||||||
|  |     subghz_worker_start(worker); | ||||||
|  |     return value; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_tx(uint32_t frequency) { | uint32_t subghz_tx(uint32_t frequency) { | ||||||
|     furi_hal_subghz_idle(); |     furi_hal_subghz_idle(); | ||||||
|     furi_hal_subghz_set_frequency_and_path(frequency); |     uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||||
|     hal_gpio_write(&gpio_cc1101_g0, true); |     hal_gpio_write(&gpio_cc1101_g0, true); | ||||||
|     furi_hal_subghz_tx(); |     furi_hal_subghz_tx(); | ||||||
|  |     return value; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_idle(void) { | void subghz_idle(void) { | ||||||
|     furi_hal_subghz_idle(); |     furi_hal_subghz_idle(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_end(void) { | void subghz_rx_end(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhzWorker* worker = context; | ||||||
|  | 
 | ||||||
|  |     if(subghz_worker_is_running(worker)) { | ||||||
|  |         subghz_worker_stop(worker); | ||||||
|  |         furi_hal_subghz_stop_async_rx(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_sleep(void) { | ||||||
|     furi_hal_subghz_sleep(); |     furi_hal_subghz_sleep(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void subghz_frequency_preset_to_str(void* context, string_t output) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubGhz* subghz = context; | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "Frequency: %d\n" | ||||||
|  |         "Preset: %d\n", | ||||||
|  |         (int)subghz->frequency, | ||||||
|  |         (int)subghz->preset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void subghz_transmitter_tx_start(void* context) { | void subghz_transmitter_tx_start(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     subghz->encoder = subghz_protocol_encoder_common_alloc(); |     subghz->encoder = subghz_protocol_encoder_common_alloc(); | ||||||
| @ -47,8 +77,17 @@ void subghz_transmitter_tx_start(void* context) { | |||||||
|     //get upload
 |     //get upload
 | ||||||
|     if(subghz->protocol_result->get_upload_protocol) { |     if(subghz->protocol_result->get_upload_protocol) { | ||||||
|         if(subghz->protocol_result->get_upload_protocol(subghz->protocol_result, subghz->encoder)) { |         if(subghz->protocol_result->get_upload_protocol(subghz->protocol_result, subghz->encoder)) { | ||||||
|             subghz_begin(FuriHalSubGhzPresetOokAsync); |             if(subghz->preset) { | ||||||
|             subghz_tx(433920000); |                 subghz_begin(subghz->preset); | ||||||
|  |             } else { | ||||||
|  |                 subghz_begin(FuriHalSubGhzPresetOok650Async); | ||||||
|  |             } | ||||||
|  |             if(subghz->frequency) { | ||||||
|  |                 subghz_tx(subghz->frequency); | ||||||
|  |             } else { | ||||||
|  |                 subghz_tx(433920000); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             //Start TX
 |             //Start TX
 | ||||||
|             furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, subghz->encoder); |             furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, subghz->encoder); | ||||||
|         } |         } | ||||||
| @ -59,7 +98,6 @@ void subghz_transmitter_tx_stop(void* context) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     //Stop TX
 |     //Stop TX
 | ||||||
|     furi_hal_subghz_stop_async_tx(); |     furi_hal_subghz_stop_async_tx(); | ||||||
|     subghz_end(); |  | ||||||
|     subghz_protocol_encoder_common_free(subghz->encoder); |     subghz_protocol_encoder_common_free(subghz->encoder); | ||||||
|     //if protocol dynamic then we save the last upload
 |     //if protocol dynamic then we save the last upload
 | ||||||
|     if(subghz->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) { |     if(subghz->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) { | ||||||
| @ -79,12 +117,35 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
|     string_init_set_str(path, file_path); |     string_init_set_str(path, file_path); | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(temp_str); |     string_init(temp_str); | ||||||
|  |     int res = 0; | ||||||
|  |     int data = 0; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { |         if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // Read and parse name protocol from 1st line
 | 
 | ||||||
|  |         // Read and parse frequency from 1st line
 | ||||||
|  |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         res = sscanf(string_get_cstr(temp_str), "Frequency: %d\n", &data); | ||||||
|  |         if(res != 1) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         subghz->frequency = (uint32_t)data; | ||||||
|  | 
 | ||||||
|  |         // Read and parse preset from 2st line
 | ||||||
|  |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         res = sscanf(string_get_cstr(temp_str), "Preset: %d\n", &data); | ||||||
|  |         if(res != 1) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         subghz->preset = (FuriHalSubGhzPreset)data; | ||||||
|  | 
 | ||||||
|  |         // Read and parse name protocol from 2st line
 | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -93,16 +154,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
|         subghz->protocol_result = |         subghz->protocol_result = | ||||||
|             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); |             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); | ||||||
|         if(subghz->protocol_result == NULL) { |         if(subghz->protocol_result == NULL) { | ||||||
|             file_worker_show_error(file_worker, "Cannot parse\nfile"); |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!subghz->protocol_result->to_load_protocol(file_worker, subghz->protocol_result)) { |         if(!subghz->protocol_result->to_load_protocol_from_file( | ||||||
|             file_worker_show_error(file_worker, "Cannot parse\nfile"); |                file_worker, subghz->protocol_result)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         loaded = true; |         loaded = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|  |     if(!loaded) { | ||||||
|  |         file_worker_show_error(file_worker, "Cannot parse\nfile"); | ||||||
|  |     } | ||||||
|     string_clear(temp_str); |     string_clear(temp_str); | ||||||
|     string_clear(path); |     string_clear(path); | ||||||
|     file_worker_close(file_worker); |     file_worker_close(file_worker); | ||||||
| @ -113,6 +176,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
| 
 | 
 | ||||||
| bool subghz_save_protocol_to_file(void* context, const char* dev_name) { | bool subghz_save_protocol_to_file(void* context, const char* dev_name) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|  |     furi_assert(subghz->protocol_result); | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     FileWorker* file_worker = file_worker_alloc(false); | ||||||
|     string_t dev_file_name; |     string_t dev_file_name; | ||||||
|     string_init(dev_file_name); |     string_init(dev_file_name); | ||||||
| @ -140,6 +204,11 @@ bool subghz_save_protocol_to_file(void* context, const char* dev_name) { | |||||||
|                file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { |                file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |         //Get string frequency preset protocol
 | ||||||
|  |         subghz_frequency_preset_to_str(subghz, temp_str); | ||||||
|  |         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|         //Get string save
 |         //Get string save
 | ||||||
|         subghz->protocol_result->to_save_string(subghz->protocol_result, temp_str); |         subghz->protocol_result->to_save_string(subghz->protocol_result, temp_str); | ||||||
|         // Prepare and write data to file
 |         // Prepare and write data to file
 | ||||||
| @ -157,7 +226,7 @@ bool subghz_save_protocol_to_file(void* context, const char* dev_name) { | |||||||
|     return saved; |     return saved; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_saved_protocol_select(SubGhz* subghz) { | bool subghz_load_protocol_from_file(SubGhz* subghz) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     FileWorker* file_worker = file_worker_alloc(false); | ||||||
| @ -165,6 +234,8 @@ bool subghz_saved_protocol_select(SubGhz* subghz) { | |||||||
|     string_init(protocol_file_name); |     string_init(protocol_file_name); | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(temp_str); |     string_init(temp_str); | ||||||
|  |     int sscanf_res = 0; | ||||||
|  |     int data = 0; | ||||||
| 
 | 
 | ||||||
|     // Input events and views are managed by file_select
 |     // Input events and views are managed by file_select
 | ||||||
|     bool res = file_worker_file_select( |     bool res = file_worker_file_select( | ||||||
| @ -197,7 +268,27 @@ bool subghz_saved_protocol_select(SubGhz* subghz) { | |||||||
|                file_worker, string_get_cstr(protocol_file_name), FSAM_READ, FSOM_OPEN_EXISTING)) { |                file_worker, string_get_cstr(protocol_file_name), FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // Read and parse name protocol from 1st line
 |         // Read and parse frequency from 1st line
 | ||||||
|  |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         sscanf_res = sscanf(string_get_cstr(temp_str), "Frequency: %d\n", &data); | ||||||
|  |         if(sscanf_res != 1) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         subghz->frequency = (uint32_t)data; | ||||||
|  | 
 | ||||||
|  |         // Read and parse preset from 2st line
 | ||||||
|  |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         sscanf_res = sscanf(string_get_cstr(temp_str), "Preset: %d\n", &data); | ||||||
|  |         if(sscanf_res != 1) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         subghz->preset = (FuriHalSubGhzPreset)data; | ||||||
|  | 
 | ||||||
|  |         // Read and parse name protocol from 3st line
 | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -206,16 +297,19 @@ bool subghz_saved_protocol_select(SubGhz* subghz) { | |||||||
|         subghz->protocol_result = |         subghz->protocol_result = | ||||||
|             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); |             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str)); | ||||||
|         if(subghz->protocol_result == NULL) { |         if(subghz->protocol_result == NULL) { | ||||||
|             file_worker_show_error(file_worker, "Cannot parse\nfile"); |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!subghz->protocol_result->to_load_protocol(file_worker, subghz->protocol_result)) { |         if(!subghz->protocol_result->to_load_protocol_from_file( | ||||||
|             file_worker_show_error(file_worker, "Cannot parse\nfile"); |                file_worker, subghz->protocol_result)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         res = true; |         res = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|  |     if(!res) { | ||||||
|  |         file_worker_show_error(file_worker, "Cannot parse\nfile"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     string_clear(temp_str); |     string_clear(temp_str); | ||||||
|     string_clear(protocol_file_name); |     string_clear(protocol_file_name); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,11 +1,10 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "subghz.h" | #include "subghz.h" | ||||||
| #include "views/subghz_analyze.h" |  | ||||||
| #include "views/subghz_receiver.h" | #include "views/subghz_receiver.h" | ||||||
| #include "views/subghz_transmitter.h" | #include "views/subghz_transmitter.h" | ||||||
| #include "views/subghz_static.h" |  | ||||||
| 
 | 
 | ||||||
|  | #include "views/subghz_test_static.h" | ||||||
| #include "views/subghz_test_carrier.h" | #include "views/subghz_test_carrier.h" | ||||||
| #include "views/subghz_test_packet.h" | #include "views/subghz_test_packet.h" | ||||||
| 
 | 
 | ||||||
| @ -25,12 +24,14 @@ | |||||||
| #include <lib/subghz/subghz_worker.h> | #include <lib/subghz/subghz_worker.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol.h> | #include <lib/subghz/protocols/subghz_protocol.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | #include <lib/subghz/protocols/subghz_protocol_common.h> | ||||||
|  | #include "subghz_history.h" | ||||||
| 
 | 
 | ||||||
| #define SUBGHZ_TEXT_STORE_SIZE 128 | #define SUBGHZ_TEXT_STORE_SIZE 128 | ||||||
| 
 | 
 | ||||||
| #define NOTIFICATION_STARTING_STATE 0u | #define NOTIFICATION_STARTING_STATE 0u | ||||||
| #define NOTIFICATION_IDLE_STATE 1u | #define NOTIFICATION_IDLE_STATE 1u | ||||||
| #define NOTIFICATION_TX_STATE 2u | #define NOTIFICATION_TX_STATE 2u | ||||||
|  | #define NOTIFICATION_RX_STATE 3u | ||||||
| 
 | 
 | ||||||
| extern const uint32_t subghz_frequencies[]; | extern const uint32_t subghz_frequencies[]; | ||||||
| extern const uint32_t subghz_frequencies_count; | extern const uint32_t subghz_frequencies_count; | ||||||
| @ -43,10 +44,11 @@ struct SubGhz { | |||||||
|     SubGhzWorker* worker; |     SubGhzWorker* worker; | ||||||
|     SubGhzProtocol* protocol; |     SubGhzProtocol* protocol; | ||||||
|     SubGhzProtocolCommon* protocol_result; |     SubGhzProtocolCommon* protocol_result; | ||||||
|     SubGhzProtocolEncoderCommon* encoder; |     SubGhzProtocolCommonEncoder* encoder; | ||||||
|  |     uint32_t frequency; | ||||||
|  |     FuriHalSubGhzPreset preset; | ||||||
| 
 | 
 | ||||||
|     SceneManager* scene_manager; |     SceneManager* scene_manager; | ||||||
| 
 |  | ||||||
|     ViewDispatcher* view_dispatcher; |     ViewDispatcher* view_dispatcher; | ||||||
| 
 | 
 | ||||||
|     Submenu* submenu; |     Submenu* submenu; | ||||||
| @ -56,11 +58,10 @@ struct SubGhz { | |||||||
|     char text_store[SUBGHZ_TEXT_STORE_SIZE + 1]; |     char text_store[SUBGHZ_TEXT_STORE_SIZE + 1]; | ||||||
|     uint8_t state_notifications; |     uint8_t state_notifications; | ||||||
| 
 | 
 | ||||||
|     SubghzAnalyze* subghz_analyze; |  | ||||||
|     SubghzReceiver* subghz_receiver; |     SubghzReceiver* subghz_receiver; | ||||||
|     SubghzTransmitter* subghz_transmitter; |     SubghzTransmitter* subghz_transmitter; | ||||||
|     SubghzStatic* subghz_static; |  | ||||||
| 
 | 
 | ||||||
|  |     SubghzTestStatic* subghz_test_static; | ||||||
|     SubghzTestCarrier* subghz_test_carrier; |     SubghzTestCarrier* subghz_test_carrier; | ||||||
|     SubghzTestPacket* subghz_test_packet; |     SubghzTestPacket* subghz_test_packet; | ||||||
| }; | }; | ||||||
| @ -68,7 +69,6 @@ struct SubGhz { | |||||||
| typedef enum { | typedef enum { | ||||||
|     SubGhzViewMenu, |     SubGhzViewMenu, | ||||||
| 
 | 
 | ||||||
|     SubGhzViewAnalyze, |  | ||||||
|     SubGhzViewDialogEx, |     SubGhzViewDialogEx, | ||||||
|     SubGhzViewReceiver, |     SubGhzViewReceiver, | ||||||
|     SubGhzViewPopup, |     SubGhzViewPopup, | ||||||
| @ -81,13 +81,14 @@ typedef enum { | |||||||
| } SubGhzView; | } SubGhzView; | ||||||
| 
 | 
 | ||||||
| void subghz_begin(FuriHalSubGhzPreset preset); | void subghz_begin(FuriHalSubGhzPreset preset); | ||||||
| void subghz_rx(uint32_t frequency); | uint32_t subghz_rx(void* context, uint32_t frequency); | ||||||
| void subghz_tx(uint32_t frequency); | uint32_t subghz_tx(uint32_t frequency); | ||||||
| void subghz_idle(void); | void subghz_idle(void); | ||||||
| void subghz_end(void); | void subghz_rx_end(void* context); | ||||||
|  | void subghz_sleep(void); | ||||||
| void subghz_transmitter_tx_start(void* context); | void subghz_transmitter_tx_start(void* context); | ||||||
| void subghz_transmitter_tx_stop(void* context); | void subghz_transmitter_tx_stop(void* context); | ||||||
| bool subghz_key_load(SubGhz* subghz, const char* file_path); | bool subghz_key_load(SubGhz* subghz, const char* file_path); | ||||||
| bool subghz_save_protocol_to_file(void* context, const char* dev_name); | bool subghz_save_protocol_to_file(void* context, const char* dev_name); | ||||||
| bool subghz_saved_protocol_select(SubGhz* subghz); | bool subghz_load_protocol_from_file(SubGhz* subghz); | ||||||
| uint32_t subghz_random_serial(void); | uint32_t subghz_random_serial(void); | ||||||
|  | |||||||
| @ -1,233 +0,0 @@ | |||||||
| #include "subghz_analyze.h" |  | ||||||
| #include "../subghz_i.h" |  | ||||||
| 
 |  | ||||||
| #include <math.h> |  | ||||||
| #include <furi.h> |  | ||||||
| #include <furi-hal.h> |  | ||||||
| #include <input/input.h> |  | ||||||
| #include <gui/elements.h> |  | ||||||
| #include <notification/notification-messages.h> |  | ||||||
| 
 |  | ||||||
| #include <lib/subghz/subghz_worker.h> |  | ||||||
| #include <lib/subghz/protocols/subghz_protocol.h> |  | ||||||
| 
 |  | ||||||
| #include <assets_icons.h> |  | ||||||
| 
 |  | ||||||
| struct SubghzAnalyze { |  | ||||||
|     View* view; |  | ||||||
|     SubGhzWorker* worker; |  | ||||||
|     SubGhzProtocol* protocol; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     uint8_t frequency; |  | ||||||
|     uint32_t real_frequency; |  | ||||||
|     uint32_t counter; |  | ||||||
|     string_t text; |  | ||||||
|     uint16_t scene; |  | ||||||
|     SubGhzProtocolCommon parser; |  | ||||||
| } SubghzAnalyzeModel; |  | ||||||
| 
 |  | ||||||
| static const char subghz_symbols[] = {'-', '\\', '|', '/'}; |  | ||||||
| 
 |  | ||||||
| void subghz_analyze_draw(Canvas* canvas, SubghzAnalyzeModel* model) { |  | ||||||
|     char buffer[64]; |  | ||||||
| 
 |  | ||||||
|     canvas_set_color(canvas, ColorBlack); |  | ||||||
|     canvas_set_font(canvas, FontPrimary); |  | ||||||
| 
 |  | ||||||
|     snprintf( |  | ||||||
|         buffer, |  | ||||||
|         sizeof(buffer), |  | ||||||
|         "Analyze: %03ld.%03ldMHz %c", |  | ||||||
|         model->real_frequency / 1000000 % 1000, |  | ||||||
|         model->real_frequency / 1000 % 1000, |  | ||||||
|         subghz_symbols[model->counter % 4]); |  | ||||||
|     canvas_draw_str(canvas, 0, 8, buffer); |  | ||||||
| 
 |  | ||||||
|     switch(model->scene) { |  | ||||||
|     case 1: |  | ||||||
|         canvas_draw_icon(canvas, 0, 10, &I_RFIDDolphinReceive_97x61); |  | ||||||
|         canvas_invert_color(canvas); |  | ||||||
|         canvas_draw_box(canvas, 80, 12, 20, 20); |  | ||||||
|         canvas_invert_color(canvas); |  | ||||||
|         canvas_draw_icon(canvas, 75, 18, &I_sub1_10px); |  | ||||||
|         elements_multiline_text_aligned( |  | ||||||
|             canvas, 90, 38, AlignCenter, AlignTop, "Detecting\r\nSubGhz"); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     default: |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
|         elements_multiline_text(canvas, 0, 20, string_get_cstr(model->text)); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool subghz_analyze_input(InputEvent* event, void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzAnalyze* subghz_analyze = context; |  | ||||||
| 
 |  | ||||||
|     if(event->type != InputTypeShort) return false; |  | ||||||
| 
 |  | ||||||
|     if(event->key == InputKeyBack) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_analyze->view, (SubghzAnalyzeModel * model) { |  | ||||||
|             bool model_updated = false; |  | ||||||
| 
 |  | ||||||
|             if(event->key == InputKeyLeft) { |  | ||||||
|                 if(model->frequency > 0) model->frequency--; |  | ||||||
|                 model_updated = true; |  | ||||||
|             } else if(event->key == InputKeyRight) { |  | ||||||
|                 if(model->frequency < subghz_frequencies_count - 1) model->frequency++; |  | ||||||
|                 model_updated = true; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if(model_updated) { |  | ||||||
|                 furi_hal_subghz_idle(); |  | ||||||
|                 model->real_frequency = |  | ||||||
|                     furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); |  | ||||||
|                 furi_hal_subghz_rx(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return model_updated; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_analyze_text_callback(string_t text, void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzAnalyze* subghz_analyze = context; |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_analyze->view, (SubghzAnalyzeModel * model) { |  | ||||||
|             model->counter++; |  | ||||||
|             string_set(model->text, text); |  | ||||||
|             model->scene = 0; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_analyze_protocol_callback(SubGhzProtocolCommon* parser, void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzAnalyze* subghz_analyze = context; |  | ||||||
|     char buffer[64]; |  | ||||||
|     snprintf( |  | ||||||
|         buffer, |  | ||||||
|         sizeof(buffer), |  | ||||||
|         "%s\r\n" |  | ||||||
|         "K:%lX%lX\r\n" |  | ||||||
|         "SN:%lX\r\n" |  | ||||||
|         "BTN:%X", |  | ||||||
|         parser->name, |  | ||||||
|         (uint32_t)(parser->code_found >> 32), |  | ||||||
|         (uint32_t)(parser->code_found & 0x00000000FFFFFFFF), |  | ||||||
|         parser->serial, |  | ||||||
|         parser->btn); |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_analyze->view, (SubghzAnalyzeModel * model) { |  | ||||||
|             model->counter++; |  | ||||||
|             model->parser = *parser; |  | ||||||
|             string_set(model->text, buffer); |  | ||||||
|             model->scene = 0; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_analyze_enter(void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzAnalyze* subghz_analyze = context; |  | ||||||
| 
 |  | ||||||
|     furi_hal_subghz_reset(); |  | ||||||
|     furi_hal_subghz_idle(); |  | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_analyze->view, (SubghzAnalyzeModel * model) { |  | ||||||
|             model->frequency = subghz_frequencies_433_92; |  | ||||||
|             model->real_frequency = |  | ||||||
|                 furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); |  | ||||||
|             model->scene = 1; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |  | ||||||
| 
 |  | ||||||
|     furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz_analyze->worker); |  | ||||||
| 
 |  | ||||||
|     subghz_worker_start(subghz_analyze->worker); |  | ||||||
| 
 |  | ||||||
|     furi_hal_subghz_flush_rx(); |  | ||||||
|     furi_hal_subghz_rx(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_analyze_exit(void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     SubghzAnalyze* subghz_analyze = context; |  | ||||||
| 
 |  | ||||||
|     subghz_worker_stop(subghz_analyze->worker); |  | ||||||
| 
 |  | ||||||
|     furi_hal_subghz_stop_async_rx(); |  | ||||||
|     furi_hal_subghz_sleep(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| SubghzAnalyze* subghz_analyze_alloc() { |  | ||||||
|     SubghzAnalyze* subghz_analyze = furi_alloc(sizeof(SubghzAnalyze)); |  | ||||||
| 
 |  | ||||||
|     // View allocation and configuration
 |  | ||||||
|     subghz_analyze->view = view_alloc(); |  | ||||||
|     view_allocate_model(subghz_analyze->view, ViewModelTypeLocking, sizeof(SubghzAnalyzeModel)); |  | ||||||
|     view_set_context(subghz_analyze->view, subghz_analyze); |  | ||||||
|     view_set_draw_callback(subghz_analyze->view, (ViewDrawCallback)subghz_analyze_draw); |  | ||||||
|     view_set_input_callback(subghz_analyze->view, subghz_analyze_input); |  | ||||||
|     view_set_enter_callback(subghz_analyze->view, subghz_analyze_enter); |  | ||||||
|     view_set_exit_callback(subghz_analyze->view, subghz_analyze_exit); |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_analyze->view, (SubghzAnalyzeModel * model) { |  | ||||||
|             string_init(model->text); |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     subghz_analyze->worker = subghz_worker_alloc(); |  | ||||||
|     subghz_analyze->protocol = subghz_protocol_alloc(); |  | ||||||
| 
 |  | ||||||
|     subghz_worker_set_overrun_callback( |  | ||||||
|         subghz_analyze->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset); |  | ||||||
|     subghz_worker_set_pair_callback( |  | ||||||
|         subghz_analyze->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse); |  | ||||||
|     subghz_worker_set_context(subghz_analyze->worker, subghz_analyze->protocol); |  | ||||||
| 
 |  | ||||||
|     subghz_protocol_load_keeloq_file( |  | ||||||
|         subghz_analyze->protocol, "/ext/assets/subghz/keeloq_mfcodes"); |  | ||||||
|     subghz_protocol_load_nice_flor_s_file( |  | ||||||
|         subghz_analyze->protocol, "/ext/assets/subghz/nice_floor_s_rx"); |  | ||||||
|     subghz_protocol_enable_dump_text( |  | ||||||
|         subghz_analyze->protocol, subghz_analyze_text_callback, subghz_analyze); |  | ||||||
| 
 |  | ||||||
|     return subghz_analyze; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void subghz_analyze_free(SubghzAnalyze* subghz_analyze) { |  | ||||||
|     furi_assert(subghz_analyze); |  | ||||||
| 
 |  | ||||||
|     subghz_protocol_free(subghz_analyze->protocol); |  | ||||||
|     subghz_worker_free(subghz_analyze->worker); |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         subghz_analyze->view, (SubghzAnalyzeModel * model) { |  | ||||||
|             string_clear(model->text); |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
|     view_free(subghz_analyze->view); |  | ||||||
|     free(subghz_analyze); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze) { |  | ||||||
|     furi_assert(subghz_analyze); |  | ||||||
|     return subghz_analyze->view; |  | ||||||
| } |  | ||||||
| @ -1,11 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <gui/view.h> |  | ||||||
| 
 |  | ||||||
| typedef struct SubghzAnalyze SubghzAnalyze; |  | ||||||
| 
 |  | ||||||
| SubghzAnalyze* subghz_analyze_alloc(); |  | ||||||
| 
 |  | ||||||
| void subghz_analyze_free(SubghzAnalyze* subghz_analyze); |  | ||||||
| 
 |  | ||||||
| View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze); |  | ||||||
| @ -1,25 +1,74 @@ | |||||||
| #include "subghz_receiver.h" | #include "subghz_receiver.h" | ||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| 
 |  | ||||||
| #include <math.h> | #include <math.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
|  | #include <lib/subghz/protocols/subghz_protocol_princeton.h> | ||||||
| 
 | 
 | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
|  | #define FRAME_HEIGHT 12 | ||||||
|  | #define MAX_LEN_PX 100 | ||||||
|  | #define MENU_ITEMS 4 | ||||||
|  | 
 | ||||||
|  | #define COUNT_FREQUNCY_HOPPER 3 | ||||||
|  | const uint32_t subghz_frequencies_hopper[] = { | ||||||
|  |     /* 300 - 348 */ | ||||||
|  |     315000000, | ||||||
|  |     /* 387 - 464 */ | ||||||
|  |     433920000, /* LPD433 mid */ | ||||||
|  |     /* 779 - 928 */ | ||||||
|  |     868350000, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     ReceiverSceneStart, | ||||||
|  |     ReceiverSceneMain, | ||||||
|  |     ReceiverSceneConfig, | ||||||
|  |     ReceiverSceneInfo, | ||||||
|  | } SubghzReceiverScene; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     SubGhzHopperStateOFF, | ||||||
|  |     SubGhzHopperStatePause, | ||||||
|  |     SubGhzHopperStateRunnig, | ||||||
|  |     SubGhzHopperStateRSSITimeOut, | ||||||
|  | } SubGhzHopperState; | ||||||
|  | 
 | ||||||
|  | static const Icon* ReceiverItemIcons[] = { | ||||||
|  |     [TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8, | ||||||
|  |     [TYPE_PROTOCOL_STATIC] = &I_Unlock_7x8, | ||||||
|  |     [TYPE_PROTOCOL_DYNAMIC] = &I_Lock_7x8, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct SubghzReceiver { | struct SubghzReceiver { | ||||||
|     View* view; |     View* view; | ||||||
|     SubghzReceiverCallback callback; |     SubghzReceiverCallback callback; | ||||||
|     void* context; |     void* context; | ||||||
|  |     SubGhzWorker* worker; | ||||||
|  |     SubGhzProtocol* protocol; | ||||||
|  |     osTimerId timer; | ||||||
|  |     SubGhzHopperState hopper_state; | ||||||
|  |     uint8_t hopper_timeout; | ||||||
|  |     uint32_t event_key_sequence; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     string_t text; |     string_t text; | ||||||
|     uint16_t scene; |     uint16_t scene; | ||||||
|     SubGhzProtocolCommon* protocol; |     SubGhzProtocolCommon* protocol_result; | ||||||
|  |     SubGhzHistory* history; | ||||||
|  |     uint8_t frequency; | ||||||
|  |     uint8_t temp_frequency; | ||||||
|  |     uint32_t real_frequency; | ||||||
|  | 
 | ||||||
|  |     uint16_t idx; | ||||||
|  |     uint16_t list_offset; | ||||||
|  |     uint16_t history_item; | ||||||
|  |     bool menu; | ||||||
| } SubghzReceiverModel; | } SubghzReceiverModel; | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_callback( | void subghz_receiver_set_callback( | ||||||
| @ -32,48 +81,393 @@ void subghz_receiver_set_callback( | |||||||
|     subghz_receiver->context = context; |     subghz_receiver->context = context; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_protocol(SubghzReceiver* subghz_receiver, SubGhzProtocolCommon* protocol) { | void subghz_receiver_set_protocol( | ||||||
|  |     SubghzReceiver* subghz_receiver, | ||||||
|  |     SubGhzProtocolCommon* protocol_result, | ||||||
|  |     SubGhzProtocol* protocol) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             model->protocol = protocol; |             model->protocol_result = protocol_result; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  |     subghz_receiver->protocol = protocol; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|  |     SubGhzProtocolCommon* result = NULL; | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             result = model->protocol_result; | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|  |     subghz_receiver->worker = worker; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             size_t history_item = model->history_item; | ||||||
|  |             uint16_t bounds = history_item > 3 ? 2 : history_item; | ||||||
|  | 
 | ||||||
|  |             if(history_item > 3 && model->idx >= history_item - 1) { | ||||||
|  |                 model->list_offset = model->idx - 3; | ||||||
|  |             } else if(model->list_offset < model->idx - bounds) { | ||||||
|  |                 model->list_offset = CLAMP(model->list_offset + 1, history_item - bounds, 0); | ||||||
|  |             } else if(model->list_offset > model->idx - bounds) { | ||||||
|  |                 model->list_offset = CLAMP(model->idx - 1, history_item - bounds, 0); | ||||||
|  |             } | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { | ||||||
|  |     canvas_set_color(canvas, ColorBlack); | ||||||
|  |     canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); | ||||||
|  | 
 | ||||||
|  |     canvas_set_color(canvas, ColorWhite); | ||||||
|  |     canvas_draw_dot(canvas, 0, 0 + idx * FRAME_HEIGHT); | ||||||
|  |     canvas_draw_dot(canvas, 1, 0 + idx * FRAME_HEIGHT); | ||||||
|  |     canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 1); | ||||||
|  | 
 | ||||||
|  |     canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 11); | ||||||
|  |     canvas_draw_dot(canvas, scrollbar ? 121 : 126, 0 + idx * FRAME_HEIGHT); | ||||||
|  |     canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) { | ||||||
|  |     bool scrollbar = model->history_item > 4; | ||||||
|  |     string_t str_buff; | ||||||
|  |     char buffer[64]; | ||||||
|  |     uint32_t frequency; | ||||||
|  |     string_init(str_buff); | ||||||
|  | 
 | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontSecondary); |  | ||||||
|     elements_multiline_text(canvas, 0, 10, string_get_cstr(model->text)); |  | ||||||
| 
 | 
 | ||||||
|     elements_button_left(canvas, "Back"); |     switch(model->scene) { | ||||||
|     if(model->protocol && model->protocol->to_save_string && |     case ReceiverSceneMain: | ||||||
|        strcmp(model->protocol->name, "KeeLoq")) { |         for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) { | ||||||
|         elements_button_right(canvas, "Save"); |             size_t idx = CLAMP(i + model->list_offset, model->history_item, 0); | ||||||
|  |             subghz_history_get_text_item_menu(model->history, str_buff, idx); | ||||||
|  |             elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); | ||||||
|  |             if(model->idx == idx) { | ||||||
|  |                 subghz_receiver_draw_frame(canvas, i, scrollbar); | ||||||
|  |             } else { | ||||||
|  |                 canvas_set_color(canvas, ColorBlack); | ||||||
|  |             } | ||||||
|  |             canvas_draw_icon( | ||||||
|  |                 canvas, | ||||||
|  |                 1, | ||||||
|  |                 2 + i * FRAME_HEIGHT, | ||||||
|  |                 ReceiverItemIcons[subghz_history_get_type_protocol(model->history, idx)]); | ||||||
|  |             canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); | ||||||
|  |             string_clean(str_buff); | ||||||
|  |         } | ||||||
|  |         if(scrollbar) { | ||||||
|  |             elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item); | ||||||
|  |         } | ||||||
|  |         canvas_set_color(canvas, ColorBlack); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  | 
 | ||||||
|  |         elements_button_left(canvas, "Config"); | ||||||
|  |         canvas_draw_line(canvas, 46, 51, 125, 51); | ||||||
|  |         if(subghz_history_get_text_space_left(model->history, str_buff)) { | ||||||
|  |             canvas_draw_str(canvas, 54, 62, string_get_cstr(str_buff)); | ||||||
|  |         } else { | ||||||
|  |             if((model->real_frequency / 1000 % 10) > 4) { | ||||||
|  |                 frequency = model->real_frequency + 10000; | ||||||
|  |             } else { | ||||||
|  |                 frequency = model->real_frequency; | ||||||
|  |             } | ||||||
|  |             snprintf( | ||||||
|  |                 buffer, | ||||||
|  |                 sizeof(buffer), | ||||||
|  |                 "%03ld.%02ld", | ||||||
|  |                 frequency / 1000000 % 1000, | ||||||
|  |                 frequency / 10000 % 100); | ||||||
|  |             canvas_draw_str(canvas, 44, 62, buffer); | ||||||
|  |             canvas_draw_str(canvas, 79, 62, "AM"); | ||||||
|  |             canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff)); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case ReceiverSceneStart: | ||||||
|  |         canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); | ||||||
|  |         canvas_set_font(canvas, FontPrimary); | ||||||
|  |         canvas_draw_str(canvas, 63, 46, "Scanning..."); | ||||||
|  |         canvas_set_color(canvas, ColorBlack); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         elements_button_left(canvas, "Config"); | ||||||
|  |         if((model->real_frequency / 1000 % 10) > 4) { | ||||||
|  |             frequency = model->real_frequency + 10000; | ||||||
|  |         } else { | ||||||
|  |             frequency = model->real_frequency; | ||||||
|  |         } | ||||||
|  |         snprintf( | ||||||
|  |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "%03ld.%02ld", | ||||||
|  |             frequency / 1000000 % 1000, | ||||||
|  |             frequency / 10000 % 100); | ||||||
|  |         canvas_draw_str(canvas, 44, 62, buffer); | ||||||
|  |         canvas_draw_str(canvas, 79, 62, "AM"); | ||||||
|  |         subghz_history_get_text_space_left(model->history, str_buff); | ||||||
|  |         canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff)); | ||||||
|  |         canvas_draw_line(canvas, 46, 51, 125, 51); | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case ReceiverSceneConfig: | ||||||
|  |         if(model->frequency < subghz_frequencies_count) { | ||||||
|  |             snprintf( | ||||||
|  |                 buffer, | ||||||
|  |                 sizeof(buffer), | ||||||
|  |                 "Frequency:  < %03ld.%03ldMHz >", | ||||||
|  |                 model->real_frequency / 1000000 % 1000, | ||||||
|  |                 model->real_frequency / 1000 % 1000); | ||||||
|  |             canvas_draw_str(canvas, 0, 8, buffer); | ||||||
|  |             canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <OFF>"); | ||||||
|  |         } else { | ||||||
|  |             canvas_draw_str(canvas, 0, 8, "Frequency: < --- >"); | ||||||
|  |             canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <ON>"); | ||||||
|  |         } | ||||||
|  |         canvas_draw_str(canvas, 0, 28, "Modulation: <AM>"); | ||||||
|  | 
 | ||||||
|  |         elements_button_center(canvas, "Save"); | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case ReceiverSceneInfo: | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text)); | ||||||
|  |         snprintf( | ||||||
|  |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "%03ld.%03ld", | ||||||
|  |             subghz_history_get_frequency(model->history, model->idx) / 1000000 % 1000, | ||||||
|  |             subghz_history_get_frequency(model->history, model->idx) / 1000 % 1000); | ||||||
|  |         canvas_draw_str(canvas, 90, 8, buffer); | ||||||
|  |         if(model->protocol_result && model->protocol_result->to_save_string && | ||||||
|  |            strcmp(model->protocol_result->name, "KeeLoq")) { | ||||||
|  |             elements_button_right(canvas, "Save"); | ||||||
|  |             elements_button_center(canvas, "Send"); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     default: | ||||||
|  | 
 | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(str_buff); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_receiver_history_full(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzReceiver* subghz_receiver = context; | ||||||
|  |     subghz_receiver->callback(SubghzReceverEventSendHistoryFull, subghz_receiver->context); | ||||||
|  |     subghz_receiver->hopper_state = SubGhzHopperStateOFF; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_receiver_input(InputEvent* event, void* context) { | bool subghz_receiver_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     uint8_t scene = 0; | ||||||
|     SubghzReceiver* subghz_receiver = context; |     SubghzReceiver* subghz_receiver = context; | ||||||
| 
 |  | ||||||
|     if(event->type != InputTypeShort) return false; |  | ||||||
| 
 |  | ||||||
|     bool can_be_saved = false; |  | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             can_be_saved = |             scene = model->scene; | ||||||
|                 (model->protocol && model->protocol->to_save_string && |  | ||||||
|                  strcmp(model->protocol->name, "KeeLoq")); |  | ||||||
|             return false; |             return false; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     bool can_be_saved = false; | ||||||
|         return false; | 
 | ||||||
|     } else if(event->key == InputKeyLeft) { |     switch(scene) { | ||||||
|         subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context); |     case ReceiverSceneMain: | ||||||
|     } else if(can_be_saved && event->key == InputKeyRight) { |         if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
|         subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context); |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     model->idx = 0; | ||||||
|  |                     model->list_offset = 0; | ||||||
|  |                     model->history_item = 0; | ||||||
|  |                     subghz_history_clean(model->history); | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |             return false; | ||||||
|  |         } else if( | ||||||
|  |             event->key == InputKeyUp && | ||||||
|  |             (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     if(model->idx != 0) model->idx--; | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |         } else if( | ||||||
|  |             event->key == InputKeyDown && | ||||||
|  |             (event->type == InputTypeShort || event->type == InputTypeRepeat)) { | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++; | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |         } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { | ||||||
|  |             subghz_receiver->hopper_state = SubGhzHopperStatePause; | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     model->scene = ReceiverSceneConfig; | ||||||
|  |                     model->temp_frequency = model->frequency; | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |             subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); | ||||||
|  |         } else if(event->key == InputKeyOk && event->type == InputTypeShort) { | ||||||
|  |             subghz_receiver->event_key_sequence = event->sequence; | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     string_clean(model->text); | ||||||
|  |                     model->protocol_result = subghz_protocol_get_by_name( | ||||||
|  |                         subghz_receiver->protocol, | ||||||
|  |                         subghz_history_get_name(model->history, model->idx)); | ||||||
|  |                     if(model->protocol_result->to_load_protocol != NULL) { | ||||||
|  |                         model->protocol_result->to_load_protocol( | ||||||
|  |                             model->protocol_result, | ||||||
|  |                             subghz_history_get_raw_data(model->history, model->idx)); | ||||||
|  |                         model->protocol_result->to_string(model->protocol_result, model->text); | ||||||
|  |                         model->scene = ReceiverSceneInfo; | ||||||
|  |                     } | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case ReceiverSceneInfo: | ||||||
|  |         with_view_model( | ||||||
|  |             subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                 can_be_saved = | ||||||
|  |                     (model->protocol_result && model->protocol_result->to_save_string && | ||||||
|  |                      strcmp(model->protocol_result->name, "KeeLoq")); | ||||||
|  |                 return false; | ||||||
|  |             }); | ||||||
|  |         if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     subghz_rx_end(subghz_receiver->worker); | ||||||
|  |                     model->real_frequency = | ||||||
|  |                         subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]); | ||||||
|  |                     subghz_receiver->hopper_state = SubGhzHopperStateRunnig; | ||||||
|  |                     model->scene = ReceiverSceneMain; | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |             subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); | ||||||
|  |         } else if(can_be_saved && event->key == InputKeyRight) { | ||||||
|  |             subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context); | ||||||
|  |             return false; | ||||||
|  |         } else if( | ||||||
|  |             can_be_saved && event->key == InputKeyOk && event->type == InputTypePress && | ||||||
|  |             subghz_receiver->event_key_sequence != event->sequence) { | ||||||
|  |             subghz_receiver->hopper_state = SubGhzHopperStatePause; | ||||||
|  |             subghz_rx_end(subghz_receiver->worker); | ||||||
|  |             subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context); | ||||||
|  |             return true; | ||||||
|  |         } else if( | ||||||
|  |             can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease && | ||||||
|  |             subghz_receiver->event_key_sequence != event->sequence) { | ||||||
|  |             subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case ReceiverSceneConfig: | ||||||
|  |         if(event->type != InputTypeShort) return false; | ||||||
|  |         if(event->key == InputKeyBack) { | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     model->frequency = model->temp_frequency; | ||||||
|  |                     model->real_frequency = subghz_frequencies[model->frequency]; | ||||||
|  |                     subghz_receiver->hopper_state = SubGhzHopperStateRunnig; | ||||||
|  |                     if(subghz_history_get_item(model->history) == 0) { | ||||||
|  |                         model->scene = ReceiverSceneStart; | ||||||
|  |                     } else { | ||||||
|  |                         model->scene = ReceiverSceneMain; | ||||||
|  |                     } | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |             subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); | ||||||
|  |         } else if(event->key == InputKeyOk) { | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     if(model->frequency < subghz_frequencies_count) { | ||||||
|  |                         subghz_rx_end(subghz_receiver->worker); | ||||||
|  |                         model->real_frequency = subghz_rx( | ||||||
|  |                             subghz_receiver->worker, subghz_frequencies[model->frequency]); | ||||||
|  |                         subghz_receiver->hopper_state = SubGhzHopperStateOFF; | ||||||
|  |                     } else { | ||||||
|  |                         osTimerStart(subghz_receiver->timer, 1024 / 10); | ||||||
|  |                         subghz_receiver->hopper_state = SubGhzHopperStateRunnig; | ||||||
|  |                     } | ||||||
|  |                     if(subghz_history_get_item(model->history) == 0) { | ||||||
|  |                         model->scene = ReceiverSceneStart; | ||||||
|  |                     } else { | ||||||
|  |                         model->scene = ReceiverSceneMain; | ||||||
|  |                     } | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |             subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context); | ||||||
|  |         } else { | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     bool model_updated = false; | ||||||
|  | 
 | ||||||
|  |                     if(event->key == InputKeyLeft) { | ||||||
|  |                         if(model->frequency > 0) model->frequency--; | ||||||
|  |                         model_updated = true; | ||||||
|  |                     } else if(event->key == InputKeyRight) { | ||||||
|  |                         if(model->frequency < subghz_frequencies_count) model->frequency++; | ||||||
|  |                         model_updated = true; | ||||||
|  |                     } | ||||||
|  |                     if(model_updated) { | ||||||
|  |                         model->real_frequency = subghz_frequencies[model->frequency]; | ||||||
|  |                     } | ||||||
|  |                     return model_updated; | ||||||
|  |                 }); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     case ReceiverSceneStart: | ||||||
|  |         if(event->type != InputTypeShort) return false; | ||||||
|  |         if(event->key == InputKeyBack) { | ||||||
|  |             return false; | ||||||
|  |         } else if(event->key == InputKeyLeft) { | ||||||
|  |             subghz_receiver->hopper_state = SubGhzHopperStatePause; | ||||||
|  |             with_view_model( | ||||||
|  |                 subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                     model->temp_frequency = model->frequency; | ||||||
|  |                     model->scene = ReceiverSceneConfig; | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  |             subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  | 
 | ||||||
|  |     default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     subghz_receiver_update_offset(subghz_receiver); | ||||||
|  |     if(scene != ReceiverSceneInfo) { | ||||||
|  |         with_view_model( | ||||||
|  |             subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |                 if(subghz_history_get_text_space_left(model->history, NULL)) { | ||||||
|  |                     subghz_receiver_history_full(subghz_receiver); | ||||||
|  |                 } | ||||||
|  |                 return false; | ||||||
|  |             }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| @ -86,7 +480,88 @@ void subghz_receiver_text_callback(string_t text, void* context) { | |||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             string_set(model->text, text); |             string_set(model->text, text); | ||||||
|             model->scene = 0; |             model->scene = ReceiverSceneMain; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzReceiver* subghz_receiver = context; | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             model->protocol_result = parser; | ||||||
|  |             subghz_history_set_frequency_preset( | ||||||
|  |                 model->history, | ||||||
|  |                 model->history_item, | ||||||
|  |                 model->real_frequency, | ||||||
|  |                 FuriHalSubGhzPresetOok650Async); | ||||||
|  |             subghz_history_add_to_history(model->history, parser); | ||||||
|  | 
 | ||||||
|  |             model->history_item = subghz_history_get_item(model->history); | ||||||
|  |             model->scene = ReceiverSceneMain; | ||||||
|  |             if(subghz_history_get_text_space_left(model->history, NULL)) { | ||||||
|  |                 subghz_receiver_history_full(subghz_receiver); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  |     subghz_protocol_reset(subghz_receiver->protocol); | ||||||
|  |     subghz_receiver_update_offset(subghz_receiver); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_receiver_timer_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     SubghzReceiver* subghz_receiver = context; | ||||||
|  | 
 | ||||||
|  |     switch(subghz_receiver->hopper_state) { | ||||||
|  |     case SubGhzHopperStatePause: | ||||||
|  |         return; | ||||||
|  |         break; | ||||||
|  |     case SubGhzHopperStateOFF: | ||||||
|  |         osTimerStop(subghz_receiver->timer); | ||||||
|  |         return; | ||||||
|  |         break; | ||||||
|  |     case SubGhzHopperStateRSSITimeOut: | ||||||
|  |         if(subghz_receiver->hopper_timeout != 0) { | ||||||
|  |             subghz_receiver->hopper_timeout--; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     float rssi = -127.0f; | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) { | ||||||
|  |                 // See RSSI Calculation timings in CC1101 17.3 RSSI
 | ||||||
|  |                 rssi = furi_hal_subghz_get_rssi(); | ||||||
|  | 
 | ||||||
|  |                 // Stay if RSSI is high enough
 | ||||||
|  |                 if(rssi > -90.0f) { | ||||||
|  |                     subghz_receiver->hopper_timeout = 10; | ||||||
|  |                     subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut; | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 subghz_receiver->hopper_state = SubGhzHopperStateRunnig; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Select next frequency
 | ||||||
|  |             if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) { | ||||||
|  |                 model->frequency++; | ||||||
|  |             } else { | ||||||
|  |                 model->frequency = 0; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Restart radio
 | ||||||
|  |             furi_hal_subghz_idle(); | ||||||
|  |             subghz_protocol_reset(subghz_receiver->protocol); | ||||||
|  |             model->real_frequency = furi_hal_subghz_set_frequency_and_path( | ||||||
|  |                 subghz_frequencies_hopper[model->frequency]); | ||||||
|  |             furi_hal_subghz_rx(); | ||||||
|  | 
 | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| @ -94,21 +569,37 @@ void subghz_receiver_text_callback(string_t text, void* context) { | |||||||
| void subghz_receiver_enter(void* context) { | void subghz_receiver_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzReceiver* subghz_receiver = context; |     SubghzReceiver* subghz_receiver = context; | ||||||
|  |     //Start CC1101 Rx
 | ||||||
|  |     subghz_begin(FuriHalSubGhzPresetOok650Async); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             model->protocol->to_string(model->protocol, model->text); |             subghz_rx_end(subghz_receiver->worker); | ||||||
|  |             model->frequency = subghz_frequencies_433_92; | ||||||
|  |             model->real_frequency = | ||||||
|  |                 subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]); | ||||||
|  |             if(subghz_history_get_item(model->history) == 0) { | ||||||
|  |                 model->scene = ReceiverSceneStart; | ||||||
|  |             } else { | ||||||
|  |                 model->scene = ReceiverSceneMain; | ||||||
|  |             } | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  |     subghz_protocol_enable_dump( | ||||||
|  |         subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_exit(void* context) { | void subghz_receiver_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzReceiver* subghz_receiver = context; |     SubghzReceiver* subghz_receiver = context; | ||||||
|  |     osTimerStop(subghz_receiver->timer); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             string_clean(model->text); |             string_clean(model->text); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  |     // Stop CC1101 Rx
 | ||||||
|  |     subghz_rx_end(subghz_receiver->worker); | ||||||
|  |     subghz_sleep(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzReceiver* subghz_receiver_alloc() { | SubghzReceiver* subghz_receiver_alloc() { | ||||||
| @ -126,8 +617,13 @@ SubghzReceiver* subghz_receiver_alloc() { | |||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             string_init(model->text); |             string_init(model->text); | ||||||
|  |             model->history = subghz_history_alloc(); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |     subghz_receiver->timer = | ||||||
|  |         osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL); | ||||||
|  |     subghz_receiver->hopper_state = SubGhzHopperStateOFF; | ||||||
|     return subghz_receiver; |     return subghz_receiver; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -137,8 +633,10 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) { | |||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_receiver->view, (SubghzReceiverModel * model) { |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|             string_clear(model->text); |             string_clear(model->text); | ||||||
|             return true; |             subghz_history_free(model->history); | ||||||
|  |             return false; | ||||||
|         }); |         }); | ||||||
|  |     osTimerDelete(subghz_receiver->timer); | ||||||
|     view_free(subghz_receiver->view); |     view_free(subghz_receiver->view); | ||||||
|     free(subghz_receiver); |     free(subghz_receiver); | ||||||
| } | } | ||||||
| @ -147,3 +645,44 @@ View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) { | |||||||
|     furi_assert(subghz_receiver); |     furi_assert(subghz_receiver); | ||||||
|     return subghz_receiver->view; |     return subghz_receiver->view; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|  |     uint32_t frequency; | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             frequency = subghz_history_get_frequency(model->history, model->idx); | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  |     return frequency; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|  |     FuriHalSubGhzPreset preset; | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             preset = subghz_history_get_preset(model->history, model->idx); | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  |     return preset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output) { | ||||||
|  |     furi_assert(subghz_receiver); | ||||||
|  |     uint32_t frequency; | ||||||
|  |     uint32_t preset; | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_receiver->view, (SubghzReceiverModel * model) { | ||||||
|  |             frequency = subghz_history_get_frequency(model->history, model->idx); | ||||||
|  |             preset = (uint32_t)subghz_history_get_preset(model->history, model->idx); | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     string_cat_printf( | ||||||
|  |         output, | ||||||
|  |         "Frequency: %d\n" | ||||||
|  |         "Preset: %d\n", | ||||||
|  |         (int)frequency, | ||||||
|  |         (int)preset); | ||||||
|  | } | ||||||
|  | |||||||
| @ -2,10 +2,20 @@ | |||||||
| 
 | 
 | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_common.h> | #include <lib/subghz/protocols/subghz_protocol_common.h> | ||||||
|  | #include <lib/subghz/protocols/subghz_protocol.h> | ||||||
|  | #include <lib/subghz/subghz_worker.h> | ||||||
|  | #include "../subghz_history.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  |     SubghzReceverEventOK, | ||||||
|  |     SubghzReceverEventConfig, | ||||||
|  |     SubghzReceverEventMain, | ||||||
|     SubghzReceverEventSave, |     SubghzReceverEventSave, | ||||||
|     SubghzReceverEventBack, |     SubghzReceverEventBack, | ||||||
|  |     SubghzReceverEventMore, | ||||||
|  |     SubghzReceverEventSendStart, | ||||||
|  |     SubghzReceverEventSendStop, | ||||||
|  |     SubghzReceverEventSendHistoryFull, | ||||||
| } SubghzReceverEvent; | } SubghzReceverEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzReceiver SubghzReceiver; | typedef struct SubghzReceiver SubghzReceiver; | ||||||
| @ -23,4 +33,17 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver); | |||||||
| 
 | 
 | ||||||
| View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver); | View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver); | ||||||
| 
 | 
 | ||||||
| void subghz_receiver_set_protocol(SubghzReceiver* subghz_receiver, SubGhzProtocolCommon* protocol); | void subghz_receiver_set_protocol( | ||||||
|  |     SubghzReceiver* subghz_receiver, | ||||||
|  |     SubGhzProtocolCommon* protocol_result, | ||||||
|  |     SubGhzProtocol* protocol); | ||||||
|  | 
 | ||||||
|  | SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver); | ||||||
|  | 
 | ||||||
|  | void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker); | ||||||
|  | 
 | ||||||
|  | uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver); | ||||||
|  | 
 | ||||||
|  | FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver); | ||||||
|  | 
 | ||||||
|  | void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output); | ||||||
|  | |||||||
| @ -1,11 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <gui/view.h> |  | ||||||
| 
 |  | ||||||
| typedef struct SubghzStatic SubghzStatic; |  | ||||||
| 
 |  | ||||||
| SubghzStatic* subghz_static_alloc(); |  | ||||||
| 
 |  | ||||||
| void subghz_static_free(SubghzStatic* subghz_static); |  | ||||||
| 
 |  | ||||||
| View* subghz_static_get_view(SubghzStatic* subghz_static); |  | ||||||
| @ -71,41 +71,37 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestCarrier* subghz_test_carrier = context; |     SubghzTestCarrier* subghz_test_carrier = context; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(event->key == InputKeyBack || event->type != InputTypeShort) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_test_carrier->view, (SubghzTestCarrierModel * model) { |         subghz_test_carrier->view, (SubghzTestCarrierModel * model) { | ||||||
|             osTimerStop(subghz_test_carrier->timer); |  | ||||||
|             furi_hal_subghz_idle(); |             furi_hal_subghz_idle(); | ||||||
| 
 | 
 | ||||||
|             if(event->type == InputTypeShort) { |             if(event->key == InputKeyLeft) { | ||||||
|                 if(event->key == InputKeyLeft) { |                 if(model->frequency > 0) model->frequency--; | ||||||
|                     if(model->frequency > 0) model->frequency--; |             } else if(event->key == InputKeyRight) { | ||||||
|                 } else if(event->key == InputKeyRight) { |                 if(model->frequency < subghz_frequencies_count - 1) model->frequency++; | ||||||
|                     if(model->frequency < subghz_frequencies_count - 1) model->frequency++; |             } else if(event->key == InputKeyDown) { | ||||||
|                 } else if(event->key == InputKeyDown) { |                 if(model->path > 0) model->path--; | ||||||
|                     if(model->path > 0) model->path--; |             } else if(event->key == InputKeyUp) { | ||||||
|                 } else if(event->key == InputKeyUp) { |                 if(model->path < FuriHalSubGhzPath868) model->path++; | ||||||
|                     if(model->path < FuriHalSubGhzPath868) model->path++; |             } else if(event->key == InputKeyOk) { | ||||||
|                 } else if(event->key == InputKeyOk) { |                 if(model->status == SubghzTestCarrierModelStatusTx) { | ||||||
|                     if(model->status == SubghzTestCarrierModelStatusTx) { |                     model->status = SubghzTestCarrierModelStatusRx; | ||||||
|                         model->status = SubghzTestCarrierModelStatusRx; |                 } else { | ||||||
|                     } else { |                     model->status = SubghzTestCarrierModelStatusTx; | ||||||
|                         model->status = SubghzTestCarrierModelStatusTx; |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
| 
 |  | ||||||
|                 model->real_frequency = |  | ||||||
|                     furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); |  | ||||||
|                 furi_hal_subghz_set_path(model->path); |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             model->real_frequency = | ||||||
|  |                 furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); | ||||||
|  |             furi_hal_subghz_set_path(model->path); | ||||||
|  | 
 | ||||||
|             if(model->status == SubghzTestCarrierModelStatusRx) { |             if(model->status == SubghzTestCarrierModelStatusRx) { | ||||||
|                 hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |                 hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
|                 furi_hal_subghz_rx(); |                 furi_hal_subghz_rx(); | ||||||
|                 osTimerStart(subghz_test_carrier->timer, 1024 / 4); |  | ||||||
|             } else { |             } else { | ||||||
|                 hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |                 hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||||
|                 hal_gpio_write(&gpio_cc1101_g0, true); |                 hal_gpio_write(&gpio_cc1101_g0, true); | ||||||
| @ -123,7 +119,7 @@ void subghz_test_carrier_enter(void* context) { | |||||||
|     SubghzTestCarrier* subghz_test_carrier = context; |     SubghzTestCarrier* subghz_test_carrier = context; | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
| 
 | 
 | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
| 
 | 
 | ||||||
| @ -159,8 +155,11 @@ void subghz_test_carrier_rssi_timer_callback(void* context) { | |||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_test_carrier->view, (SubghzTestCarrierModel * model) { |         subghz_test_carrier->view, (SubghzTestCarrierModel * model) { | ||||||
|             model->rssi = furi_hal_subghz_get_rssi(); |             if(model->status == SubghzTestCarrierModelStatusRx) { | ||||||
|             return true; |                 model->rssi = furi_hal_subghz_get_rssi(); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -170,7 +169,7 @@ SubghzTestCarrier* subghz_test_carrier_alloc() { | |||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     subghz_test_carrier->view = view_alloc(); |     subghz_test_carrier->view = view_alloc(); | ||||||
|     view_allocate_model( |     view_allocate_model( | ||||||
|         subghz_test_carrier->view, ViewModelTypeLockFree, sizeof(SubghzTestCarrierModel)); |         subghz_test_carrier->view, ViewModelTypeLocking, sizeof(SubghzTestCarrierModel)); | ||||||
|     view_set_context(subghz_test_carrier->view, subghz_test_carrier); |     view_set_context(subghz_test_carrier->view, subghz_test_carrier); | ||||||
|     view_set_draw_callback(subghz_test_carrier->view, (ViewDrawCallback)subghz_test_carrier_draw); |     view_set_draw_callback(subghz_test_carrier->view, (ViewDrawCallback)subghz_test_carrier_draw); | ||||||
|     view_set_input_callback(subghz_test_carrier->view, subghz_test_carrier_input); |     view_set_input_callback(subghz_test_carrier->view, subghz_test_carrier_input); | ||||||
|  | |||||||
| @ -116,7 +116,7 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTestPacket* instance = context; |     SubghzTestPacket* instance = context; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(event->key == InputKeyBack || event->type != InputTypeShort) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -128,28 +128,26 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { | |||||||
|                 furi_hal_subghz_stop_async_tx(); |                 furi_hal_subghz_stop_async_tx(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(event->type == InputTypeShort) { |             if(event->key == InputKeyLeft) { | ||||||
|                 if(event->key == InputKeyLeft) { |                 if(model->frequency > 0) model->frequency--; | ||||||
|                     if(model->frequency > 0) model->frequency--; |             } else if(event->key == InputKeyRight) { | ||||||
|                 } else if(event->key == InputKeyRight) { |                 if(model->frequency < subghz_frequencies_count - 1) model->frequency++; | ||||||
|                     if(model->frequency < subghz_frequencies_count - 1) model->frequency++; |             } else if(event->key == InputKeyDown) { | ||||||
|                 } else if(event->key == InputKeyDown) { |                 if(model->path > 0) model->path--; | ||||||
|                     if(model->path > 0) model->path--; |             } else if(event->key == InputKeyUp) { | ||||||
|                 } else if(event->key == InputKeyUp) { |                 if(model->path < FuriHalSubGhzPath868) model->path++; | ||||||
|                     if(model->path < FuriHalSubGhzPath868) model->path++; |             } else if(event->key == InputKeyOk) { | ||||||
|                 } else if(event->key == InputKeyOk) { |                 if(model->status == SubghzTestPacketModelStatusTx) { | ||||||
|                     if(model->status == SubghzTestPacketModelStatusTx) { |                     model->status = SubghzTestPacketModelStatusRx; | ||||||
|                         model->status = SubghzTestPacketModelStatusRx; |                 } else { | ||||||
|                     } else { |                     model->status = SubghzTestPacketModelStatusTx; | ||||||
|                         model->status = SubghzTestPacketModelStatusTx; |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
| 
 |  | ||||||
|                 model->real_frequency = |  | ||||||
|                     furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); |  | ||||||
|                 furi_hal_subghz_set_path(model->path); |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             model->real_frequency = | ||||||
|  |                 furi_hal_subghz_set_frequency(subghz_frequencies[model->frequency]); | ||||||
|  |             furi_hal_subghz_set_path(model->path); | ||||||
|  | 
 | ||||||
|             if(model->status == SubghzTestPacketModelStatusRx) { |             if(model->status == SubghzTestPacketModelStatusRx) { | ||||||
|                 furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance); |                 furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance); | ||||||
|             } else { |             } else { | ||||||
| @ -168,7 +166,7 @@ void subghz_test_packet_enter(void* context) { | |||||||
|     SubghzTestPacket* instance = context; |     SubghzTestPacket* instance = context; | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzTestPacketModel * model) { |         instance->view, (SubghzTestPacketModel * model) { | ||||||
| @ -210,7 +208,7 @@ SubghzTestPacket* subghz_test_packet_alloc() { | |||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     instance->view = view_alloc(); |     instance->view = view_alloc(); | ||||||
|     view_allocate_model(instance->view, ViewModelTypeLockFree, sizeof(SubghzTestPacketModel)); |     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzTestPacketModel)); | ||||||
|     view_set_context(instance->view, instance); |     view_set_context(instance->view, instance); | ||||||
|     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_packet_draw); |     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_packet_draw); | ||||||
|     view_set_input_callback(instance->view, subghz_test_packet_input); |     view_set_input_callback(instance->view, subghz_test_packet_input); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "subghz_static.h" | #include "subghz_test_static.h" | ||||||
| #include "../subghz_i.h" | #include "../subghz_i.h" | ||||||
| 
 | 
 | ||||||
| #include <math.h> | #include <math.h> | ||||||
| @ -8,30 +8,30 @@ | |||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> | #include <lib/subghz/protocols/subghz_protocol_princeton.h> | ||||||
| 
 | 
 | ||||||
| static const uint32_t subghz_static_keys[] = { | static const uint32_t subghz_test_static_keys[] = { | ||||||
|     0x0074BADE, |     0x0074BADE, | ||||||
|     0x0074BADD, |     0x0074BADD, | ||||||
|     0x0074BADB, |     0x0074BADB, | ||||||
|     0x00E34A4E, |     0x00E34A4E, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct SubghzStatic { | struct SubghzTestStatic { | ||||||
|     View* view; |     View* view; | ||||||
|     SubGhzEncoderPrinceton* encoder; |     SubGhzEncoderPrinceton* encoder; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzStaticStatusRx, |     SubghzTestStaticStatusRx, | ||||||
|     SubghzStaticStatusTx, |     SubghzTestStaticStatusTx, | ||||||
| } SubghzStaticStatus; | } SubghzTestStaticStatus; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint8_t frequency; |     uint8_t frequency; | ||||||
|     uint32_t real_frequency; |     uint32_t real_frequency; | ||||||
|     uint8_t button; |     uint8_t button; | ||||||
| } SubghzStaticModel; | } SubghzTestStaticModel; | ||||||
| 
 | 
 | ||||||
| void subghz_static_draw(Canvas* canvas, SubghzStaticModel* model) { | void subghz_test_static_draw(Canvas* canvas, SubghzTestStaticModel* model) { | ||||||
|     char buffer[64]; |     char buffer[64]; | ||||||
| 
 | 
 | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
| @ -52,24 +52,21 @@ void subghz_static_draw(Canvas* canvas, SubghzStaticModel* model) { | |||||||
|     canvas_draw_str(canvas, 0, 31, buffer); |     canvas_draw_str(canvas, 0, 31, buffer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_static_input(InputEvent* event, void* context) { | bool subghz_test_static_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzStatic* instance = context; |     SubghzTestStatic* instance = context; | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(event->key == InputKeyBack) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzStaticModel * model) { |         instance->view, (SubghzTestStaticModel * model) { | ||||||
|             bool reconfigure = false; |  | ||||||
|             if(event->type == InputTypeShort) { |             if(event->type == InputTypeShort) { | ||||||
|                 if(event->key == InputKeyLeft) { |                 if(event->key == InputKeyLeft) { | ||||||
|                     if(model->frequency > 0) model->frequency--; |                     if(model->frequency > 0) model->frequency--; | ||||||
|                     reconfigure = true; |  | ||||||
|                 } else if(event->key == InputKeyRight) { |                 } else if(event->key == InputKeyRight) { | ||||||
|                     if(model->frequency < subghz_frequencies_count - 1) model->frequency++; |                     if(model->frequency < subghz_frequencies_count - 1) model->frequency++; | ||||||
|                     reconfigure = true; |  | ||||||
|                 } else if(event->key == InputKeyDown) { |                 } else if(event->key == InputKeyDown) { | ||||||
|                     if(model->button > 0) model->button--; |                     if(model->button > 0) model->button--; | ||||||
|                 } else if(event->key == InputKeyUp) { |                 } else if(event->key == InputKeyUp) { | ||||||
| @ -77,28 +74,29 @@ bool subghz_static_input(InputEvent* event, void* context) { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(reconfigure) { |             model->real_frequency = subghz_frequencies[model->frequency]; | ||||||
|                 furi_hal_subghz_idle(); |  | ||||||
|                 model->real_frequency = |  | ||||||
|                     furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); |  | ||||||
|                 furi_hal_subghz_tx(); |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             if(event->key == InputKeyOk) { |             if(event->key == InputKeyOk) { | ||||||
|  |                 NotificationApp* notification = furi_record_open("notification"); | ||||||
|                 if(event->type == InputTypePress) { |                 if(event->type == InputTypePress) { | ||||||
|                     NotificationApp* notification = furi_record_open("notification"); |  | ||||||
|                     notification_message_block(notification, &sequence_set_red_255); |                     notification_message_block(notification, &sequence_set_red_255); | ||||||
| 
 | 
 | ||||||
|  |                     FURI_LOG_I("SubghzTestStatic", "TX Start"); | ||||||
|  |                     furi_hal_subghz_idle(); | ||||||
|  |                     furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); | ||||||
|  | 
 | ||||||
|                     subghz_encoder_princeton_set( |                     subghz_encoder_princeton_set( | ||||||
|                         instance->encoder, subghz_static_keys[model->button], 20); |                         instance->encoder, subghz_test_static_keys[model->button], 10000); | ||||||
|  | 
 | ||||||
|                     furi_hal_subghz_start_async_tx( |                     furi_hal_subghz_start_async_tx( | ||||||
|                         subghz_encoder_princeton_yield, instance->encoder); |                         subghz_encoder_princeton_yield, instance->encoder); | ||||||
|                     while(!furi_hal_subghz_is_async_tx_complete()) osDelay(33); |                 } else if(event->type == InputTypeRelease) { | ||||||
|  |                     FURI_LOG_I("SubghzTestStatic", "TX Stop"); | ||||||
|                     furi_hal_subghz_stop_async_tx(); |                     furi_hal_subghz_stop_async_tx(); | ||||||
| 
 | 
 | ||||||
|                     notification_message(notification, &sequence_reset_red); |                     notification_message(notification, &sequence_reset_red); | ||||||
|                     furi_record_close("notification"); |  | ||||||
|                 } |                 } | ||||||
|  |                 furi_record_close("notification"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return true; |             return true; | ||||||
| @ -107,58 +105,55 @@ bool subghz_static_input(InputEvent* event, void* context) { | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_static_enter(void* context) { | void subghz_test_static_enter(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzStatic* instance = context; |     SubghzTestStatic* instance = context; | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
|     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync); |     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); | ||||||
| 
 | 
 | ||||||
|     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||||
|     hal_gpio_write(&gpio_cc1101_g0, false); |     hal_gpio_write(&gpio_cc1101_g0, false); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         instance->view, (SubghzStaticModel * model) { |         instance->view, (SubghzTestStaticModel * model) { | ||||||
|             model->frequency = subghz_frequencies_433_92; |             model->frequency = subghz_frequencies_433_92; | ||||||
|             model->real_frequency = |             model->real_frequency = subghz_frequencies[model->frequency]; | ||||||
|                 furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]); |  | ||||||
|             model->button = 0; |             model->button = 0; | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
| 
 |  | ||||||
|     furi_hal_subghz_tx(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_static_exit(void* context) { | void subghz_test_static_exit(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     furi_hal_subghz_sleep(); |     furi_hal_subghz_sleep(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubghzStatic* subghz_static_alloc() { | SubghzTestStatic* subghz_test_static_alloc() { | ||||||
|     SubghzStatic* instance = furi_alloc(sizeof(SubghzStatic)); |     SubghzTestStatic* instance = furi_alloc(sizeof(SubghzTestStatic)); | ||||||
| 
 | 
 | ||||||
|     // View allocation and configuration
 |     // View allocation and configuration
 | ||||||
|     instance->view = view_alloc(); |     instance->view = view_alloc(); | ||||||
|     view_allocate_model(instance->view, ViewModelTypeLockFree, sizeof(SubghzStaticModel)); |     view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzTestStaticModel)); | ||||||
|     view_set_context(instance->view, instance); |     view_set_context(instance->view, instance); | ||||||
|     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_static_draw); |     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_static_draw); | ||||||
|     view_set_input_callback(instance->view, subghz_static_input); |     view_set_input_callback(instance->view, subghz_test_static_input); | ||||||
|     view_set_enter_callback(instance->view, subghz_static_enter); |     view_set_enter_callback(instance->view, subghz_test_static_enter); | ||||||
|     view_set_exit_callback(instance->view, subghz_static_exit); |     view_set_exit_callback(instance->view, subghz_test_static_exit); | ||||||
| 
 | 
 | ||||||
|     instance->encoder = subghz_encoder_princeton_alloc(); |     instance->encoder = subghz_encoder_princeton_alloc(); | ||||||
| 
 | 
 | ||||||
|     return instance; |     return instance; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_static_free(SubghzStatic* instance) { | void subghz_test_static_free(SubghzTestStatic* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     subghz_encoder_princeton_free(instance->encoder); |     subghz_encoder_princeton_free(instance->encoder); | ||||||
|     view_free(instance->view); |     view_free(instance->view); | ||||||
|     free(instance); |     free(instance); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| View* subghz_static_get_view(SubghzStatic* instance) { | View* subghz_test_static_get_view(SubghzTestStatic* instance) { | ||||||
|     furi_assert(instance); |     furi_assert(instance); | ||||||
|     return instance->view; |     return instance->view; | ||||||
| } | } | ||||||
							
								
								
									
										11
									
								
								applications/subghz/views/subghz_test_static.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,11 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/view.h> | ||||||
|  | 
 | ||||||
|  | typedef struct SubghzTestStatic SubghzTestStatic; | ||||||
|  | 
 | ||||||
|  | SubghzTestStatic* subghz_test_static_alloc(); | ||||||
|  | 
 | ||||||
|  | void subghz_test_static_free(SubghzTestStatic* subghz_static); | ||||||
|  | 
 | ||||||
|  | View* subghz_test_static_get_view(SubghzTestStatic* subghz_static); | ||||||
| @ -7,8 +7,7 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| 
 | #include <lib/subghz/protocols/subghz_protocol_keeloq.h> | ||||||
| #include <assets_icons.h> |  | ||||||
| 
 | 
 | ||||||
| struct SubghzTransmitter { | struct SubghzTransmitter { | ||||||
|     View* view; |     View* view; | ||||||
| @ -19,6 +18,8 @@ struct SubghzTransmitter { | |||||||
| typedef struct { | typedef struct { | ||||||
|     string_t text; |     string_t text; | ||||||
|     uint16_t scene; |     uint16_t scene; | ||||||
|  |     uint32_t real_frequency; | ||||||
|  |     FuriHalSubGhzPreset preset; | ||||||
|     SubGhzProtocolCommon* protocol; |     SubGhzProtocolCommon* protocol; | ||||||
| } SubghzTransmitterModel; | } SubghzTransmitterModel; | ||||||
| 
 | 
 | ||||||
| @ -42,36 +43,102 @@ void subghz_transmitter_set_protocol( | |||||||
|         }); |         }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void subghz_transmitter_set_frequency_preset( | ||||||
|  |     SubghzTransmitter* subghz_transmitter, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset) { | ||||||
|  |     with_view_model( | ||||||
|  |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|  |             model->real_frequency = frequency; | ||||||
|  |             model->preset = preset; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void subghz_transmitter_button_right(Canvas* canvas, const char* str) { | ||||||
|  |     const uint8_t button_height = 13; | ||||||
|  |     const uint8_t vertical_offset = 3; | ||||||
|  |     const uint8_t horizontal_offset = 1; | ||||||
|  |     const uint8_t string_width = canvas_string_width(canvas, str); | ||||||
|  |     const Icon* icon = &I_ButtonCenter_7x7; | ||||||
|  |     const uint8_t icon_offset = 3; | ||||||
|  |     const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset; | ||||||
|  |     const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; | ||||||
|  | 
 | ||||||
|  |     const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40; | ||||||
|  |     const uint8_t y = canvas_height(canvas); | ||||||
|  | 
 | ||||||
|  |     canvas_draw_box(canvas, x, y - button_height, button_width, button_height); | ||||||
|  | 
 | ||||||
|  |     canvas_draw_line(canvas, x - 1, y, x - 1, y - button_height + 0); | ||||||
|  |     canvas_draw_line(canvas, x - 2, y, x - 2, y - button_height + 1); | ||||||
|  |     canvas_draw_line(canvas, x - 3, y, x - 3, y - button_height + 2); | ||||||
|  | 
 | ||||||
|  |     canvas_draw_line(canvas, x + button_width + 0, y, x + button_width + 0, y - button_height + 0); | ||||||
|  |     canvas_draw_line(canvas, x + button_width + 1, y, x + button_width + 1, y - button_height + 1); | ||||||
|  |     canvas_draw_line(canvas, x + button_width + 2, y, x + button_width + 2, y - button_height + 2); | ||||||
|  | 
 | ||||||
|  |     canvas_invert_color(canvas); | ||||||
|  |     canvas_draw_icon( | ||||||
|  |         canvas, x + horizontal_offset, y - button_height + vertical_offset, &I_ButtonCenter_7x7); | ||||||
|  |     canvas_draw_str( | ||||||
|  |         canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); | ||||||
|  |     canvas_invert_color(canvas); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { | void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) { | ||||||
|  |     char buffer[64]; | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
|     elements_multiline_text(canvas, 0, 10, string_get_cstr(model->text)); |     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text)); | ||||||
|  |     snprintf( | ||||||
|  |         buffer, | ||||||
|  |         sizeof(buffer), | ||||||
|  |         "%03ld.%03ld", | ||||||
|  |         model->real_frequency / 1000000 % 1000, | ||||||
|  |         model->real_frequency / 1000 % 1000); | ||||||
|  |     canvas_draw_str(canvas, 90, 8, buffer); | ||||||
| 
 | 
 | ||||||
|     if(model->protocol && model->protocol->get_upload_protocol) { |     if(model->protocol && model->protocol->get_upload_protocol) { | ||||||
|         elements_button_center(canvas, "Send"); |         if((!strcmp(model->protocol->name, "KeeLoq")) && | ||||||
|  |            (!strcmp(subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         subghz_transmitter_button_right(canvas, "Send"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_transmitter_input(InputEvent* event, void* context) { | bool subghz_transmitter_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubghzTransmitter* subghz_transmitter = context; |     SubghzTransmitter* subghz_transmitter = context; | ||||||
|     bool can_be_send = false; |     bool can_be_sent = false; | ||||||
|  | 
 | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|             can_be_send = (model->protocol && model->protocol->get_upload_protocol); |             if(model->protocol && model->protocol->get_upload_protocol) { | ||||||
|  |                 if((!strcmp(model->protocol->name, "KeeLoq")) && | ||||||
|  |                    (!strcmp( | ||||||
|  |                        subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 can_be_sent = true; | ||||||
|  |             } | ||||||
|  |             //can_be_sent = (model->protocol && model->protocol->get_upload_protocol);
 | ||||||
|             string_clean(model->text); |             string_clean(model->text); | ||||||
|             model->protocol->to_string(model->protocol, model->text); |             model->protocol->to_string(model->protocol, model->text); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     //if(event->type != InputTypeShort) return false;
 |     //if(event->type != InputTypeShort) return false;
 | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { | ||||||
|         return false; |  | ||||||
|     } else if(can_be_send && event->key == InputKeyOk && event->type == InputTypePress) { |  | ||||||
|         subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); |         subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context); | ||||||
|         return true; |         return true; | ||||||
|     } else if(can_be_send && event->key == InputKeyOk && event->type == InputTypeRelease) { |     } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) { | ||||||
|         subghz_transmitter->callback(SubghzTransmitterEventSendStop, subghz_transmitter->context); |         subghz_transmitter->callback(SubghzTransmitterEventSendStop, subghz_transmitter->context); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @ -96,6 +163,7 @@ void subghz_transmitter_enter(void* context) { | |||||||
|     SubghzTransmitter* subghz_transmitter = context; |     SubghzTransmitter* subghz_transmitter = context; | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         subghz_transmitter->view, (SubghzTransmitterModel * model) { |         subghz_transmitter->view, (SubghzTransmitterModel * model) { | ||||||
|  |             string_clean(model->text); | ||||||
|             model->protocol->to_string(model->protocol, model->text); |             model->protocol->to_string(model->protocol, model->text); | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ typedef enum { | |||||||
|     SubghzTransmitterEventSendStart, |     SubghzTransmitterEventSendStart, | ||||||
|     SubghzTransmitterEventSendStop, |     SubghzTransmitterEventSendStop, | ||||||
|     SubghzTransmitterEventBack, |     SubghzTransmitterEventBack, | ||||||
|  |     SubghzTransmitterEventNoMan, | ||||||
| } SubghzTransmitterEvent; | } SubghzTransmitterEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct SubghzTransmitter SubghzTransmitter; | typedef struct SubghzTransmitter SubghzTransmitter; | ||||||
| @ -27,3 +28,7 @@ View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter); | |||||||
| void subghz_transmitter_set_protocol( | void subghz_transmitter_set_protocol( | ||||||
|     SubghzTransmitter* subghz_transmitter, |     SubghzTransmitter* subghz_transmitter, | ||||||
|     SubGhzProtocolCommon* protocol); |     SubGhzProtocolCommon* protocol); | ||||||
|  | void subghz_transmitter_set_frequency_preset( | ||||||
|  |     SubghzTransmitter* subghz_transmitter, | ||||||
|  |     uint32_t frequency, | ||||||
|  |     FuriHalSubGhzPreset preset); | ||||||
|  | |||||||
| @ -1,11 +1,12 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include "../minunit.h" | #include "../minunit.h" | ||||||
| #include "irda.h" | #include "irda.h" | ||||||
| #include "irda_common_i.h" | #include "common/irda_common_i.h" | ||||||
| #include "test_data/irda_nec_test_data.srcdata" | #include "test_data/irda_nec_test_data.srcdata" | ||||||
| #include "test_data/irda_necext_test_data.srcdata" | #include "test_data/irda_necext_test_data.srcdata" | ||||||
| #include "test_data/irda_samsung_test_data.srcdata" | #include "test_data/irda_samsung_test_data.srcdata" | ||||||
| #include "test_data/irda_rc6_test_data.srcdata" | #include "test_data/irda_rc6_test_data.srcdata" | ||||||
|  | #include "test_data/irda_rc5_test_data.srcdata" | ||||||
| 
 | 
 | ||||||
| #define RUN_ENCODER(data, expected) \ | #define RUN_ENCODER(data, expected) \ | ||||||
|     run_encoder((data), COUNT_OF(data), (expected), COUNT_OF(expected)) |     run_encoder((data), COUNT_OF(data), (expected), COUNT_OF(expected)) | ||||||
| @ -153,16 +154,19 @@ MU_TEST(test_decoder_samsung32) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST(test_mix) { | MU_TEST(test_mix) { | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input2, test_decoder_rc5_expected2); | ||||||
|     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); |     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); | ||||||
|     // can use encoder data for decoding, but can't do opposite
 |     // can use encoder data for decoding, but can't do opposite
 | ||||||
|     RUN_DECODER(test_encoder_rc6_expected1, test_encoder_rc6_input1); |     RUN_DECODER(test_encoder_rc6_expected1, test_encoder_rc6_input1); | ||||||
|     RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1); |     RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1); | ||||||
|     RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1); |     RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1); | ||||||
|     RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1); |     RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input1, test_decoder_rc5_expected1); | ||||||
|     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); |     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); | ||||||
|     RUN_DECODER(test_decoder_nec_input2, test_decoder_nec_expected2); |     RUN_DECODER(test_decoder_nec_input2, test_decoder_nec_expected2); | ||||||
|     RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1); |     RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1); | ||||||
|     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); |     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input5, test_decoder_rc5_expected5); | ||||||
|     RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1); |     RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -187,6 +191,25 @@ MU_TEST(test_decoder_necext1) { | |||||||
|     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); |     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | MU_TEST(test_decoder_rc5) { | ||||||
|  |     RUN_DECODER(test_decoder_rc5x_input1, test_decoder_rc5x_expected1); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input1, test_decoder_rc5_expected1); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input2, test_decoder_rc5_expected2); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input3, test_decoder_rc5_expected3); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input4, test_decoder_rc5_expected4); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input5, test_decoder_rc5_expected5); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input6, test_decoder_rc5_expected6); | ||||||
|  |     RUN_DECODER(test_decoder_rc5_input_all_repeats, test_decoder_rc5_expected_all_repeats); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_encoder_rc5x) { | ||||||
|  |     RUN_ENCODER(test_decoder_rc5x_expected1, test_decoder_rc5x_input1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MU_TEST(test_encoder_rc5) { | ||||||
|  |     RUN_ENCODER(test_decoder_rc5_expected_all_repeats, test_decoder_rc5_input_all_repeats); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| MU_TEST(test_decoder_rc6) { | MU_TEST(test_decoder_rc6) { | ||||||
|     RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1); |     RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1); | ||||||
| } | } | ||||||
| @ -200,20 +223,24 @@ MU_TEST(test_encoder_decoder_all) { | |||||||
|     run_encoder_decoder(test_necext_all, COUNT_OF(test_necext_all)); |     run_encoder_decoder(test_necext_all, COUNT_OF(test_necext_all)); | ||||||
|     run_encoder_decoder(test_samsung32_all, COUNT_OF(test_samsung32_all)); |     run_encoder_decoder(test_samsung32_all, COUNT_OF(test_samsung32_all)); | ||||||
|     run_encoder_decoder(test_rc6_all, COUNT_OF(test_rc6_all)); |     run_encoder_decoder(test_rc6_all, COUNT_OF(test_rc6_all)); | ||||||
|  |     run_encoder_decoder(test_rc5_all, COUNT_OF(test_rc5_all)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MU_TEST_SUITE(test_irda_decoder_encoder) { | MU_TEST_SUITE(test_irda_decoder_encoder) { | ||||||
|     MU_SUITE_CONFIGURE(&test_setup, &test_teardown); |     MU_SUITE_CONFIGURE(&test_setup, &test_teardown); | ||||||
| 
 | 
 | ||||||
|     MU_RUN_TEST(test_encoder_decoder_all); |     MU_RUN_TEST(test_encoder_rc5x); | ||||||
|  |     MU_RUN_TEST(test_encoder_rc5); | ||||||
|  |     MU_RUN_TEST(test_decoder_rc5); | ||||||
|  |     MU_RUN_TEST(test_decoder_rc6); | ||||||
|  |     MU_RUN_TEST(test_encoder_rc6); | ||||||
|     MU_RUN_TEST(test_decoder_unexpected_end_in_sequence); |     MU_RUN_TEST(test_decoder_unexpected_end_in_sequence); | ||||||
|     MU_RUN_TEST(test_decoder_nec1); |     MU_RUN_TEST(test_decoder_nec1); | ||||||
|     MU_RUN_TEST(test_decoder_nec2); |     MU_RUN_TEST(test_decoder_nec2); | ||||||
|     MU_RUN_TEST(test_decoder_samsung32); |     MU_RUN_TEST(test_decoder_samsung32); | ||||||
|     MU_RUN_TEST(test_decoder_necext1); |     MU_RUN_TEST(test_decoder_necext1); | ||||||
|     MU_RUN_TEST(test_mix); |     MU_RUN_TEST(test_mix); | ||||||
|     MU_RUN_TEST(test_decoder_rc6); |     MU_RUN_TEST(test_encoder_decoder_all); | ||||||
|     MU_RUN_TEST(test_encoder_rc6); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int run_minunit_test_irda_decoder_encoder() { | int run_minunit_test_irda_decoder_encoder() { | ||||||
|  | |||||||
| @ -0,0 +1,160 @@ | |||||||
|  | /* | ||||||
|  | _______----__--____----__--____--__----____----__--__--__--__ | ||||||
|  |      | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | ||||||
|  |       s1  s2   t |     address       |        command        | | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | const uint32_t test_decoder_rc5x_input1[] = { | ||||||
|  | 27000 + 888, 1776, 888, 888, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_decoder_rc5x_expected1[] = { | ||||||
|  |     {IrdaProtocolRC5X,     0x13,      0x10,  false}, // toggle 0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | _______--__----____----__--____--__----____----__--__--__--__ | ||||||
|  |      | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | ||||||
|  |       s1  s2   t |     address       |        command        | | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | const uint32_t test_decoder_rc5_input1[] = { | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_decoder_rc5_expected1[] = { | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x10,  false}, // toggle 0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | _______--__--__--__----__--____--__----____----__--__--__--__ | ||||||
|  |      | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | ||||||
|  |       s1  s2   t |     address       |        command        | | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | const uint32_t test_decoder_rc5_input2[] = { | ||||||
|  | 27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_decoder_rc5_expected2[] = { | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x10,  false}, // toggle 1 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | _______--__----____----__--____--__----____----__--__--____-- | ||||||
|  |      | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | | ||||||
|  |       s1  s2   t |     address       |        command        | | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | const uint32_t test_decoder_rc5_input3[] = { | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_decoder_rc5_expected3[] = { | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x11,  false}, // toggle 0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | _______--__--__--__----__--____--__----____----__--__--____-- | ||||||
|  |      | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | | ||||||
|  |       s1  s2   t |     address       |        command        | | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | const uint32_t test_decoder_rc5_input4[] = { | ||||||
|  | 27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_decoder_rc5_expected4[] = { | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x11,  false}, // toggle 1 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | _______--__----____--__--__--__--__--__--__--__--__--__--__-- | ||||||
|  |      | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | ||||||
|  |       s1  s2   t |     address       |        command        | | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | const uint32_t test_decoder_rc5_input5[] = { | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_decoder_rc5_expected5[] = { | ||||||
|  |     {IrdaProtocolRC5,     0x1F,      0x3F,  false}, // toggle 0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | _______--__--__--__--__--__--__--__--__--__--__--__--__--__-- | ||||||
|  |      | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | ||||||
|  |       s1  s2   t |     address       |        command        | | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | const uint32_t test_decoder_rc5_input6[] = { | ||||||
|  | 27000 + 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_decoder_rc5_expected6[] = { | ||||||
|  |     {IrdaProtocolRC5,     0x1F,      0x3F,  false}, // toggle 1 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | const uint32_t test_decoder_rc5_input_all_repeats[] = { | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888, | ||||||
|  | 27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888, | ||||||
|  | 27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888, | ||||||
|  | 27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888, | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888, | ||||||
|  | 27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888, | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888, | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888, | ||||||
|  | 27000 + 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, | ||||||
|  | 27000 + 888, 888, 888, 1776, 1776, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_decoder_rc5_expected_all_repeats[] = { | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x11,  false}, // toggle 0 | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x11,  false}, // toggle 1 | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x11,  true},  // toggle 1 | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x11,  true},  // toggle 1 | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x11,  false}, // toggle 0 | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x10,  false}, // toggle 1 | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x10,  false}, // toggle 0 | ||||||
|  |     {IrdaProtocolRC5,     0x13,      0x10,  true},  // toggle 0 | ||||||
|  |     {IrdaProtocolRC5,     0x1F,      0x3F,  false}, // toggle 1 | ||||||
|  |     {IrdaProtocolRC5,     0x1F,      0x3F,  false}, // toggle 0 | ||||||
|  |     {IrdaProtocolRC5,     0x1F,      0x3F,  true},  // toggle 0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | const IrdaMessage test_rc5_all[] = { | ||||||
|  |     {IrdaProtocolRC5,     0x1F,      0x3F,  false}, | ||||||
|  |     {IrdaProtocolRC5,     0x00,      0x00,  false}, | ||||||
|  |     {IrdaProtocolRC5,     0x10,      0x01,  false}, | ||||||
|  |     {IrdaProtocolRC5,     0x01,      0x20,  false}, | ||||||
|  |     {IrdaProtocolRC5,     0x01,      0x20,  false}, | ||||||
|  |     {IrdaProtocolRC5,     0x01,      0x20,  true}, | ||||||
|  |     {IrdaProtocolRC5,     0x01,      0x20,  true}, | ||||||
|  |     {IrdaProtocolRC5,     0x01,      0x20,  true}, | ||||||
|  |     {IrdaProtocolRC5,     0x01,      0x20,  true}, | ||||||
|  |     {IrdaProtocolRC5,     0x1F,      0x3F,  false}, | ||||||
|  |     {IrdaProtocolRC5,     0x0A,      0x2A,  false}, | ||||||
|  |     {IrdaProtocolRC5,     0x15,      0x15,  false}, | ||||||
|  |     {IrdaProtocolRC5,     0x15,      0x15,  true}, | ||||||
|  | 
 | ||||||
|  |     {IrdaProtocolRC5X,     0x1F,      0x3F,  false}, | ||||||
|  |     {IrdaProtocolRC5X,     0x00,      0x00,  false}, | ||||||
|  |     {IrdaProtocolRC5X,     0x10,      0x01,  false}, | ||||||
|  |     {IrdaProtocolRC5X,     0x01,      0x20,  false}, | ||||||
|  |     {IrdaProtocolRC5X,     0x01,      0x20,  false}, | ||||||
|  |     {IrdaProtocolRC5X,     0x01,      0x20,  true}, | ||||||
|  |     {IrdaProtocolRC5X,     0x01,      0x20,  true}, | ||||||
|  |     {IrdaProtocolRC5X,     0x01,      0x20,  true}, | ||||||
|  |     {IrdaProtocolRC5X,     0x01,      0x20,  true}, | ||||||
|  |     {IrdaProtocolRC5X,     0x1F,      0x3F,  false}, | ||||||
|  |     {IrdaProtocolRC5X,     0x0A,      0x2A,  false}, | ||||||
|  |     {IrdaProtocolRC5X,     0x15,      0x15,  false}, | ||||||
|  |     {IrdaProtocolRC5X,     0x15,      0x15,  true}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| @ -15,17 +15,17 @@ _____---------______--____--__--__------____--____--__----____--__----__--__--__ | |||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| const uint32_t test_decoder_rc6_input1[] = { | const uint32_t test_decoder_rc6_input1[] = { | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444 + 888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444 + 888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 888,   // failed | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 888,   // failed | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444 + 888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444 + 888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 888,   // failed | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 888,   // failed | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444 + 888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 888, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444 + 888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 888, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 888,   // failed | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 444 + 444, 888 + 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 888,   // failed | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const IrdaMessage test_decoder_rc6_expected1[] = { | const IrdaMessage test_decoder_rc6_expected1[] = { | ||||||
| @ -54,14 +54,14 @@ const IrdaMessage test_encoder_rc6_input1[] = { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const uint32_t test_encoder_rc6_expected1[] = { | const uint32_t test_encoder_rc6_expected1[] = { | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 888, 888+444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 888, 888+444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 888, 888+444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 888, 888+444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 888, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 888, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 888, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 888, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 888, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 888, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 888, 888+444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444, 888, 888+444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| 2700, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | 27000, 2666, 889, 444, 888, 444, 444, 444, 444, 444+888, 888, 444, 888, 444, 444, 888, 888, 444, 444, 888, 444, 444, 444, 444, 888, 888, 888, 444, 444, 444, 444, 444, 444, 444, 444, 444, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -53,6 +53,9 @@ const uint8_t *_I_ButtonLeft_4x7[] = {_I_ButtonLeft_4x7_0}; | |||||||
| const uint8_t _I_ButtonLeftSmall_3x5_0[] = {0x04,0x06,0x07,0x06,0x04,}; | const uint8_t _I_ButtonLeftSmall_3x5_0[] = {0x04,0x06,0x07,0x06,0x04,}; | ||||||
| const uint8_t *_I_ButtonLeftSmall_3x5[] = {_I_ButtonLeftSmall_3x5_0}; | const uint8_t *_I_ButtonLeftSmall_3x5[] = {_I_ButtonLeftSmall_3x5_0}; | ||||||
| 
 | 
 | ||||||
|  | const uint8_t _I_DFU_128x50_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8F,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x7F,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x75,0x00,0x00,0xF0,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0x0A,0x00,0x00,0x0F,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xE0,0x0F,0x00,0xC0,0xE0,0x4F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x30,0x1E,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x18,0x00,0x8C,0x01,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x81,0xFF,0x19,0x00,0x63,0x00,0xC0,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x60,0x5E,0x1F,0x80,0x18,0x00,0xE0,0x0E,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x18,0xAF,0x0F,0x40,0x06,0x00,0xF8,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x06,0x57,0x01,0x20,0x01,0x00,0x78,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x81,0xAF,0x02,0x90,0x00,0x00,0x38,0x80,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x80,0x57,0x01,0x48,0x00,0x00,0x10,0x60,0x40,0x00,0x00,0x00,0x00,0x00,0xC0,0x10,0x80,0xAB,0x00,0x24,0x00,0x00,0x08,0x10,0x40,0x3F,0x00,0x00,0x00,0x00,0x38,0x0C,0xC0,0x57,0x01,0x12,0x00,0x00,0x04,0x08,0x40,0xC0,0x0F,0x00,0x00,0xC0,0x07,0x03,0xF0,0xAB,0x00,0x0A,0x00,0x00,0x02,0x04,0x40,0x00,0xF0,0x1F,0x80,0x3F,0xC0,0x00,0xFC,0x55,0x01,0x05,0xE0,0x00,0x01,0x04,0x40,0x00,0x00,0xE0,0x7F,0x00,0x30,0x00,0xFF,0xAB,0x00,0x05,0xE0,0x80,0x00,0x02,0x40,0x0F,0x00,0x00,0x00,0x80,0x0F,0xE0,0xCF,0x55,0x81,0x02,0xF0,0x40,0x00,0x02,0x40,0xF0,0x0F,0x00,0x00,0x7F,0x00,0xFE,0xC3,0xAB,0x80,0x02,0x78,0x20,0x00,0x01,0x40,0x00,0xF0,0xFF,0xFF,0x00,0xF0,0xFF,0xC0,0xD5,0x81,0x01,0x7E,0x10,0x80,0x00,0x20,0x00,0x00,0x00,0x00,0xC0,0xFF,0x0F,0xE0,0xFA,0x83,0xC1,0x3F,0x08,0x80,0x00,0x20,0x00,0x00,0x00,0x00,0xFF,0xFF,0x01,0xD8,0x07,0x83,0xF1,0x1F,0x04,0x40,0x00,0x20,0x00,0xE0,0xFF,0xFF,0xFF,0x0F,0x80,0xC7,0x01,0x83,0xF1,0x0F,0x00,0x20,0x00,0x10,0xE0,0xFF,0xFF,0xFF,0x3F,0xC0,0x7F,0x40,0x80,0x83,0xE1,0x01,0x00,0x20,0x00,0x18,0xFC,0xFF,0xFF,0xFF,0x03,0x3F,0x00,0x20,0xFC,0x83,0x01,0x00,0x00,0x10,0x00,0x18,0xFF,0xFF,0xFF,0x3F,0xF0,0x00,0x00,0x10,0xD7,0x01,0x03,0x00,0x00,0x08,0x00,0x1C,0xFF,0xFF,0x01,0x00,0x0F,0x00,0x00,0x88,0xAB,0x02,0xE3,0x01,0x00,0x08,0x00,0x0C,0xFF,0x07,0x00,0xE0,0x00,0x00,0x00,0xC4,0x55,0x05,0x1E,0x00,0x00,0x04,0x00,0x0E,0x7F,0x00,0x00,0x1C,0x00,0x00,0x00,0xA3,0xAB,0x02,0x06,0x00,0x00,0x02,0x00,0x0F,0x0F,0x00,0x80,0x03,0x00,0x00,0xC0,0x10,0x57,0x05,0x02,0x00,0x00,0x01,0x80,0x07,0x03,0x00,0x70,0x00,0x00,0x00,0x30,0x08,0xAB,0x0A,0x02,0x00,0xC0,0x00,0xC0,0x07,0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,0x84,0x57,0x15,0x01,0x00,0x30,0x00,0xE0,0x07,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0xC3,0xFF,0x2A,0x01,0x00,0x0C,0x00,0xF0,0x0F,0x00,0xC0,0x00,0x00,0x00,0xE0,0xC0,0xE0,0xFE,0x55,0x01,0x82,0x03,0x00,0xF8,0x15,0x00,0x30,0x00,0x00,0x00,0x1C,0x30,0x78,0xFE,0xAA,0x01,0x7C,0x00,0x00,0xFC,0x23,0x00,0x0E,0x00,0x00,0xC0,0x03,0x0C,0x3C,0x7F,0x5D,0x01,0x00,0x00,0x00,0xFF,0x45,0xC0,0x01,0x00,0x00,0x3E,0x00,0x02,0x8F,0xBF,0xAE,0x03,0x00,0x00,0xC0,0xFF,0x82,0x30,0x00,0x00,0xC0,0x01,0x80,0xC1,0x43,0xFE,0x5D,0x01,0x00,0x00,0xF0,0xFF,0x05,0x0F,0x00,0x80,0x3F,0x00,0x60,0xF0,0x31,0xF6,0xAE,0x03,0x00,0x00,0xFA,0xAF,0x02,0xFC,0xFF,0x7F,0x00,0x00,0x18,0x7C,0x08,0x23,0xFF,0x05,0x00,0x00,0xFD,0x55,0x01,0x00,0x00,0x00,0x00,0x00,0x86,0x1F,0x84,0x30,0xFE,0x0A,0x00,0x00,0xAA,0xAA,0x00,0x00,0x00,0x00,0x00,0x80,0xF1,0x07,0x43,0x18,0xFF,0x15,0x00,0x00,0x54,0x15,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0x80,0x20,0x8C,0xFF,0xAA,0x00,0x00,0x00,0x00,0x00,}; | ||||||
|  | const uint8_t *_I_DFU_128x50[] = {_I_DFU_128x50_0}; | ||||||
|  | 
 | ||||||
| const uint8_t _I_Warning_30x23_0[] = {0x00,0xC0,0x00,0x00,0x00,0xE0,0x01,0x00,0x00,0xF0,0x03,0x00,0x00,0xF0,0x03,0x00,0x00,0xF8,0x07,0x00,0x00,0x3C,0x0F,0x00,0x00,0x3C,0x0F,0x00,0x00,0x3E,0x1F,0x00,0x00,0x3F,0x3F,0x00,0x00,0x3F,0x3F,0x00,0x80,0x3F,0x7F,0x00,0xC0,0x3F,0xFF,0x00,0xC0,0x3F,0xFF,0x00,0xE0,0x3F,0xFF,0x01,0xF0,0x3F,0xFF,0x03,0xF0,0x3F,0xFF,0x03,0xF8,0x3F,0xFF,0x07,0xFC,0xFF,0xFF,0x0F,0xFC,0xFF,0xFF,0x0F,0xFE,0x3F,0xFF,0x1F,0xFF,0x3F,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xFE,0xFF,0xFF,0x1F,}; | const uint8_t _I_Warning_30x23_0[] = {0x00,0xC0,0x00,0x00,0x00,0xE0,0x01,0x00,0x00,0xF0,0x03,0x00,0x00,0xF0,0x03,0x00,0x00,0xF8,0x07,0x00,0x00,0x3C,0x0F,0x00,0x00,0x3C,0x0F,0x00,0x00,0x3E,0x1F,0x00,0x00,0x3F,0x3F,0x00,0x00,0x3F,0x3F,0x00,0x80,0x3F,0x7F,0x00,0xC0,0x3F,0xFF,0x00,0xC0,0x3F,0xFF,0x00,0xE0,0x3F,0xFF,0x01,0xF0,0x3F,0xFF,0x03,0xF0,0x3F,0xFF,0x03,0xF8,0x3F,0xFF,0x07,0xFC,0xFF,0xFF,0x0F,0xFC,0xFF,0xFF,0x0F,0xFE,0x3F,0xFF,0x1F,0xFF,0x3F,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xFE,0xFF,0xFF,0x1F,}; | ||||||
| const uint8_t *_I_Warning_30x23[] = {_I_Warning_30x23_0}; | const uint8_t *_I_Warning_30x23[] = {_I_Warning_30x23_0}; | ||||||
| 
 | 
 | ||||||
| @ -95,6 +98,18 @@ const uint8_t *_I_Flipper_young_80x60[] = {_I_Flipper_young_80x60_0}; | |||||||
| const uint8_t _I_DolphinFirstStart3_57x48_0[] = {0x00,0x00,0x00,0x80,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0xF8,0x03,0x01,0x00,0x00,0x08,0x00,0x00,0x04,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0xC0,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x02,0x00,0x38,0x40,0x00,0x00,0x02,0x00,0x04,0x00,0x3E,0x40,0x00,0x00,0xF4,0x03,0x08,0x80,0x07,0x80,0x00,0x00,0x5C,0x0D,0x10,0xE0,0x01,0x80,0x00,0x00,0xA8,0x3A,0x20,0xE0,0x00,0x00,0x01,0x00,0x58,0x55,0x00,0xC0,0x01,0x00,0x01,0x00,0xB0,0xAA,0x00,0x80,0x07,0x00,0x01,0x00,0x60,0x55,0x01,0x00,0x1E,0x00,0x01,0x0E,0xC0,0xAA,0x02,0xE0,0x5C,0x00,0x01,0x11,0x80,0x55,0x05,0x00,0xA9,0x00,0x01,0x21,0x00,0xAB,0x0A,0x00,0x56,0x07,0x01,0x41,0x00,0x56,0x15,0x00,0xEC,0x08,0x01,0x81,0x00,0xBF,0x2A,0x00,0x34,0x08,0x01,0x01,0xF1,0xC0,0x57,0x00,0x0C,0x08,0x01,0x02,0x0A,0x00,0xBE,0x00,0x04,0x08,0x01,0x02,0x06,0x00,0x78,0x83,0x02,0x04,0x01,0x02,0x0C,0x00,0xF0,0x7F,0x01,0x04,0x01,0x02,0xF4,0x01,0xFE,0x81,0x00,0x04,0x01,0x04,0x08,0xFF,0x6B,0x40,0x00,0x02,0x01,0x04,0x88,0x55,0x1D,0x40,0x00,0x02,0x01,0x04,0x50,0xAA,0x06,0x20,0x00,0x02,0x01,0x04,0x30,0xD4,0x01,0x20,0x00,0x01,0x01,0x04,0x10,0x68,0x00,0x10,0x00,0x01,0x01,0x04,0x18,0x18,0x00,0x10,0x00,0x01,0x01,0x08,0x18,0x06,0x80,0x10,0x00,0x01,0x01,0x08,0xE8,0x01,0x60,0x08,0x80,0x00,0x01,0x08,0x08,0x00,0x18,0x08,0x80,0x00,0x00,0x08,0x10,0x00,0x06,0x08,0x80,0x00,0x00,0x08,0x60,0xE0,0x01,0x08,0x80,0x00,0x00,0x08,0x80,0x1F,0x00,0x08,0x80,0x00,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x06,0x00,}; | const uint8_t _I_DolphinFirstStart3_57x48_0[] = {0x00,0x00,0x00,0x80,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0xF8,0x03,0x01,0x00,0x00,0x08,0x00,0x00,0x04,0xBC,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0xC0,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x02,0x00,0x38,0x40,0x00,0x00,0x02,0x00,0x04,0x00,0x3E,0x40,0x00,0x00,0xF4,0x03,0x08,0x80,0x07,0x80,0x00,0x00,0x5C,0x0D,0x10,0xE0,0x01,0x80,0x00,0x00,0xA8,0x3A,0x20,0xE0,0x00,0x00,0x01,0x00,0x58,0x55,0x00,0xC0,0x01,0x00,0x01,0x00,0xB0,0xAA,0x00,0x80,0x07,0x00,0x01,0x00,0x60,0x55,0x01,0x00,0x1E,0x00,0x01,0x0E,0xC0,0xAA,0x02,0xE0,0x5C,0x00,0x01,0x11,0x80,0x55,0x05,0x00,0xA9,0x00,0x01,0x21,0x00,0xAB,0x0A,0x00,0x56,0x07,0x01,0x41,0x00,0x56,0x15,0x00,0xEC,0x08,0x01,0x81,0x00,0xBF,0x2A,0x00,0x34,0x08,0x01,0x01,0xF1,0xC0,0x57,0x00,0x0C,0x08,0x01,0x02,0x0A,0x00,0xBE,0x00,0x04,0x08,0x01,0x02,0x06,0x00,0x78,0x83,0x02,0x04,0x01,0x02,0x0C,0x00,0xF0,0x7F,0x01,0x04,0x01,0x02,0xF4,0x01,0xFE,0x81,0x00,0x04,0x01,0x04,0x08,0xFF,0x6B,0x40,0x00,0x02,0x01,0x04,0x88,0x55,0x1D,0x40,0x00,0x02,0x01,0x04,0x50,0xAA,0x06,0x20,0x00,0x02,0x01,0x04,0x30,0xD4,0x01,0x20,0x00,0x01,0x01,0x04,0x10,0x68,0x00,0x10,0x00,0x01,0x01,0x04,0x18,0x18,0x00,0x10,0x00,0x01,0x01,0x08,0x18,0x06,0x80,0x10,0x00,0x01,0x01,0x08,0xE8,0x01,0x60,0x08,0x80,0x00,0x01,0x08,0x08,0x00,0x18,0x08,0x80,0x00,0x00,0x08,0x10,0x00,0x06,0x08,0x80,0x00,0x00,0x08,0x60,0xE0,0x01,0x08,0x80,0x00,0x00,0x08,0x80,0x1F,0x00,0x08,0x80,0x00,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x08,0x80,0x04,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x04,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x00,0x01,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x02,0x00,0x10,0x80,0x00,0x00,0x04,0x00,0x06,0x00,}; | ||||||
| const uint8_t *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0}; | const uint8_t *_I_DolphinFirstStart3_57x48[] = {_I_DolphinFirstStart3_57x48_0}; | ||||||
| 
 | 
 | ||||||
|  | const uint8_t _I_Scanning_123x52_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0x03,0x18,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x56,0x05,0x60,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x81,0x0A,0x80,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x80,0x00,0x15,0x00,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x40,0x00,0x38,0x00,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x20,0x00,0x74,0x00,0x04,0x00,0x00,0x40,0x82,0x01,0x00,0x00,0x00,0x41,0x00,0x00,0x20,0x00,0x68,0x00,0x04,0x00,0x00,0x20,0x82,0x02,0x06,0x00,0x00,0x21,0x00,0x00,0x10,0x00,0xD0,0xE0,0x0F,0x00,0x00,0x20,0x82,0x02,0x0A,0x0C,0x80,0x20,0x08,0x00,0x10,0x00,0xA0,0x1C,0x10,0x00,0x00,0x20,0x82,0x02,0x0A,0x14,0x80,0x10,0x04,0x00,0x08,0xE0,0xD3,0x03,0x10,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0x90,0xA7,0x40,0x24,0x00,0x00,0x10,0x82,0x02,0x0A,0x14,0x80,0x10,0x02,0x00,0x08,0xC8,0x7F,0x84,0x28,0x00,0x00,0x10,0x84,0x02,0x0A,0xFF,0x80,0x10,0x02,0x00,0x88,0x67,0x3E,0x88,0x28,0x00,0x00,0x10,0x84,0xFA,0xFF,0xFF,0x80,0x10,0x02,0x00,0x44,0x64,0x2E,0x88,0x28,0x00,0x00,0x10,0xFC,0xAF,0xFF,0x15,0x80,0x10,0x04,0x00,0x44,0xE4,0x2F,0x88,0x2A,0x00,0x00,0x18,0xD4,0xDF,0x1F,0x14,0x80,0x20,0x08,0x00,0x44,0xE4,0x2F,0x50,0xFF,0x00,0xFE,0x1F,0xEC,0x3F,0x0A,0x14,0x00,0x21,0x00,0x00,0x44,0xC4,0x2F,0xEA,0x00,0x01,0x01,0x1A,0xFC,0x02,0x0A,0x14,0x00,0x41,0x00,0x00,0x84,0x88,0x2F,0x1D,0x00,0x82,0x7D,0x1E,0x84,0x02,0x0A,0x18,0x00,0x82,0x00,0x00,0x86,0x1F,0xC6,0x06,0x00,0x84,0x7D,0x16,0x84,0x02,0x0A,0x00,0x00,0x02,0x00,0x00,0x46,0xF5,0xC3,0x01,0x00,0x44,0x01,0x22,0x84,0x02,0x0C,0x00,0x00,0x04,0x00,0x00,0x87,0x0A,0x7C,0x00,0x00,0x44,0x03,0x22,0x88,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x45,0x05,0x08,0x00,0x7E,0xA4,0x03,0x42,0x88,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x86,0x06,0x00,0xC0,0x81,0xA5,0x07,0x42,0x08,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x30,0x00,0xD2,0xFF,0x81,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0xD2,0x1F,0x80,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x80,0x00,0x03,0x00,0xD1,0x1F,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xE1,0x00,0x80,0xE9,0x0F,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x1E,0x00,0xC0,0xE8,0x0F,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x70,0xEE,0x0F,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0xF9,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xAA,0x9F,0xF0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0x55,0xFD,0x5F,0xF0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0xEA,0xFF,0x3F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0xD5,0xFF,0x1F,0xE0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x80,0xAA,0xFF,0x0F,0xE0,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x55,0x55,0x03,0xF0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xAA,0xAA,0x00,0xB0,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x54,0x75,0x00,0x58,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0xA8,0x0F,0x00,0xA8,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x7C,0x00,0x00,0x5C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0xAE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0xD7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x80,0x7B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0xC0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAA,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | ||||||
|  | const uint8_t *_I_Scanning_123x52[] = {_I_Scanning_123x52_0}; | ||||||
|  | 
 | ||||||
|  | const uint8_t _I_Quest_7x8_0[] = {0x1E,0x33,0x33,0x30,0x18,0x0C,0x00,0x0C,}; | ||||||
|  | const uint8_t *_I_Quest_7x8[] = {_I_Quest_7x8_0}; | ||||||
|  | 
 | ||||||
|  | const uint8_t _I_Unlock_7x8_0[] = {0x1C,0x22,0x02,0x4F,0x67,0x73,0x79,0x3C,}; | ||||||
|  | const uint8_t *_I_Unlock_7x8[] = {_I_Unlock_7x8_0}; | ||||||
|  | 
 | ||||||
|  | const uint8_t _I_Lock_7x8_0[] = {0x1C,0x22,0x22,0x7F,0x7F,0x77,0x7F,0x3E,}; | ||||||
|  | const uint8_t *_I_Lock_7x8[] = {_I_Lock_7x8_0}; | ||||||
|  | 
 | ||||||
| const uint8_t _I_PassportBottom_128x17_0[] = {0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0xF2,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0xF9,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0D,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x05,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x05,0xFA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x09,0x79,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0xD5,0x80,0x55,0xD5,0x00,0xF3,0xCC,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x6A,0x00,0xAB,0x6A,0x00,0x06,0x86,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,0xFE,0x3F,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | const uint8_t _I_PassportBottom_128x17_0[] = {0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x95,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x9A,0xF2,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x8F,0xF9,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0D,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x05,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x05,0xFA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x09,0x79,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0xD5,0x80,0x55,0xD5,0x00,0xF3,0xCC,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0x6A,0x00,0xAB,0x6A,0x00,0x06,0x86,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,0xFE,0x3F,0x00,0xFC,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | ||||||
| const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; | const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; | ||||||
| 
 | 
 | ||||||
| @ -321,12 +336,12 @@ const uint8_t _A_iButton_14_5[] = {0x00,0x00,0x00,0x38,0x00,0x24,0x00,0x22,0x80, | |||||||
| const uint8_t _A_iButton_14_6[] = {0x00,0x00,0x00,0x38,0x00,0x24,0x00,0x23,0x80,0x20,0xF0,0x10,0x0C,0x0D,0xE2,0x02,0x91,0x01,0x69,0x01,0x15,0x01,0x8D,0x00,0x4D,0x00,0x3E,0x00,}; | const uint8_t _A_iButton_14_6[] = {0x00,0x00,0x00,0x38,0x00,0x24,0x00,0x23,0x80,0x20,0xF0,0x10,0x0C,0x0D,0xE2,0x02,0x91,0x01,0x69,0x01,0x15,0x01,0x8D,0x00,0x4D,0x00,0x3E,0x00,}; | ||||||
| const uint8_t *_A_iButton_14[] = {_A_iButton_14_0,_A_iButton_14_1,_A_iButton_14_2,_A_iButton_14_3,_A_iButton_14_4,_A_iButton_14_5,_A_iButton_14_6}; | const uint8_t *_A_iButton_14[] = {_A_iButton_14_0,_A_iButton_14_1,_A_iButton_14_2,_A_iButton_14_3,_A_iButton_14_4,_A_iButton_14_5,_A_iButton_14_6}; | ||||||
| 
 | 
 | ||||||
|  | const uint8_t _I_Detailed_chip_17x13_0[] = {0xFC,0x7F,0x00,0x02,0x80,0x00,0x11,0x11,0x01,0x91,0x12,0x01,0x5F,0xF0,0x01,0x21,0x08,0x01,0x21,0x08,0x01,0x21,0x08,0x01,0x5F,0xF4,0x01,0x91,0x12,0x01,0x11,0x11,0x01,0x02,0x80,0x00,0xFC,0x7F,0x00,}; | ||||||
|  | const uint8_t *_I_Detailed_chip_17x13[] = {_I_Detailed_chip_17x13_0}; | ||||||
|  | 
 | ||||||
| const uint8_t _I_Medium_chip_22x21_0[] = {0xFC,0xFF,0x0F,0x02,0x00,0x10,0xF9,0xFF,0x27,0x85,0x52,0x28,0xC5,0xFF,0x28,0x25,0x00,0x29,0x95,0x67,0x2A,0x5D,0x60,0x2E,0x55,0x00,0x2A,0x1D,0x80,0x2E,0x55,0x80,0x2A,0x1D,0x80,0x2E,0x55,0x80,0x2A,0x5D,0x80,0x2E,0x95,0x7D,0x2A,0x25,0x00,0x29,0xC5,0xFF,0x28,0x85,0x52,0x28,0xF9,0xFF,0x27,0x02,0x00,0x10,0xFC,0xFF,0x0F,}; | const uint8_t _I_Medium_chip_22x21_0[] = {0xFC,0xFF,0x0F,0x02,0x00,0x10,0xF9,0xFF,0x27,0x85,0x52,0x28,0xC5,0xFF,0x28,0x25,0x00,0x29,0x95,0x67,0x2A,0x5D,0x60,0x2E,0x55,0x00,0x2A,0x1D,0x80,0x2E,0x55,0x80,0x2A,0x1D,0x80,0x2E,0x55,0x80,0x2A,0x5D,0x80,0x2E,0x95,0x7D,0x2A,0x25,0x00,0x29,0xC5,0xFF,0x28,0x85,0x52,0x28,0xF9,0xFF,0x27,0x02,0x00,0x10,0xFC,0xFF,0x0F,}; | ||||||
| const uint8_t *_I_Medium_chip_22x21[] = {_I_Medium_chip_22x21_0}; | const uint8_t *_I_Medium_chip_22x21[] = {_I_Medium_chip_22x21_0}; | ||||||
| 
 | 
 | ||||||
| const uint8_t _I_EMV_Chip_14x11_0[] = {0xFC,0x0F,0x02,0x10,0xC9,0x24,0x2F,0x3C,0x11,0x22,0x11,0x22,0x11,0x22,0x2F,0x3D,0xC9,0x24,0x02,0x10,0xFC,0x0F,}; |  | ||||||
| const uint8_t *_I_EMV_Chip_14x11[] = {_I_EMV_Chip_14x11_0}; |  | ||||||
| 
 |  | ||||||
| const uint8_t _I_Health_16x16_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x01,0x40,0x01,0x40,0x01,0x78,0x0F,0x08,0x08,0x78,0x0F,0x40,0x01,0x40,0x01,0xC0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | const uint8_t _I_Health_16x16_0[] = {0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x01,0x40,0x01,0x40,0x01,0x78,0x0F,0x08,0x08,0x78,0x0F,0x40,0x01,0x40,0x01,0xC0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; | ||||||
| const uint8_t *_I_Health_16x16[] = {_I_Health_16x16_0}; | const uint8_t *_I_Health_16x16[] = {_I_Health_16x16_0}; | ||||||
| 
 | 
 | ||||||
| @ -442,6 +457,7 @@ const Icon I_125_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.fram | |||||||
| const Icon I_ButtonRightSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRightSmall_3x5}; | const Icon I_ButtonRightSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRightSmall_3x5}; | ||||||
| const Icon I_ButtonLeft_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeft_4x7}; | const Icon I_ButtonLeft_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeft_4x7}; | ||||||
| const Icon I_ButtonLeftSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeftSmall_3x5}; | const Icon I_ButtonLeftSmall_3x5 = {.width=3,.height=5,.frame_count=1,.frame_rate=0,.frames=_I_ButtonLeftSmall_3x5}; | ||||||
|  | const Icon I_DFU_128x50 = {.width=128,.height=50,.frame_count=1,.frame_rate=0,.frames=_I_DFU_128x50}; | ||||||
| const Icon I_Warning_30x23 = {.width=30,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Warning_30x23}; | const Icon I_Warning_30x23 = {.width=30,.height=23,.frame_count=1,.frame_rate=0,.frames=_I_Warning_30x23}; | ||||||
| const Icon I_ButtonRight_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRight_4x7}; | const Icon I_ButtonRight_4x7 = {.width=4,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonRight_4x7}; | ||||||
| const Icon I_ButtonCenter_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonCenter_7x7}; | const Icon I_ButtonCenter_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_ButtonCenter_7x7}; | ||||||
| @ -456,6 +472,10 @@ const Icon I_DolphinFirstStart8_56x51 = {.width=56,.height=51,.frame_count=1,.fr | |||||||
| const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; | const Icon I_DolphinFirstStart7_61x51 = {.width=61,.height=51,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart7_61x51}; | ||||||
| const Icon I_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60}; | const Icon I_Flipper_young_80x60 = {.width=80,.height=60,.frame_count=1,.frame_rate=0,.frames=_I_Flipper_young_80x60}; | ||||||
| const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; | const Icon I_DolphinFirstStart3_57x48 = {.width=57,.height=48,.frame_count=1,.frame_rate=0,.frames=_I_DolphinFirstStart3_57x48}; | ||||||
|  | const Icon I_Scanning_123x52 = {.width=123,.height=52,.frame_count=1,.frame_rate=0,.frames=_I_Scanning_123x52}; | ||||||
|  | const Icon I_Quest_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Quest_7x8}; | ||||||
|  | const Icon I_Unlock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Unlock_7x8}; | ||||||
|  | const Icon I_Lock_7x8 = {.width=7,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Lock_7x8}; | ||||||
| const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; | const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; | ||||||
| const Icon I_DoorLeft_8x56 = {.width=8,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_8x56}; | const Icon I_DoorLeft_8x56 = {.width=8,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_8x56}; | ||||||
| const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; | const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; | ||||||
| @ -503,8 +523,8 @@ const Icon A_Sub1ghz_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.fr | |||||||
| const Icon A_Tamagotchi_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Tamagotchi_14}; | const Icon A_Tamagotchi_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Tamagotchi_14}; | ||||||
| const Icon A_U2F_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_U2F_14}; | const Icon A_U2F_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_U2F_14}; | ||||||
| const Icon A_iButton_14 = {.width=14,.height=14,.frame_count=7,.frame_rate=3,.frames=_A_iButton_14}; | const Icon A_iButton_14 = {.width=14,.height=14,.frame_count=7,.frame_rate=3,.frames=_A_iButton_14}; | ||||||
|  | const Icon I_Detailed_chip_17x13 = {.width=17,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Detailed_chip_17x13}; | ||||||
| const Icon I_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21}; | const Icon I_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21}; | ||||||
| const Icon I_EMV_Chip_14x11 = {.width=14,.height=11,.frame_count=1,.frame_rate=0,.frames=_I_EMV_Chip_14x11}; |  | ||||||
| const Icon I_Health_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Health_16x16}; | const Icon I_Health_16x16 = {.width=16,.height=16,.frame_count=1,.frame_rate=0,.frames=_I_Health_16x16}; | ||||||
| const Icon I_FaceCharging_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceCharging_29x14}; | const Icon I_FaceCharging_29x14 = {.width=29,.height=14,.frame_count=1,.frame_rate=0,.frames=_I_FaceCharging_29x14}; | ||||||
| const Icon I_BatteryBody_52x28 = {.width=52,.height=28,.frame_count=1,.frame_rate=0,.frames=_I_BatteryBody_52x28}; | const Icon I_BatteryBody_52x28 = {.width=52,.height=28,.frame_count=1,.frame_rate=0,.frames=_I_BatteryBody_52x28}; | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ extern const Icon I_125_10px; | |||||||
| extern const Icon I_ButtonRightSmall_3x5; | extern const Icon I_ButtonRightSmall_3x5; | ||||||
| extern const Icon I_ButtonLeft_4x7; | extern const Icon I_ButtonLeft_4x7; | ||||||
| extern const Icon I_ButtonLeftSmall_3x5; | extern const Icon I_ButtonLeftSmall_3x5; | ||||||
|  | extern const Icon I_DFU_128x50; | ||||||
| extern const Icon I_Warning_30x23; | extern const Icon I_Warning_30x23; | ||||||
| extern const Icon I_ButtonRight_4x7; | extern const Icon I_ButtonRight_4x7; | ||||||
| extern const Icon I_ButtonCenter_7x7; | extern const Icon I_ButtonCenter_7x7; | ||||||
| @ -28,6 +29,10 @@ extern const Icon I_DolphinFirstStart8_56x51; | |||||||
| extern const Icon I_DolphinFirstStart7_61x51; | extern const Icon I_DolphinFirstStart7_61x51; | ||||||
| extern const Icon I_Flipper_young_80x60; | extern const Icon I_Flipper_young_80x60; | ||||||
| extern const Icon I_DolphinFirstStart3_57x48; | extern const Icon I_DolphinFirstStart3_57x48; | ||||||
|  | extern const Icon I_Scanning_123x52; | ||||||
|  | extern const Icon I_Quest_7x8; | ||||||
|  | extern const Icon I_Unlock_7x8; | ||||||
|  | extern const Icon I_Lock_7x8; | ||||||
| extern const Icon I_PassportBottom_128x17; | extern const Icon I_PassportBottom_128x17; | ||||||
| extern const Icon I_DoorLeft_8x56; | extern const Icon I_DoorLeft_8x56; | ||||||
| extern const Icon I_DoorLocked_10x56; | extern const Icon I_DoorLocked_10x56; | ||||||
| @ -75,8 +80,8 @@ extern const Icon A_Sub1ghz_14; | |||||||
| extern const Icon A_Tamagotchi_14; | extern const Icon A_Tamagotchi_14; | ||||||
| extern const Icon A_U2F_14; | extern const Icon A_U2F_14; | ||||||
| extern const Icon A_iButton_14; | extern const Icon A_iButton_14; | ||||||
|  | extern const Icon I_Detailed_chip_17x13; | ||||||
| extern const Icon I_Medium_chip_22x21; | extern const Icon I_Medium_chip_22x21; | ||||||
| extern const Icon I_EMV_Chip_14x11; |  | ||||||
| extern const Icon I_Health_16x16; | extern const Icon I_Health_16x16; | ||||||
| extern const Icon I_FaceCharging_29x14; | extern const Icon I_FaceCharging_29x14; | ||||||
| extern const Icon I_BatteryBody_52x28; | extern const Icon I_BatteryBody_52x28; | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Common/DFU_128x50.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/GubGHz/Scanning_123x52.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
| Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/GubGHz/quest_7x8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/GubGHz/unlock_7x8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/NFC/Detailed_chip_17x13.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 981 B | 
							
								
								
									
										148
									
								
								assets/resources/nfc/emv/aid.nfc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,148 @@ | |||||||
|  | A00000000305076010 VISA ELO Credit | ||||||
|  | A0000000031010 VISA Debit/Credit (Classic) | ||||||
|  | A000000003101001 VISA Credit | ||||||
|  | A000000003101002 VISA Debit | ||||||
|  | A0000000032010 VISA Electron | ||||||
|  | A0000000032020 VISA | ||||||
|  | A0000000033010 VISA Interlink | ||||||
|  | A0000000034010 VISA Specific | ||||||
|  | A0000000035010 VISA Specific | ||||||
|  | A0000000036010 Domestic Visa Cash | ||||||
|  | A0000000036020 International Visa Cash | ||||||
|  | A0000000038002 VISA Auth EMV-CAP (DPA) | ||||||
|  | A0000000038010 VISA Plus | ||||||
|  | A0000000039010 VISA Loyalty | ||||||
|  | A000000003999910 VISA Proprietary ATM | ||||||
|  | A00000000401 MasterCard PayPass | ||||||
|  | A0000000041010 MasterCard Global | ||||||
|  | A00000000410101213 MasterCard Credit | ||||||
|  | A00000000410101215 MasterCard Credit | ||||||
|  | A0000000042010 MasterCard Specific | ||||||
|  | A0000000043010 MasterCard Specific | ||||||
|  | A0000000043060 Maestro (Debit) | ||||||
|  | A000000004306001 Maestro (Debit) | ||||||
|  | A0000000044010 MasterCard Specific | ||||||
|  | A0000000045010 MasterCard Specific | ||||||
|  | A0000000046000 Cirrus | ||||||
|  | A0000000048002 SecureCode EMV-CAP | ||||||
|  | A0000000049999 MasterCard PayPass | ||||||
|  | A0000000050001 Maestro UK | ||||||
|  | A0000000050002 Solo | ||||||
|  | A00000002401 Self Service | ||||||
|  | A000000025 American Express | ||||||
|  | A0000000250000 American Express | ||||||
|  | A00000002501 American Express | ||||||
|  | A000000025010402 American Express | ||||||
|  | A000000025010701 ExpressPay | ||||||
|  | A000000025010801 American Express | ||||||
|  | A0000000291010 Link / American Express | ||||||
|  | A0000000421010 Cartes Bancaire EMV Card | ||||||
|  | A0000000426010 Apple Pay | ||||||
|  | A00000006510 JCB | ||||||
|  | A0000000651010 JCB J Smart Credit | ||||||
|  | A00000006900 Moneo | ||||||
|  | A000000077010000021000000000003B Visa AEPN | ||||||
|  | A000000098 Debit Card | ||||||
|  | A0000000980848 Debit Card | ||||||
|  | A0000001211010 Dankort VISA GEM Vision | ||||||
|  | A0000001410001 PagoBANCOMAT | ||||||
|  | A0000001523010 Discover, Pulse D Pas | ||||||
|  | A0000001524010 Discover | ||||||
|  | A0000001544442 Banricompras Debito | ||||||
|  | A000000172950001 BAROC Taiwan | ||||||
|  | A0000002281010 SPAN (M/Chip) | ||||||
|  | A0000002282010 SPAN (VIS) | ||||||
|  | A0000002771010 INTERAC | ||||||
|  | A00000031510100528 Currence PuC | ||||||
|  | A0000003156020 Chipknip | ||||||
|  | A0000003591010028001 Girocard EAPS | ||||||
|  | A0000003710001 InterSwitch Verve Card | ||||||
|  | A0000004540010 Etranzact Genesis Card | ||||||
|  | A0000004540011 Etranzact Genesis Card 2 | ||||||
|  | A0000004766C GOOGLE_PAYMENT | ||||||
|  | A0000005241010 RuPay | ||||||
|  | A0000006723010 TROY chip credit card | ||||||
|  | A0000006723020 TROY chip debit card | ||||||
|  | A0000007705850 XTRAPOWER | ||||||
|  | B012345678 Maestro TEST | ||||||
|  | D27600002545500100 Girocard | ||||||
|  | D5780000021010 Bankaxept | ||||||
|  | F0000000030001 BRADESCO | ||||||
|  | A000000003000000 (VISA) Card Manager | ||||||
|  | A000000003534441 Schlumberger SD | ||||||
|  | A0000000035350 Security Domain | ||||||
|  | A000000003535041 Security Domain | ||||||
|  | A0000000040000 MasterCard Card Manager | ||||||
|  | A000000018434D Gemplus card manager | ||||||
|  | A000000018434D00 Gemplus Security Domain | ||||||
|  | A0000000960200 Proton WISD | ||||||
|  | A0000001510000 Global Platform SD | ||||||
|  | A00000015153504341534400 CASD_AID | ||||||
|  | A000000476A010 GSD_MANAGER_AID | ||||||
|  | A000000476A110 GSD_MANAGER_AID | ||||||
|  | 315041592E5359532E4444463031 Visa PSE  | ||||||
|  | 325041592E5359532E4444463031 Visa PPSE | ||||||
|  | A0000000042203 MasterCard Specific | ||||||
|  | A0000000045555 APDULogger | ||||||
|  | A0000000090001FF44FF1289 Orange | ||||||
|  | A0000000101030 Maestro-CH | ||||||
|  | A00000001800 Gemplus | ||||||
|  | A0000000181001 gemplus util packages | ||||||
|  | A000000025010104 American Express | ||||||
|  | A00000002949034010100001 HSBC | ||||||
|  | A00000002949282010100000 Barclay | ||||||
|  | A00000005945430100 Girocard Electronic Cash | ||||||
|  | A0000000980840 Visa Common Debit | ||||||
|  | A0000001570010 AMEX | ||||||
|  | A0000001570020 MasterCard | ||||||
|  | A0000001570021 Maestro | ||||||
|  | A0000001570022 Maestro | ||||||
|  | A0000001570023 CASH | ||||||
|  | A0000001570030 VISA | ||||||
|  | A0000001570031 VISA | ||||||
|  | A0000001570040 JCB | ||||||
|  | A0000001570050 Postcard | ||||||
|  | A0000001570051 Postcard | ||||||
|  | A0000001570100 MCard | ||||||
|  | A0000001570104 MyOne | ||||||
|  | A000000157010C WIRCard | ||||||
|  | A000000157010D Power Card | ||||||
|  | A0000001574443 DINERS CLUB | ||||||
|  | A0000001574444 Supercard Plus | ||||||
|  | A00000022820101010 SPAN | ||||||
|  | A000000308000010000100 ID-ONE PIV BIO | ||||||
|  | A0000003241010 Discover Zip | ||||||
|  | A000000333010101 UnionPay Debit | ||||||
|  | A000000333010102 UnionPay Credit | ||||||
|  | A000000333010103 UnionPay Quasi Credit | ||||||
|  | A000000333010106 UnionPay Electronic Cash | ||||||
|  | A000000333010108 U.S. UnionPay Common Debit | ||||||
|  | A000000337102000 Classic | ||||||
|  | A000000337101001 Prepaye Online | ||||||
|  | A000000337102001 Prepaye Possibile Offiline | ||||||
|  | A000000337601001 Porte Monnaie Electronique | ||||||
|  | A0000006581010 MIR Credit | ||||||
|  | A0000006581011 MIR Credit | ||||||
|  | A0000006582010 MIR Debit | ||||||
|  | D040000001000002 Paylife Quick IEP | ||||||
|  | D040000002000002 RFU | ||||||
|  | D040000003000002 POS | ||||||
|  | D040000004000002 ATM | ||||||
|  | D04000000B000002 Retail | ||||||
|  | D04000000C000002 Bank_Data | ||||||
|  | D04000000D000002 Shopping | ||||||
|  | D040000013000001 DF_UNI_Kepler1 | ||||||
|  | D040000013000001 DF_Schüler1 | ||||||
|  | D040000013000002 DF_UNI_Kepler2 | ||||||
|  | D040000013000002 DF_Schüler2 | ||||||
|  | D040000014000001 DF_Mensa | ||||||
|  | D040000015000001 DF_UNI_Ausweis | ||||||
|  | D040000015000001 DF_Ausweis | ||||||
|  | D0400000190001 EMV ATM Maestro | ||||||
|  | D0400000190002 EMV POS Maestro | ||||||
|  | D0400000190003 EMV ATM MasterCard | ||||||
|  | D0400000190004 EMV POS MasterCard | ||||||
|  | D276000025 Girocard | ||||||
|  | D27600002547410100 Girocard ATM | ||||||
|  | D7560000010101 Reka Card | ||||||
|  | D7560000300101 M Budget | ||||||
							
								
								
									
										249
									
								
								assets/resources/nfc/emv/country_code.nfc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,249 @@ | |||||||
|  | 0004 AFG | ||||||
|  | 0008 ALB | ||||||
|  | 0010 ATA | ||||||
|  | 0012 DZA | ||||||
|  | 0016 ASM | ||||||
|  | 0020 AND | ||||||
|  | 0024 AGO | ||||||
|  | 0028 ATG | ||||||
|  | 0031 AZE | ||||||
|  | 0032 ARG | ||||||
|  | 0036 AUS | ||||||
|  | 0040 AUT | ||||||
|  | 0044 BHS | ||||||
|  | 0048 BHR | ||||||
|  | 0050 BGD | ||||||
|  | 0051 ARM | ||||||
|  | 0052 BRB | ||||||
|  | 0056 BEL | ||||||
|  | 0060 BMU | ||||||
|  | 0064 BTN | ||||||
|  | 0068 BOL | ||||||
|  | 0070 BIH | ||||||
|  | 0072 BWA | ||||||
|  | 0074 BVT | ||||||
|  | 0076 BRA | ||||||
|  | 0084 BLZ | ||||||
|  | 0086 IOT | ||||||
|  | 0090 SLB | ||||||
|  | 0092 VGB | ||||||
|  | 0096 BRN | ||||||
|  | 0100 BGR | ||||||
|  | 0104 MMR | ||||||
|  | 0108 BDI | ||||||
|  | 0112 BLR | ||||||
|  | 0116 KHM | ||||||
|  | 0120 CMR | ||||||
|  | 0124 CAN | ||||||
|  | 0132 CPV | ||||||
|  | 0136 CYM | ||||||
|  | 0140 CAF | ||||||
|  | 0144 LKA | ||||||
|  | 0148 TCD | ||||||
|  | 0152 CHL | ||||||
|  | 0156 CHN | ||||||
|  | 0158 TWN | ||||||
|  | 0162 CXR | ||||||
|  | 0166 CCK | ||||||
|  | 0170 COL | ||||||
|  | 0174 COM | ||||||
|  | 0175 MYT | ||||||
|  | 0178 COG | ||||||
|  | 0180 COD | ||||||
|  | 0184 COK | ||||||
|  | 0188 CRI | ||||||
|  | 0191 HRV | ||||||
|  | 0192 CUB | ||||||
|  | 0196 CYP | ||||||
|  | 0203 CZE | ||||||
|  | 0204 BEN | ||||||
|  | 0208 DNK | ||||||
|  | 0212 DMA | ||||||
|  | 0214 DOM | ||||||
|  | 0218 ECU | ||||||
|  | 0222 SLV | ||||||
|  | 0226 GNQ | ||||||
|  | 0231 ETH | ||||||
|  | 0232 ERI | ||||||
|  | 0233 EST | ||||||
|  | 0234 FRO | ||||||
|  | 0238 FLK | ||||||
|  | 0239 SGS | ||||||
|  | 0242 FJI | ||||||
|  | 0246 FIN | ||||||
|  | 0248 ALA | ||||||
|  | 0250 FRA | ||||||
|  | 0254 GUF | ||||||
|  | 0258 PYF | ||||||
|  | 0260 ATF | ||||||
|  | 0262 DJI | ||||||
|  | 0266 GAB | ||||||
|  | 0268 GEO | ||||||
|  | 0270 GMB | ||||||
|  | 0275 PSE | ||||||
|  | 0276 DEU | ||||||
|  | 0288 GHA | ||||||
|  | 0292 GIB | ||||||
|  | 0296 KIR | ||||||
|  | 0300 GRC | ||||||
|  | 0304 GRL | ||||||
|  | 0308 GRD | ||||||
|  | 0312 GLP | ||||||
|  | 0316 GUM | ||||||
|  | 0320 GTM | ||||||
|  | 0324 GIN | ||||||
|  | 0328 GUY | ||||||
|  | 0332 HTI | ||||||
|  | 0334 HMD | ||||||
|  | 0336 VAT | ||||||
|  | 0340 HND | ||||||
|  | 0344 HKG | ||||||
|  | 0348 HUN | ||||||
|  | 0352 ISL | ||||||
|  | 0356 IND | ||||||
|  | 0360 IDN | ||||||
|  | 0364 IRN | ||||||
|  | 0368 IRQ | ||||||
|  | 0372 IRL | ||||||
|  | 0376 ISR | ||||||
|  | 0380 ITA | ||||||
|  | 0384 CIV | ||||||
|  | 0388 JAM | ||||||
|  | 0392 JPN | ||||||
|  | 0398 KAZ | ||||||
|  | 0400 JOR | ||||||
|  | 0404 KEN | ||||||
|  | 0408 PRK | ||||||
|  | 0410 KOR | ||||||
|  | 0414 KWT | ||||||
|  | 0417 KGZ | ||||||
|  | 0418 LAO | ||||||
|  | 0422 LBN | ||||||
|  | 0426 LSO | ||||||
|  | 0428 LVA | ||||||
|  | 0430 LBR | ||||||
|  | 0434 LBY | ||||||
|  | 0438 LIE | ||||||
|  | 0440 LTU | ||||||
|  | 0442 LUX | ||||||
|  | 0446 MAC | ||||||
|  | 0450 MDG | ||||||
|  | 0454 MWI | ||||||
|  | 0458 MYS | ||||||
|  | 0462 MDV | ||||||
|  | 0466 MLI | ||||||
|  | 0470 MLT | ||||||
|  | 0474 MTQ | ||||||
|  | 0478 MRT | ||||||
|  | 0480 MUS | ||||||
|  | 0484 MEX | ||||||
|  | 0492 MCO | ||||||
|  | 0496 MNG | ||||||
|  | 0498 MDA | ||||||
|  | 0499 MNE | ||||||
|  | 0500 MSR | ||||||
|  | 0504 MAR | ||||||
|  | 0508 MOZ | ||||||
|  | 0512 OMN | ||||||
|  | 0516 NAM | ||||||
|  | 0520 NRU | ||||||
|  | 0524 NPL | ||||||
|  | 0528 NLD | ||||||
|  | 0531 CUW | ||||||
|  | 0533 ABW | ||||||
|  | 0534 SXM | ||||||
|  | 0535 BES | ||||||
|  | 0540 NCL | ||||||
|  | 0548 VUT | ||||||
|  | 0554 NZL | ||||||
|  | 0558 NIC | ||||||
|  | 0562 NER | ||||||
|  | 0566 NGA | ||||||
|  | 0570 NIU | ||||||
|  | 0574 NFK | ||||||
|  | 0578 NOR | ||||||
|  | 0580 MNP | ||||||
|  | 0581 UMI | ||||||
|  | 0583 FSM | ||||||
|  | 0584 MHL | ||||||
|  | 0585 PLW | ||||||
|  | 0586 PAK | ||||||
|  | 0591 PAN | ||||||
|  | 0598 PNG | ||||||
|  | 0600 PRY | ||||||
|  | 0604 PER | ||||||
|  | 0608 PHL | ||||||
|  | 0612 PCN | ||||||
|  | 0616 POL | ||||||
|  | 0620 PRT | ||||||
|  | 0624 GNB | ||||||
|  | 0626 TLS | ||||||
|  | 0630 PRI | ||||||
|  | 0634 QAT | ||||||
|  | 0638 REU | ||||||
|  | 0642 ROU | ||||||
|  | 0643 RUS | ||||||
|  | 0646 RWA | ||||||
|  | 0652 BLM | ||||||
|  | 0654 SHN | ||||||
|  | 0659 KNA | ||||||
|  | 0660 AIA | ||||||
|  | 0662 LCA | ||||||
|  | 0663 MAF | ||||||
|  | 0666 SPM | ||||||
|  | 0670 VCT | ||||||
|  | 0674 SMR | ||||||
|  | 0678 STP | ||||||
|  | 0682 SAU | ||||||
|  | 0686 SEN | ||||||
|  | 0688 SRB | ||||||
|  | 0690 SYC | ||||||
|  | 0694 SLE | ||||||
|  | 0702 SGP | ||||||
|  | 0703 SVK | ||||||
|  | 0704 VNM | ||||||
|  | 0705 SVN | ||||||
|  | 0706 SOM | ||||||
|  | 0710 ZAF | ||||||
|  | 0716 ZWE | ||||||
|  | 0724 ESP | ||||||
|  | 0728 SSD | ||||||
|  | 0729 SDN | ||||||
|  | 0732 ESH | ||||||
|  | 0740 SUR | ||||||
|  | 0744 SJM | ||||||
|  | 0748 SWZ | ||||||
|  | 0752 SWE | ||||||
|  | 0756 CHE | ||||||
|  | 0760 SYR | ||||||
|  | 0762 TJK | ||||||
|  | 0764 THA | ||||||
|  | 0768 TGO | ||||||
|  | 0772 TKL | ||||||
|  | 0776 TON | ||||||
|  | 0780 TTO | ||||||
|  | 0784 ARE | ||||||
|  | 0788 TUN | ||||||
|  | 0792 TUR | ||||||
|  | 0795 TKM | ||||||
|  | 0796 TCA | ||||||
|  | 0798 TUV | ||||||
|  | 0800 UGA | ||||||
|  | 0804 UKR | ||||||
|  | 0807 MKD | ||||||
|  | 0818 EGY | ||||||
|  | 0826 GBR | ||||||
|  | 0831 GGY | ||||||
|  | 0832 JEY | ||||||
|  | 0833 IMN | ||||||
|  | 0834 TZA | ||||||
|  | 0840 USA | ||||||
|  | 0850 VIR | ||||||
|  | 0854 BFA | ||||||
|  | 0858 URY | ||||||
|  | 0860 UZB | ||||||
|  | 0862 VEN | ||||||
|  | 0876 WLF | ||||||
|  | 0882 WSM | ||||||
|  | 0887 YEM | ||||||
|  | 0894 ZMB | ||||||
							
								
								
									
										168
									
								
								assets/resources/nfc/emv/currency_code.nfc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,168 @@ | |||||||
|  | 0997 USN | ||||||
|  | 0994 XSU | ||||||
|  | 0990 CLF | ||||||
|  | 0986 BRL | ||||||
|  | 0985 PLN | ||||||
|  | 0984 BOV | ||||||
|  | 0981 GEL | ||||||
|  | 0980 UAH | ||||||
|  | 0979 MXV | ||||||
|  | 0978 EUR | ||||||
|  | 0977 BAM | ||||||
|  | 0976 CDF | ||||||
|  | 0975 BGN | ||||||
|  | 0973 AOA | ||||||
|  | 0972 TJS | ||||||
|  | 0971 AFN | ||||||
|  | 0970 COU | ||||||
|  | 0969 MGA | ||||||
|  | 0968 SRD | ||||||
|  | 0967 ZMW | ||||||
|  | 0965 XUA | ||||||
|  | 0960 XDR | ||||||
|  | 0953 XPF | ||||||
|  | 0952 XOF | ||||||
|  | 0951 XCD | ||||||
|  | 0950 XAF | ||||||
|  | 0949 TRY | ||||||
|  | 0948 CHW | ||||||
|  | 0947 CHE | ||||||
|  | 0946 RON | ||||||
|  | 0944 AZN | ||||||
|  | 0943 MZN | ||||||
|  | 0941 RSD | ||||||
|  | 0940 UYI | ||||||
|  | 0938 SDG | ||||||
|  | 0937 VEF | ||||||
|  | 0936 GHS | ||||||
|  | 0934 TMT | ||||||
|  | 0933 BYN | ||||||
|  | 0932 ZWL | ||||||
|  | 0931 CUC | ||||||
|  | 0930 STN | ||||||
|  | 0929 MRU | ||||||
|  | 0901 TWD | ||||||
|  | 0886 YER | ||||||
|  | 0882 WST | ||||||
|  | 0860 UZS | ||||||
|  | 0858 UYU | ||||||
|  | 0840 USD | ||||||
|  | 0834 TZS | ||||||
|  | 0826 GBP | ||||||
|  | 0818 EGP | ||||||
|  | 0807 MKD | ||||||
|  | 0800 UGX | ||||||
|  | 0788 TND | ||||||
|  | 0784 AED | ||||||
|  | 0780 TTD | ||||||
|  | 0776 TOP | ||||||
|  | 0764 THB | ||||||
|  | 0760 SYP | ||||||
|  | 0756 CHF | ||||||
|  | 0752 SEK | ||||||
|  | 0748 SZL | ||||||
|  | 0728 SSP | ||||||
|  | 0710 ZAR | ||||||
|  | 0706 SOS | ||||||
|  | 0704 VND | ||||||
|  | 0702 SGD | ||||||
|  | 0694 SLL | ||||||
|  | 0690 SCR | ||||||
|  | 0682 SAR | ||||||
|  | 0654 SHP | ||||||
|  | 0646 RWF | ||||||
|  | 0643 RUB | ||||||
|  | 0634 QAR | ||||||
|  | 0608 PHP | ||||||
|  | 0604 PEN | ||||||
|  | 0600 PYG | ||||||
|  | 0598 PGK | ||||||
|  | 0590 PAB | ||||||
|  | 0586 PKR | ||||||
|  | 0578 NOK | ||||||
|  | 0566 NGN | ||||||
|  | 0558 NIO | ||||||
|  | 0554 NZD | ||||||
|  | 0548 VUV | ||||||
|  | 0533 AWG | ||||||
|  | 0532 ANG | ||||||
|  | 0524 NPR | ||||||
|  | 0516 NAD | ||||||
|  | 0512 OMR | ||||||
|  | 0504 MAD | ||||||
|  | 0498 MDL | ||||||
|  | 0496 MNT | ||||||
|  | 0484 MXN | ||||||
|  | 0480 MUR | ||||||
|  | 0462 MVR | ||||||
|  | 0458 MYR | ||||||
|  | 0454 MWK | ||||||
|  | 0446 MOP | ||||||
|  | 0434 LYD | ||||||
|  | 0430 LRD | ||||||
|  | 0426 LSL | ||||||
|  | 0422 LBP | ||||||
|  | 0418 LAK | ||||||
|  | 0417 KGS | ||||||
|  | 0414 KWD | ||||||
|  | 0410 KRW | ||||||
|  | 0408 KPW | ||||||
|  | 0404 KES | ||||||
|  | 0400 JOD | ||||||
|  | 0398 KZT | ||||||
|  | 0392 JPY | ||||||
|  | 0388 JMD | ||||||
|  | 0376 ILS | ||||||
|  | 0368 IQD | ||||||
|  | 0364 IRR | ||||||
|  | 0360 IDR | ||||||
|  | 0356 INR | ||||||
|  | 0352 ISK | ||||||
|  | 0348 HUF | ||||||
|  | 0344 HKD | ||||||
|  | 0340 HNL | ||||||
|  | 0332 HTG | ||||||
|  | 0328 GYD | ||||||
|  | 0324 GNF | ||||||
|  | 0320 GTQ | ||||||
|  | 0292 GIP | ||||||
|  | 0270 GMD | ||||||
|  | 0262 DJF | ||||||
|  | 0242 FJD | ||||||
|  | 0238 FKP | ||||||
|  | 0232 ERN | ||||||
|  | 0230 ETB | ||||||
|  | 0222 SVC | ||||||
|  | 0214 DOP | ||||||
|  | 0208 DKK | ||||||
|  | 0203 CZK | ||||||
|  | 0192 CUP | ||||||
|  | 0191 HRK | ||||||
|  | 0188 CRC | ||||||
|  | 0174 KMF | ||||||
|  | 0170 COP | ||||||
|  | 0156 CNY | ||||||
|  | 0152 CLP | ||||||
|  | 0144 LKR | ||||||
|  | 0136 KYD | ||||||
|  | 0132 CVE | ||||||
|  | 0124 CAD | ||||||
|  | 0116 KHR | ||||||
|  | 0108 BIF | ||||||
|  | 0104 MMK | ||||||
|  | 0096 BND | ||||||
|  | 0090 SBD | ||||||
|  | 0084 BZD | ||||||
|  | 0072 BWP | ||||||
|  | 0068 BOB | ||||||
|  | 0064 BTN | ||||||
|  | 0060 BMD | ||||||
|  | 0052 BBD | ||||||
|  | 0051 AMD | ||||||
|  | 0050 BDT | ||||||
|  | 0048 BHD | ||||||
|  | 0044 BSD | ||||||
|  | 0036 AUD | ||||||
|  | 0032 ARS | ||||||
|  | 0012 DZD | ||||||
|  | 0008 ALL | ||||||
| @ -13,13 +13,57 @@ | |||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| #include <u8g2.h> | #include <u8g2.h> | ||||||
| 
 | 
 | ||||||
| const uint8_t I_Warning_30x23_0[] = { | const uint8_t I_DFU_128x50[] = { | ||||||
|     0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xF0, 0x03, 0x00, |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0x00, | ||||||
|     0x00, 0xF8, 0x07, 0x00, 0x00, 0x3C, 0x0F, 0x00, 0x00, 0x3C, 0x0F, 0x00, 0x00, 0x3E, 0x1F, 0x00, |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x00, 0x00, | ||||||
|     0x00, 0x3F, 0x3F, 0x00, 0x00, 0x3F, 0x3F, 0x00, 0x80, 0x3F, 0x7F, 0x00, 0xC0, 0x3F, 0xFF, 0x00, |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x00, 0x00, 0x00, | ||||||
|     0xC0, 0x3F, 0xFF, 0x00, 0xE0, 0x3F, 0xFF, 0x01, 0xF0, 0x3F, 0xFF, 0x03, 0xF0, 0x3F, 0xFF, 0x03, |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, | ||||||
|     0xF8, 0x3F, 0xFF, 0x07, 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xFE, 0x3F, 0xFF, 0x1F, |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, | ||||||
|     0xFF, 0x3F, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x1F, |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x75, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0A, 0x00, 0x00, 0x0F, 0x60, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xE0, 0x0F, 0x00, 0xC0, 0xE0, 0x4F, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x30, 0x1E, 0x90, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x8C, 0x01, 0xA0, 0x00, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0xFF, 0x19, 0x00, 0x63, 0x00, 0xC0, 0xF0, 0x07, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x5E, 0x1F, 0x80, 0x18, 0x00, 0xE0, 0x0E, 0x18, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x18, 0xAF, 0x0F, 0x40, 0x06, 0x00, 0xF8, 0x01, 0x20, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x57, 0x01, 0x20, 0x01, 0x00, 0x78, 0x00, 0x3E, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x81, 0xAF, 0x02, 0x90, 0x00, 0x00, 0x38, 0x80, 0x41, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x80, 0x57, 0x01, 0x48, 0x00, 0x00, 0x10, 0x60, 0x40, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x10, 0x80, 0xAB, 0x00, 0x24, 0x00, 0x00, 0x08, 0x10, 0x40, | ||||||
|  |     0x3F, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0C, 0xC0, 0x57, 0x01, 0x12, 0x00, 0x00, 0x04, 0x08, 0x40, | ||||||
|  |     0xC0, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x03, 0xF0, 0xAB, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x04, 0x40, | ||||||
|  |     0x00, 0xF0, 0x1F, 0x80, 0x3F, 0xC0, 0x00, 0xFC, 0x55, 0x01, 0x05, 0xE0, 0x00, 0x01, 0x04, 0x40, | ||||||
|  |     0x00, 0x00, 0xE0, 0x7F, 0x00, 0x30, 0x00, 0xFF, 0xAB, 0x00, 0x05, 0xE0, 0x80, 0x00, 0x02, 0x40, | ||||||
|  |     0x0F, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xE0, 0xCF, 0x55, 0x81, 0x02, 0xF0, 0x40, 0x00, 0x02, 0x40, | ||||||
|  |     0xF0, 0x0F, 0x00, 0x00, 0x7F, 0x00, 0xFE, 0xC3, 0xAB, 0x80, 0x02, 0x78, 0x20, 0x00, 0x01, 0x40, | ||||||
|  |     0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xC0, 0xD5, 0x81, 0x01, 0x7E, 0x10, 0x80, 0x00, 0x20, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0xE0, 0xFA, 0x83, 0xC1, 0x3F, 0x08, 0x80, 0x00, 0x20, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0xD8, 0x07, 0x83, 0xF1, 0x1F, 0x04, 0x40, 0x00, 0x20, | ||||||
|  |     0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0x80, 0xC7, 0x01, 0x83, 0xF1, 0x0F, 0x00, 0x20, 0x00, 0x10, | ||||||
|  |     0xE0, 0xFF, 0xFF, 0xFF, 0x3F, 0xC0, 0x7F, 0x40, 0x80, 0x83, 0xE1, 0x01, 0x00, 0x20, 0x00, 0x18, | ||||||
|  |     0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x00, 0x20, 0xFC, 0x83, 0x01, 0x00, 0x00, 0x10, 0x00, 0x18, | ||||||
|  |     0xFF, 0xFF, 0xFF, 0x3F, 0xF0, 0x00, 0x00, 0x10, 0xD7, 0x01, 0x03, 0x00, 0x00, 0x08, 0x00, 0x1C, | ||||||
|  |     0xFF, 0xFF, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x88, 0xAB, 0x02, 0xE3, 0x01, 0x00, 0x08, 0x00, 0x0C, | ||||||
|  |     0xFF, 0x07, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC4, 0x55, 0x05, 0x1E, 0x00, 0x00, 0x04, 0x00, 0x0E, | ||||||
|  |     0x7F, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xA3, 0xAB, 0x02, 0x06, 0x00, 0x00, 0x02, 0x00, 0x0F, | ||||||
|  |     0x0F, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x10, 0x57, 0x05, 0x02, 0x00, 0x00, 0x01, 0x80, 0x07, | ||||||
|  |     0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0x08, 0xAB, 0x0A, 0x02, 0x00, 0xC0, 0x00, 0xC0, 0x07, | ||||||
|  |     0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x84, 0x57, 0x15, 0x01, 0x00, 0x30, 0x00, 0xE0, 0x07, | ||||||
|  |     0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0xC3, 0xFF, 0x2A, 0x01, 0x00, 0x0C, 0x00, 0xF0, 0x0F, | ||||||
|  |     0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0xE0, 0xFE, 0x55, 0x01, 0x82, 0x03, 0x00, 0xF8, 0x15, | ||||||
|  |     0x00, 0x30, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x78, 0xFE, 0xAA, 0x01, 0x7C, 0x00, 0x00, 0xFC, 0x23, | ||||||
|  |     0x00, 0x0E, 0x00, 0x00, 0xC0, 0x03, 0x0C, 0x3C, 0x7F, 0x5D, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x45, | ||||||
|  |     0xC0, 0x01, 0x00, 0x00, 0x3E, 0x00, 0x02, 0x8F, 0xBF, 0xAE, 0x03, 0x00, 0x00, 0xC0, 0xFF, 0x82, | ||||||
|  |     0x30, 0x00, 0x00, 0xC0, 0x01, 0x80, 0xC1, 0x43, 0xFE, 0x5D, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x05, | ||||||
|  |     0x0F, 0x00, 0x80, 0x3F, 0x00, 0x60, 0xF0, 0x31, 0xF6, 0xAE, 0x03, 0x00, 0x00, 0xFA, 0xAF, 0x02, | ||||||
|  |     0xFC, 0xFF, 0x7F, 0x00, 0x00, 0x18, 0x7C, 0x08, 0x23, 0xFF, 0x05, 0x00, 0x00, 0xFD, 0x55, 0x01, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x1F, 0x84, 0x30, 0xFE, 0x0A, 0x00, 0x00, 0xAA, 0xAA, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0x80, 0xF1, 0x07, 0x43, 0x18, 0xFF, 0x15, 0x00, 0x00, 0x54, 0x15, 0x00, | ||||||
|  |     0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x80, 0x20, 0x8C, 0xFF, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // Boot request enum
 | // Boot request enum
 | ||||||
| @ -138,8 +182,6 @@ void target_version_save(void) { | |||||||
| 
 | 
 | ||||||
| void target_usb_wire_reset() { | void target_usb_wire_reset() { | ||||||
|     LL_GPIO_ResetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN); |     LL_GPIO_ResetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN); | ||||||
|     LL_mDelay(10); |  | ||||||
|     LL_GPIO_SetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void target_display_init() { | void target_display_init() { | ||||||
| @ -155,10 +197,9 @@ void target_display_init() { | |||||||
|     u8g2_ClearBuffer(&fb); |     u8g2_ClearBuffer(&fb); | ||||||
|     u8g2_SetDrawColor(&fb, 0x01); |     u8g2_SetDrawColor(&fb, 0x01); | ||||||
|     u8g2_SetFont(&fb, u8g2_font_helvB08_tf); |     u8g2_SetFont(&fb, u8g2_font_helvB08_tf); | ||||||
|     u8g2_DrawStr(&fb, 2, 8, "Recovery & Update Mode"); |     u8g2_DrawXBM(&fb, 0, 64 - 50, 128, 50, I_DFU_128x50); | ||||||
|     u8g2_DrawXBM(&fb, 49, 14, 30, 23, I_Warning_30x23_0); |     u8g2_DrawStr(&fb, 2, 8, "Update & Recovery Mode"); | ||||||
|     u8g2_DrawStr(&fb, 2, 50, "DFU Bootloader activated"); |     u8g2_DrawStr(&fb, 2, 21, "DFU started"); | ||||||
|     u8g2_DrawStr(&fb, 6, 62, "www.flipp.dev/recovery"); |  | ||||||
|     // Send buffer
 |     // Send buffer
 | ||||||
|     u8g2_SetPowerSave(&fb, 0); |     u8g2_SetPowerSave(&fb, 0); | ||||||
|     u8g2_SendBuffer(&fb); |     u8g2_SendBuffer(&fb); | ||||||
|  | |||||||
| @ -1,144 +0,0 @@ | |||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| struct used for handling SPI info. |  | ||||||
| */ |  | ||||||
| typedef struct { |  | ||||||
|     SPI_HandleTypeDef* spi; |  | ||||||
|     PubSubCallback cb; |  | ||||||
|     void* ctx; |  | ||||||
| } SpiHandle; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| For transmit/receive data use `spi_xfer` function. |  | ||||||
| 
 |  | ||||||
| * `tx_data` and `rx_data` size must be equal (and equal `len`) |  | ||||||
| * `cb` called after spi operation is completed, `(NULL, ctx)` passed to callback. |  | ||||||
| */ |  | ||||||
| bool spi_xfer( |  | ||||||
|     SPI_HandleTypeDef* spi, |  | ||||||
|     uint8_t* tx_data, |  | ||||||
|     uint8_t* rx_data, |  | ||||||
|     size_t len, |  | ||||||
|     PubSubCallback cb, |  | ||||||
|     void* ctx); |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| Blocking verison: |  | ||||||
| */ |  | ||||||
| static inline bool |  | ||||||
|     spi_xfer_block(SPI_HandleTypeDef* spi, uint8_t* tx_data, uint8_t* rx_data, size_t len) { |  | ||||||
|     semaphoreInfo s; |  | ||||||
|     osSemaphore block = createSemaphoreStatic(s); |  | ||||||
|     if(!spi_xfer(spi, tx_data, rx_data, len, RELEASE_SEMAPHORE, (void*)block)) { |  | ||||||
|         osReleaseSemaphore(block); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     osWaitSemaphore(block); |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| Common implementation of SPI bus: serial interface + CS pin |  | ||||||
| */ |  | ||||||
| typedef struct { |  | ||||||
|     GpioPin* cs; ///< CS pin
 |  | ||||||
|     ValueMutex* spi; ///< <SpiHandle*>
 |  | ||||||
| } SpiBus; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| For dedicated work with one device there is `SpiDevice` entity. |  | ||||||
| It contains ValueMutex around SpiBus: after you acquire device |  | ||||||
| you can acquire spi to work with it (don't forget SPI bus is shared |  | ||||||
| around many device, release it after every transaction as quick as possible). |  | ||||||
| */ |  | ||||||
| typedef struct { |  | ||||||
|     ValueMutex* bus; ///< <SpiBus*>
 |  | ||||||
| } SpiDevice; |  | ||||||
| 
 |  | ||||||
| ##SPI IRQ device |  | ||||||
| 
 |  | ||||||
|     /*
 |  | ||||||
| Many devices (like CC1101 and NFC) present as SPI bus and IRQ line. |  | ||||||
| For work with it there is special entity `SpiIrqDevice`. |  | ||||||
| Use `subscribe_pubsub` for subscribinq to irq events. |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
|     typedef struct { |  | ||||||
|     ValueMutex* bus; ///< <SpiBus*>
 |  | ||||||
|     PubSub* irq; |  | ||||||
| } SpiIrqDevice; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| Special implementation of SPI bus: serial interface + CS, Res, D/I lines. |  | ||||||
| */ |  | ||||||
| typedef struct { |  | ||||||
|     GpioPin* cs; ///< CS pin
 |  | ||||||
|     GpioPin* res; ///< reset pin
 |  | ||||||
|     GpioPin* di; ///< D/I pin
 |  | ||||||
|     ValueMutex* spi; ///< <SPI_HandleTypeDef*>
 |  | ||||||
| } DisplayBus; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     ValueMutex* bus; ///< <DisplayBus*>
 |  | ||||||
| } DisplayDevice; |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
| # SPI devices (F2) |  | ||||||
| 
 |  | ||||||
| * `/dev/sdcard` - SD card SPI, `SpiDevice` |  | ||||||
| * `/dev/cc1101_bus` - Sub-GHz radio (CC1101), `SpiIrqDevice` |  | ||||||
| * `/dev/nfc` - NFC (ST25R3916), `SpiIrqDevice` |  | ||||||
| * `/dev/display` - `DisplayDevice` |  | ||||||
| * `/dev/spiext` - External SPI (warning! Lock PA4, PA5, PA6, PA7) |  | ||||||
| 
 |  | ||||||
| ### Application example |  | ||||||
| 
 |  | ||||||
| ```C |  | ||||||
| // Be careful, this function called from IRQ context
 |  | ||||||
| void handle_irq(void* _arg, void* _ctx) { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void cc1101_example() { |  | ||||||
|     SpiIrqDevice* cc1101_device = open_input("/dev/cc1101_bus"); |  | ||||||
|     if(cc1101_device == NULL) return; // bus not available, critical error
 |  | ||||||
| 
 |  | ||||||
|     subscribe_pubsub(cc1101_device->irq, handle_irq, NULL); |  | ||||||
| 
 |  | ||||||
|     { |  | ||||||
|         // acquire device as device bus
 |  | ||||||
|         SpiBus* spi_bus = acquire_mutex(cc1101_device->bus, 0); |  | ||||||
|         if(spi_bus == NULL) { |  | ||||||
|             printf("Device busy\n"); |  | ||||||
|             // wait for device
 |  | ||||||
|             spi_bus = acquire_mutex_block(cc1101_device->bus); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // make transaction
 |  | ||||||
|         uint8_t request[4] = {0xDE, 0xAD, 0xBE, 0xEF}; |  | ||||||
|         uint8_t response[4]; |  | ||||||
| 
 |  | ||||||
|         { |  | ||||||
|             SPI_HandleTypeDef* spi = acquire_mutex_block(spi_bus->spi); |  | ||||||
| 
 |  | ||||||
|             gpio_write(spi_bus->cs, false); |  | ||||||
|             spi_xfer_block(spi, request, response, 4); |  | ||||||
|             gpio_write(spi_bus->cs, true); |  | ||||||
| 
 |  | ||||||
|             release_mutex(cc1101_device->spi, spi); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // release device (device bus)
 |  | ||||||
|         release_mutex(cc1101_device->bus, spi_bus); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| @ -1,37 +1,30 @@ | |||||||
| #include "check.h" | #include "check.h" | ||||||
| #include "furi-hal-task.h" | #include "furi-hal-task.h" | ||||||
|  | #include <furi-hal-console.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| void __furi_abort(void); | void __furi_abort(void); | ||||||
| 
 | 
 | ||||||
| // TODO printf doesnt work in ISR context
 | void __furi_print_name(void) { | ||||||
| void __furi_check(void) { |     furi_hal_console_puts("\r\n\033[0;31m[E]"); | ||||||
|     printf("assertion failed in release mode, switch to debug mode to see full assert info"); |     if(task_is_isr_context()) { | ||||||
|     __furi_abort(); |         furi_hal_console_puts("[ISR] "); | ||||||
|  |     } else { | ||||||
|  |         const char* name = osThreadGetName(osThreadGetId()); | ||||||
|  |         if(name == NULL) { | ||||||
|  |             furi_hal_console_puts("[main] "); | ||||||
|  |         } else { | ||||||
|  |             furi_hal_console_puts("["); | ||||||
|  |             furi_hal_console_puts(name); | ||||||
|  |             furi_hal_console_puts("] "); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     furi_hal_console_puts("\033[0m"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO printf doesnt work in ISR context
 | void __furi_check(void) { | ||||||
| void __furi_check_debug(const char* file, int line, const char* function, const char* condition) { |     __furi_print_name(); | ||||||
|     printf( |     furi_hal_console_puts("assertion failed\r\n"); | ||||||
|         "assertion \"%s\" failed: file \"%s\", line %d%s%s", |  | ||||||
|         condition, |  | ||||||
|         file, |  | ||||||
|         line, |  | ||||||
|         function ? ", function: " : "", |  | ||||||
|         function ? function : ""); |  | ||||||
| 
 |  | ||||||
|     if(task_is_isr_context()) { |  | ||||||
|         printf(" in [ISR] context"); |  | ||||||
|     } else { |  | ||||||
|         // FuriApp* app = find_task(xTaskGetCurrentTaskHandle());
 |  | ||||||
| 
 |  | ||||||
|         // if(app == NULL) {
 |  | ||||||
|         //     printf(", in [main] context");
 |  | ||||||
|         // } else {
 |  | ||||||
|         //     printf(", in [%s] app context", app->name);
 |  | ||||||
|         // }
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     __furi_abort(); |     __furi_abort(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,7 +38,6 @@ extern "C" { | |||||||
| // !NDEBUG
 | // !NDEBUG
 | ||||||
| 
 | 
 | ||||||
| void __furi_check(void); | void __furi_check(void); | ||||||
| void __furi_check_debug(const char* file, int line, const char* function, const char* condition); |  | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -31,3 +31,12 @@ | |||||||
| #ifndef COUNT_OF | #ifndef COUNT_OF | ||||||
| #define COUNT_OF(x) (sizeof(x) / sizeof(x[0])) | #define COUNT_OF(x) (sizeof(x) / sizeof(x[0])) | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef FURI_SWAP | ||||||
|  | #define FURI_SWAP(x, y)     \ | ||||||
|  |     do {                    \ | ||||||
|  |         typeof(x) SWAP = x; \ | ||||||
|  |         x = y;              \ | ||||||
|  |         y = SWAP;           \ | ||||||
|  |     } while(0) | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -1,10 +1,10 @@ | |||||||
| FROM ubuntu:focal | FROM ubuntu:hirsute | ||||||
| 
 | 
 | ||||||
| RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ | RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ | ||||||
|         ca-certificates \ |         ca-certificates \ | ||||||
|         build-essential \ |         build-essential \ | ||||||
|         python3 \ |         python3 \ | ||||||
|         python-lxml \ |         python3-lxml \ | ||||||
|         git \ |         git \ | ||||||
|         clang-format-12 \ |         clang-format-12 \ | ||||||
|         dfu-util \ |         dfu-util \ | ||||||
| @ -14,10 +14,10 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-instal | |||||||
|         wget && \ |         wget && \ | ||||||
|     apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* |     apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* | ||||||
| 
 | 
 | ||||||
| RUN wget --progress=dot:giga "https://developer.arm.com/-/media/Files/downloads/gnu-rm/10-2020q4/gcc-arm-none-eabi-10-2020-q4-major-$(uname -m)-linux.tar.bz2" && \ | RUN wget --progress=dot:giga "https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.07/gcc-arm-none-eabi-10.3-2021.07-$(uname -m)-linux.tar.bz2" && \ | ||||||
|     tar xjf gcc-arm-none-eabi-10-2020-q4-major-$(uname -m)-linux.tar.bz2 && \ |     tar xjf gcc-arm-none-eabi-10.3-2021.07-$(uname -m)-linux.tar.bz2 && \ | ||||||
|     rm gcc-arm-none-eabi-10-2020-q4-major-$(uname -m)-linux.tar.bz2 && \ |     rm gcc-arm-none-eabi-10.3-2021.07-$(uname -m)-linux.tar.bz2 && \ | ||||||
|     cd gcc-arm-none-eabi-10-2020-q4-major/bin/ && \ |     cd gcc-arm-none-eabi-10.3-2021.07/bin/ && \ | ||||||
|     rm -rf ../share && \ |     rm -rf ../share && \ | ||||||
|     for file in * ; do ln -s "${PWD}/${file}" "/usr/bin/${file}" ; done && \ |     for file in * ; do ln -s "${PWD}/${file}" "/usr/bin/${file}" ; done && \ | ||||||
|     cd / && arm-none-eabi-gcc -v && arm-none-eabi-gdb -v |     cd / && arm-none-eabi-gcc -v && arm-none-eabi-gdb -v | ||||||
|  | |||||||
 Aleksandr Kutuzov
						Aleksandr Kutuzov