Merge branch 'release-candidate' into release

This commit is contained in:
Aleksandr Kutuzov 2021-09-03 01:45:03 +03:00
commit 97e0a3026f
188 changed files with 5996 additions and 4041 deletions

View File

@ -32,6 +32,7 @@ jobs:
with:
fetch-depth: 0
submodules: true
ref: ${{ github.event.pull_request.head.sha }}
- name: 'Docker cache'
uses: satackey/action-docker-layer-caching@v0.0.11
@ -47,14 +48,28 @@ jobs:
run: |
test -d artifacts && rm -rf artifacts || true
mkdir artifacts
- name: 'Generate tag suffix'
if: startsWith(github.ref, 'refs/tags/') == true
run: echo "SUFFIX=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
- name: 'Generate branch suffix'
if: startsWith(github.ref, 'refs/tags/') != true
run: echo "SUFFIX=$(git rev-parse --abbrev-ref HEAD)-$(date +'%d%m%Y')-$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: 'Generate suffix and folder name'
id: names
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)
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
SUFFIX=${BRANCH_OR_TAG}
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'
uses: ./.github/actions/docker
@ -95,17 +110,17 @@ jobs:
for TARGET in ${TARGETS}
do
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 \
artifacts/flipper-z-${TARGET}-bootloader-${SUFFIX}.bin
artifacts/flipper-z-${TARGET}-bootloader-${{steps.names.outputs.suffix}}.bin
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 \
artifacts/flipper-z-${TARGET}-firmware-${SUFFIX}.dfu
artifacts/flipper-z-${TARGET}-firmware-${{steps.names.outputs.suffix}}.dfu
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 \
artifacts/flipper-z-${TARGET}-firmware-${SUFFIX}.elf
artifacts/flipper-z-${TARGET}-firmware-${{steps.names.outputs.suffix}}.elf
done
- name: 'Generate full dfu file'
@ -117,7 +132,7 @@ jobs:
do
hex2dfu \
-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)"
done
@ -127,8 +142,8 @@ jobs:
for TARGET in ${TARGETS}
do
cp \
artifacts/flipper-z-${TARGET}-bootloader-${SUFFIX}.bin \
artifacts/flipper-z-${TARGET}-full-${SUFFIX}.bin
artifacts/flipper-z-${TARGET}-bootloader-${{steps.names.outputs.suffix}}.bin \
artifacts/flipper-z-${TARGET}-full-${{steps.names.outputs.suffix}}.bin
done
- name: 'Full flash asssembly: bootloader padding'
@ -136,7 +151,7 @@ jobs:
run: |
for TARGET in ${TARGETS}
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
- name: 'Full flash asssembly: append firmware'
@ -145,8 +160,8 @@ jobs:
for TARGET in ${TARGETS}
do
cat \
artifacts/flipper-z-${TARGET}-firmware-${SUFFIX}.bin \
>> artifacts/flipper-z-${TARGET}-full-${SUFFIX}.bin
artifacts/flipper-z-${TARGET}-firmware-${{steps.names.outputs.suffix}}.bin \
>> artifacts/flipper-z-${TARGET}-full-${{steps.names.outputs.suffix}}.bin
done
- 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_BLE_Stack_full_fw.bin \
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'
if: ${{ !github.event.pull_request.head.repo.fork }}
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'
if: ${{ !github.event.pull_request.head.repo.fork }}
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'
if: ${{ !github.event.pull_request.head.repo.fork }}
@ -178,7 +193,7 @@ jobs:
with:
switches: -avzP --delete
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_port: ${{ secrets.RSYNC_DEPLOY_PORT }}
remote_user: ${{ secrets.RSYNC_DEPLOY_USER }}
@ -190,3 +205,21 @@ jobs:
with:
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

View File

@ -43,19 +43,19 @@ jobs:
- name: 'Build docker image'
uses: ./.github/actions/docker
- name: 'Check syntax'
- name: 'Check code formatting'
id: syntax_check
uses: ./.github/actions/docker
with:
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
uses: peter-evans/create-or-update-comment@v1
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Please fix following syntax errors:
Please fix following code formatting errors:
```
${{ steps.syntax_check.outputs.errors }}
```

View File

@ -35,7 +35,6 @@ AccessorApp::AccessorApp()
: onewire_master{&ibutton_gpio} {
furi_hal_power_insomnia_enter();
notification = static_cast<NotificationApp*>(furi_record_open("notification"));
notify_init();
furi_hal_power_enable_otg();
}
@ -104,17 +103,6 @@ AccessorApp::Scene AccessorApp::get_previous_scene() {
/***************************** 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() {
notification_message(notification, &sequence_blink_green_10);
}

View File

@ -29,9 +29,7 @@ public:
bool switch_to_previous_scene(uint8_t count = 1);
Scene get_previous_scene();
void notify_init();
void notify_green_blink();
void notify_success();
char* get_text_store();

View File

@ -148,7 +148,7 @@ const FlipperApplication FLIPPER_APPS[] = {
#endif
#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
#ifdef APP_LF_RFID

View File

@ -2,20 +2,6 @@
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) {
furi_assert(archive);
@ -92,6 +78,7 @@ static void archive_leave_dir(ArchiveApp* archive) {
});
archive_switch_dir(archive, string_get_cstr(archive->browser.path));
update_offset(archive);
}
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(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;
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;
File* directory = storage_file_alloc(archive->api);
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))) {
storage_dir_close(directory);
storage_file_free(directory);
return false;
}
while(1) {
if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) {
break;
@ -180,31 +341,34 @@ static bool archive_get_filenames(ArchiveApp* archive) {
if(files_cnt > MAX_FILES) {
break;
} else if(storage_file_get_error(directory) == FSE_OK) {
if(filter_by_extension(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);
}
archive_view_add_item(archive, &file_info, name);
} else {
storage_dir_close(directory);
storage_file_free(directory);
return false;
}
}
storage_dir_close(directory);
storage_file_free(directory);
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) {
furi_assert(archive);
@ -220,24 +384,17 @@ static uint32_t archive_previous_callback(void* context) {
/* file menu */
static void archive_add_to_favorites(ArchiveApp* archive) {
furi_assert(archive);
storage_common_mkdir(archive->api, get_favorites_path());
string_t buffer_src;
string_t buffer_dst;
string_init_printf(
buffer_src,
"%s/%s",
"%s/%s\r\n",
string_get_cstr(archive->browser.path),
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_dst);
}
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),
archive->browser.text_input_buffer);
string_set(archive->browser.name, archive->browser.text_input_buffer);
// append extension
ArchiveFile_t* file;
@ -267,18 +425,38 @@ static void archive_text_input_callback(void* context) {
archive->view_archive_main, (ArchiveViewModel * model) {
file = files_array_get(
model->files, CLAMP(model->idx, files_array_size(model->files) - 1, 0));
file->fav = archive_is_favorite(archive, file);
return true;
});
string_cat(buffer_dst, known_ext[file->type]);
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);
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_dst);
archive_get_filenames(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);
model->menu = true;
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;
});
@ -340,29 +519,22 @@ static void archive_open_app(ArchiveApp* archive, const char* app_name, const ch
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(file);
string_t path;
string_init(path);
if(!fav && !orig) {
string_printf(
path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(file->name));
storage_common_remove(archive->api, string_get_cstr(path));
string_printf(
path, "%s/%s", string_get_cstr(archive->browser.path), string_get_cstr(file->name));
} else { // remove from favorites
string_printf(path, "%s/%s", get_favorites_path(), string_get_cstr(file->name));
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));
}
if(archive_is_favorite(archive, file)) { // remove from favorites
archive_favorites_delete(archive, file);
}
file_worker_remove(archive->file_worker, string_get_cstr(path));
string_clear(path);
archive_get_filenames(archive);
@ -375,6 +547,24 @@ static void archive_delete_file(ArchiveApp* archive, ArchiveFile_t* file, bool f
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) {
furi_assert(archive);
@ -391,27 +581,17 @@ static void archive_file_menu_callback(ArchiveApp* archive) {
switch(idx) {
case 0:
if(is_known_app(selected->type)) {
string_t full_path;
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);
archive_run_in_app(archive, selected, false);
}
break;
case 1:
if(is_known_app(selected->type)) {
if(!is_favorite(archive, selected)) {
if(!archive_is_favorite(archive, selected)) {
string_set(archive->browser.name, selected->name);
archive_add_to_favorites(archive);
} else {
// delete from favorites
archive_delete_file(archive, selected, true, false);
archive_favorites_delete(archive, selected);
}
archive_close_file_menu(archive);
}
@ -424,13 +604,7 @@ static void archive_file_menu_callback(ArchiveApp* archive) {
break;
case 3:
// confirmation?
if(is_favorite(archive, selected)) {
//delete both fav & original
archive_delete_file(archive, selected, true, true);
} else {
archive_delete_file(archive, selected, false, false);
}
archive_delete_file(archive, selected);
archive_close_file_menu(archive);
break;
@ -545,7 +719,13 @@ static bool archive_view_input(InputEvent* event, void* context) {
}
} else {
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) {
furi_assert(archive);
file_worker_free(archive->file_worker);
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewMain);
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput);
view_dispatcher_free(archive->view_dispatcher);
@ -598,6 +780,7 @@ ArchiveApp* archive_alloc() {
archive->api = furi_record_open("storage");
archive->text_input = text_input_alloc();
archive->view_archive_main = view_alloc();
archive->file_worker = file_worker_alloc(true);
furi_check(archive->event_queue);

View File

@ -13,10 +13,13 @@
#include <storage/storage.h>
#include "archive_views.h"
#include "applications.h"
#include "file-worker.h"
#define MAX_DEPTH 32
#define MAX_FILES 100 //temp
#define MAX_FILE_SIZE 128
#define ARCHIVE_FAV_PATH "/any/favorites.txt"
#define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp"
typedef enum {
ArchiveViewMain,
@ -27,7 +30,7 @@ typedef enum {
static const char* flipper_app_name[] = {
[ArchiveFileTypeIButton] = "iButton",
[ArchiveFileTypeNFC] = "NFC",
[ArchiveFileTypeSubOne] = "Sub-1 GHz",
[ArchiveFileTypeSubGhz] = "Sub-GHz",
[ArchiveFileTypeLFRFID] = "125 kHz RFID",
[ArchiveFileTypeIrda] = "Infrared",
};
@ -35,7 +38,7 @@ static const char* flipper_app_name[] = {
static const char* known_ext[] = {
[ArchiveFileTypeIButton] = ".ibtn",
[ArchiveFileTypeNFC] = ".nfc",
[ArchiveFileTypeSubOne] = ".sub",
[ArchiveFileTypeSubGhz] = ".sub",
[ArchiveFileTypeLFRFID] = ".rfid",
[ArchiveFileTypeIrda] = ".ir",
};
@ -44,7 +47,7 @@ static const char* tab_default_paths[] = {
[ArchiveTabFavorites] = "/any/favorites",
[ArchiveTabIButton] = "/any/ibutton",
[ArchiveTabNFC] = "/any/nfc",
[ArchiveTabSubOne] = "/any/subghz/saved",
[ArchiveTabSubGhz] = "/any/subghz/saved",
[ArchiveTabLFRFID] = "/any/lfrfid",
[ArchiveTabIrda] = "/any/irda",
[ArchiveTabBrowser] = "/any",
@ -56,8 +59,8 @@ static inline const char* get_tab_ext(ArchiveTabEnum tab) {
return known_ext[ArchiveFileTypeIButton];
case ArchiveTabNFC:
return known_ext[ArchiveFileTypeNFC];
case ArchiveTabSubOne:
return known_ext[ArchiveFileTypeSubOne];
case ArchiveTabSubGhz:
return known_ext[ArchiveFileTypeSubGhz];
case ArchiveTabLFRFID:
return known_ext[ArchiveFileTypeLFRFID];
case ArchiveTabIrda:
@ -73,8 +76,8 @@ static inline const char* get_default_path(ArchiveFileTypeEnum type) {
return tab_default_paths[ArchiveTabIButton];
case ArchiveFileTypeNFC:
return tab_default_paths[ArchiveTabNFC];
case ArchiveFileTypeSubOne:
return tab_default_paths[ArchiveTabSubOne];
case ArchiveFileTypeSubGhz:
return tab_default_paths[ArchiveTabSubGhz];
case ArchiveFileTypeLFRFID:
return tab_default_paths[ArchiveTabLFRFID];
case ArchiveFileTypeIrda:
@ -101,6 +104,13 @@ typedef struct {
EventType type;
} AppEvent;
typedef enum {
FavoritesCheck,
FavoritesRead,
FavoritesDelete,
FavoritesRename,
} FavActionsEnum;
typedef struct {
ArchiveTabEnum tab_id;
string_t name;
@ -123,5 +133,6 @@ struct ArchiveApp {
TextInput* text_input;
Storage* api;
FileWorker* file_worker;
ArchiveBrowser browser;
};

View File

@ -4,7 +4,7 @@ static const char* ArchiveTabNames[] = {
[ArchiveTabFavorites] = "Favorites",
[ArchiveTabIButton] = "iButton",
[ArchiveTabNFC] = "NFC",
[ArchiveTabSubOne] = "SubGhz",
[ArchiveTabSubGhz] = "Sub-GHz",
[ArchiveTabLFRFID] = "RFID LF",
[ArchiveTabIrda] = "Infrared",
[ArchiveTabBrowser] = "Browser"};
@ -12,7 +12,7 @@ static const char* ArchiveTabNames[] = {
static const Icon* ArchiveItemIcons[] = {
[ArchiveFileTypeIButton] = &I_ibutt_10px,
[ArchiveFileTypeNFC] = &I_Nfc_10px,
[ArchiveFileTypeSubOne] = &I_sub1_10px,
[ArchiveFileTypeSubGhz] = &I_sub1_10px,
[ArchiveFileTypeLFRFID] = &I_125_10px,
[ArchiveFileTypeIrda] = &I_ir_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);
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) {
string_t str_buff;
char cstr_buff[MAX_NAME_LEN];
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));
strlcpy(cstr_buff, string_get_cstr(file->name), string_size(file->name) + 1);
if(is_known_app(file->type)) archive_trim_file_ext(cstr_buff);
string_set_str(str_buff, cstr_buff);
string_init_set(str_buff, file->name);
string_right(str_buff, string_search_rchar(str_buff, '/') + 1);
strlcpy(cstr_buff, string_get_cstr(str_buff), string_size(str_buff) + 1);
if(is_known_app(file->type)) {
archive_trim_file_ext(cstr_buff);
}
if(is_known_app(file->type)) 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);
@ -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_str(canvas, 15, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
string_clean(str_buff);
string_clear(str_buff);
}
if(scrollbar) {
@ -117,8 +117,6 @@ static void draw_list(Canvas* canvas, ArchiveViewModel* model) {
if(model->menu) {
render_item_menu(canvas, model);
}
string_clear(str_buff);
}
static void archive_render_status_bar(Canvas* canvas, ArchiveViewModel* model) {

View File

@ -14,7 +14,7 @@
typedef enum {
ArchiveFileTypeIButton,
ArchiveFileTypeNFC,
ArchiveFileTypeSubOne,
ArchiveFileTypeSubGhz,
ArchiveFileTypeLFRFID,
ArchiveFileTypeIrda,
ArchiveFileTypeFolder,
@ -25,7 +25,7 @@ typedef enum {
typedef enum {
ArchiveTabFavorites,
ArchiveTabLFRFID,
ArchiveTabSubOne,
ArchiveTabSubGhz,
ArchiveTabNFC,
ArchiveTabIButton,
ArchiveTabIrda,

View File

@ -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);
}
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);
}
@ -300,6 +300,7 @@ void cli_process_input(Cli* cli) {
if(c == CliSymbolAsciiTab) {
cli_handle_autocomplete(cli);
} else if(c == CliSymbolAsciiSOH) {
osDelay(33); // We are too fast, Minicom is not ready yet
cli_motd();
cli_prompt(cli);
} else if(c == CliSymbolAsciiETX) {

View File

@ -88,7 +88,7 @@ bool cli_cmd_interrupt_received(Cli* cli);
* @param size - size of buffer in bytes
* @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
* @param cli - Cli instance

View File

@ -22,42 +22,6 @@ typedef struct {
EventType type;
} 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) {
state->left = 0;
state->right = 0;
@ -139,8 +103,8 @@ int32_t keypad_test_app(void* p) {
FURI_LOG_I(
"KeypadTest",
"key: %s type: %s",
keypad_test_get_key_name(event.input.key),
keypad_test_get_type_name(event.input.type));
input_get_key_name(event.input.key),
input_get_type_name(event.input.type));
if(event.input.type == InputTypeLong && event.input.key == InputKeyBack) {
release_mutex(&state_mutex, state);

View File

@ -11,6 +11,8 @@ struct ViewHolder {
BackCallback back_callback;
void* back_context;
uint8_t ongoing_input;
};
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) {
while(view_holder->ongoing_input) osDelay(1);
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) {
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;
if(view_holder->view) {

View File

@ -2,143 +2,134 @@
#include <furi-hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <notification/notification-messages.h>
typedef struct {
const char* name;
GpioPin pin;
const GpioPin* pin;
} GpioItem;
const GpioItem GPIO_PINS[] = {
{"1.2: PA7", {GPIOA, GPIO_PIN_7}},
{"1.3: PA6", {GPIOA, GPIO_PIN_6}},
{"1.4: PA4", {GPIOA, GPIO_PIN_4}},
{"1.5: PB3", {GPIOB, GPIO_PIN_3}},
{"1.6: PB2", {GPIOB, GPIO_PIN_2}},
{"1.7: PC3", {GPIOC, GPIO_PIN_3}},
{"2.7: PC1", {GPIOC, GPIO_PIN_1}},
{"2.8: PC0", {GPIOC, GPIO_PIN_0}},
static const GpioItem GPIO_PINS[] = {
{"1.2: PA7", &gpio_ext_pa7},
{"1.3: PA6", &gpio_ext_pa6},
{"1.4: PA4", &gpio_ext_pa4},
{"1.5: PB3", &gpio_ext_pb3},
{"1.6: PB2", &gpio_ext_pb2},
{"1.7: PC3", &gpio_ext_pc3},
{"2.7: PC1", &gpio_ext_pc1},
{"2.8: PC0", &gpio_ext_pc0},
};
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
union {
InputEvent input;
} value;
EventType type;
} AppEvent;
static const size_t GPIO_PINS_COUNT = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]);
typedef struct {
osMessageQueueId_t input_queue;
uint8_t gpio_index;
} State;
ViewPort* view_port;
Gui* gui;
NotificationApp* notification;
} GpioTest;
static void render_callback(Canvas* canvas, void* ctx) {
State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
static void gpio_test_render_callback(Canvas* canvas, void* ctx) {
GpioTest* gpio_test = ctx;
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 2, 10, "GPIO Control");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 2, 25, GPIO_PINS[state->gpio_index].name);
release_mutex((ValueMutex*)ctx, state);
canvas_draw_str(canvas, 2, 25, GPIO_PINS[gpio_test->gpio_index].name);
}
static void input_callback(InputEvent* input_event, void* ctx) {
osMessageQueueId_t event_queue = ctx;
static void gpio_test_input_callback(InputEvent* input_event, void* ctx) {
GpioTest* gpio_test = ctx;
AppEvent event;
event.type = EventTypeKey;
event.value.input = *input_event;
osMessageQueuePut(event_queue, &event, 0, 0);
osMessageQueuePut(gpio_test->input_queue, input_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) {
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
furi_check(event_queue);
GpioTest* gpio_test = gpio_test_alloc();
State _state;
_state.gpio_index = 0;
InputEvent event;
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(!init_mutex(&state_mutex, &_state, sizeof(State))) {
printf("[gpio-tester] cannot create mutex\r\n");
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.key == InputKeyRight) {
if(gpio_test->gpio_index < (GPIO_PINS_COUNT - 1)) {
gpio_test->gpio_index++;
}
}
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyRight) {
if(state->gpio_index < (sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]) - 1)) {
state->gpio_index++;
}
if(event.key == InputKeyLeft) {
if(gpio_test->gpio_index > 0) {
gpio_test->gpio_index--;
}
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyLeft) {
if(state->gpio_index > 0) {
state->gpio_index--;
}
}
if(event.value.input.key == InputKeyOk) {
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);
}
}
} else {
if(event.key == InputKeyOk) {
if(event.type == InputTypePress) {
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);
notification_message(gpio_test->notification, &sequence_reset_green);
}
}
}
release_mutex(&state_mutex, state);
view_port_update(view_port);
view_port_update(gpio_test->view_port);
}
gpio_test_free(gpio_test);
return 0;
}

View File

@ -309,12 +309,15 @@ void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) {
furi_assert(canvas);
if(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);
else if(canvas->orientation == CanvasOrientationVertical)
} else if(canvas->orientation == CanvasOrientationVertical) {
FURI_SWAP(canvas->width, canvas->height);
u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3);
else
} else {
furi_assert(0);
}
}
}

View File

@ -1,40 +1,5 @@
#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) {
// Iterating backward
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
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]);
if(view_port) {
gui_setup_fs_orientation(view_port, gui->canvas);
view_port_draw(view_port, gui->canvas);
return true;
} else {
@ -216,20 +182,53 @@ void gui_input(Gui* gui, InputEvent* input_event) {
furi_assert(gui);
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);
ViewPort* view_port;
view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]);
ViewPort* 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[GuiLayerNone]);
if(view_port) {
if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) {
gui_rotate_buttons(input_event);
}
if(!(gui->ongoing_input & ~key_bit) && input_event->type == InputTypePress) {
gui->ongoing_input_view_port = view_port;
}
if(view_port && view_port == gui->ongoing_input_view_port) {
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);
@ -251,7 +250,7 @@ void gui_cli_screen_stream_callback(uint8_t* data, size_t size, void* context) {
furi_assert(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, 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);
}

View File

@ -35,14 +35,19 @@ struct Gui {
// Thread and lock
osThreadId_t thread;
osMutexId_t mutex;
// Layers and Canvas
ViewPortArray_t layers[GuiLayerMAX];
Canvas* canvas;
GuiCanvasCommitCallback canvas_callback;
void* canvas_callback_context;
// Input
osMessageQueueId_t input_queue;
PubSub* input_events;
uint8_t ongoing_input;
ViewPort* ongoing_input_view_port;
// Cli
Cli* cli;
};

View File

@ -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);
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);
}

View File

@ -59,8 +59,24 @@ void widget_add_button_element(
/** Add Icon Element
* @param widget Widget instance
* @param x - x coordinate
* @param y - y coordinate
* @param x top left x coordinate
* @param y top left y coordinate
* @param icon Icon instance
*/
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);

View 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;
}

View File

@ -44,5 +44,13 @@ WidgetElement* widget_element_button_create(
ButtonCallback callback,
void* context);
/* Create icon element element */
/* Create icon element */
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);

View File

@ -1,5 +1,4 @@
#include "widget_element_i.h"
#include <m-string.h>
typedef struct {
uint8_t x;

View File

@ -35,11 +35,6 @@ void view_set_previous_callback(View* view, ViewNavigationCallback 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) {
furi_assert(view);
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) {
furi_assert(view);
if(view->enter_callback) view->enter_callback(view->context);

View File

@ -14,11 +14,6 @@ extern "C" {
#define VIEW_NONE 0xFFFFFFFF
/* Ignore navigation event */
#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 {
ViewOrientationHorizontal,
@ -119,12 +114,6 @@ void view_set_custom_callback(View* view, ViewCustomCallback 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
* @param view, pointer to View
* @param callback, callback

91
applications/gui/view_dispatcher.c Executable file → Normal file
View File

@ -37,7 +37,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) {
furi_assert(view_dispatcher);
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) {
@ -91,6 +91,19 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) {
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) {
@ -136,6 +149,10 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
if(view_dispatcher->current_view == view) {
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
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) {
view_dispatcher_set_current_view(view_dispatcher, NULL);
} else if(view_id == VIEW_IGNORE) {
} else if(view_id == VIEW_DESTROY) {
view_dispatcher_free(view_dispatcher);
} else {
View** view_pp = ViewDict_get(view_dispatcher->views, view_id);
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) {
bool is_consumed = false;
if(view_dispatcher->current_view) {
is_consumed = view_input(view_dispatcher->current_view, event);
// Check input complementarity
uint8_t key_bit = (1 << event->key);
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
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;
// Set ongoing input view if this is event is first press event
if(!(view_dispatcher->ongoing_input & ~key_bit) && event->type == InputTypePress) {
view_dispatcher->ongoing_input_view = view_dispatcher->current_view;
}
// Deliver event
if(view_dispatcher->ongoing_input_view == view_dispatcher->current_view) {
bool is_consumed = false;
if(view_dispatcher->current_view) {
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) {
view_id = view_next(view_dispatcher->current_view);
}
if(!is_consumed) {
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);
}
}

View File

@ -113,6 +113,7 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
/** Switch to View
* @param view_dispatcher ViewDispatcher instance
* @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);

View File

@ -14,7 +14,12 @@ struct ViewDispatcher {
Gui* gui;
ViewPort* view_port;
ViewDict_t views;
View* current_view;
View* ongoing_input_view;
uint8_t ongoing_input;
ViewDispatcherCustomEventCallback custom_event_callback;
ViewDispatcherNavigationEventCallback navigation_event_callback;
ViewDispatcherTickEventCallback tick_event_callback;

View File

@ -15,7 +15,6 @@ struct View {
ViewModelType model_type;
ViewNavigationCallback previous_callback;
ViewNavigationCallback next_callback;
ViewCallback enter_callback;
ViewCallback exit_callback;
ViewOrientation orientation;
@ -42,9 +41,6 @@ bool view_custom(View* view, uint32_t event);
/* Previous Callback for View dispatcher */
uint32_t view_previous(View* view);
/* Next Callback for View dispatcher */
uint32_t view_next(View* view);
/* Enter Callback for View dispatcher */
void view_enter(View* view);

View File

@ -7,6 +7,33 @@
// 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 = furi_alloc(sizeof(ViewPort));
view_port->orientation = ViewPortOrientationHorizontal;
@ -84,6 +111,7 @@ void view_port_draw(ViewPort* view_port, Canvas* canvas) {
furi_check(view_port->gui);
if(view_port->draw_callback) {
view_port_setup_canvas_orientation(view_port, canvas);
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);
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 File

@ -10,18 +10,20 @@
#include <memory>
void ibutton_cli(Cli* cli, string_t args, void* context);
void onewire_cli(Cli* cli, string_t args, void* context);
// app cli function
extern "C" void ibutton_cli_init() {
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");
}
void ibutton_cli_print_usage() {
printf("Usage:\r\n");
printf("tm read\r\n");
printf("tm <write | emulate> <key_type> <key_data>\r\n");
printf("ikey read\r\n");
printf("ikey <write | emulate> <key_type> <key_data>\r\n");
printf("\t<key_type> choose from:\r\n");
printf("\tDallas (8 bytes key_data)\r\n");
printf("\tCyfral (2 bytes key_data)\r\n");
@ -230,5 +232,53 @@ void ibutton_cli(Cli* cli, string_t args, void* context) {
ibutton_cli_print_usage();
}
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);
}

View File

@ -23,6 +23,7 @@ inline static void input_timer_stop(osTimerId_t timer_id) {
void input_press_timer_callback(void* arg) {
InputPinState* input_pin = arg;
InputEvent event;
event.sequence = input_pin->counter;
event.key = input_pin->pin->key;
input_pin->press_counter++;
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);
}
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() {
input = furi_alloc(sizeof(Input));
input->thread = osThreadGetId();
@ -103,10 +129,9 @@ int32_t input_srv() {
input->cli, "input_send", CliCommandFlagParallelSafe, input_cli_send, input);
}
const size_t pin_count = input_pins_count;
input->pin_states = furi_alloc(pin_count * sizeof(InputPinState));
input->pin_states = furi_alloc(input_pins_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};
hal_gpio_add_int_callback(&gpio, input_isr, NULL);
input->pin_states[i].pin = &input_pins[i];
@ -119,7 +144,7 @@ int32_t input_srv() {
while(1) {
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]);
if(input->pin_states[i].debounce > 0 &&
input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) {
@ -131,14 +156,15 @@ int32_t input_srv() {
// Common state info
InputEvent event;
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
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);
} else {
event.sequence = input->pin_states[i].counter;
input_timer_stop(input->pin_states[i].press_timer);
if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) {
event.type = InputTypeShort;
@ -146,6 +172,10 @@ int32_t input_srv() {
}
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);
}
}

View File

@ -15,6 +15,19 @@ typedef enum {
/* Input Event, dispatches with PubSub */
typedef struct {
uint32_t sequence;
InputKey key;
InputType type;
} 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);

View File

@ -24,6 +24,7 @@ typedef struct {
volatile uint8_t debounce;
volatile osTimerId_t press_timer;
volatile uint8_t press_counter;
volatile uint32_t counter;
} InputPinState;
/* Input state */
@ -32,6 +33,7 @@ typedef struct {
PubSub event_pubsub;
InputPinState* pin_states;
Cli* cli;
volatile uint32_t counter;
} Input;
/* Input press timer callback */

View File

@ -383,11 +383,6 @@ int32_t music_player_app(void* p) {
Gui* gui = furi_record_open("gui");
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
// TODO change to fuirac_start
osThreadAttr_t player_attr = {.name = "music_player_thread", .stack_size = 512};
@ -410,14 +405,8 @@ int32_t music_player_app(void* p) {
// press events
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyBack) {
osThreadTerminate(player);
hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
osMessageQueueDelete(event_queue);
return 0;
release_mutex(&state_mutex, state);
break;
}
if(event.value.input.type == InputTypePress &&
@ -442,9 +431,6 @@ int32_t music_player_app(void* p) {
}
} 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;
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);
}
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;
}

View 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;
}

View 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);

View File

@ -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("Press Ctrl+C to abort\r\n");
NfcDeviceCommomData params = {
NfcDeviceCommonData params = {
.uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
.uid_len = 7,
.atqa = {0x44, 0x00},

View File

@ -10,7 +10,7 @@ static const char* nfc_app_folder = "/any/nfc";
static const char* nfc_app_extension = ".nfc";
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);
uint8_t nibble_high = 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) &&
hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) {
buff[i] = (nibble_high << 4) | nibble_low;
string_right(str, 3);
string_right(str, delim_len + 2);
} else {
parsed = false;
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) {
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);
for(uint8_t i = 0; i < uid_data->uid_len; 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) {
NfcDeviceCommomData* uid_data = &dev->dev_data.nfc_data;
NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data;
bool parsed = false;
do {
// strlen("UID len: ") = 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;
}
// strlen("UID: ") = 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;
}
// strlen("ATQA: ") = 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;
}
// strlen("SAK: ") = 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;
}
parsed = true;
@ -149,13 +149,13 @@ bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string
do {
// strlen("Signature: ") = 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;
}
// strlen("Version: ") = 9
string_right(mifare_ul_string, 9);
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;
}
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);
// Read data
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;
}
}
@ -208,6 +208,12 @@ uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_
string_cat_printf(
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);
}
@ -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;
bool parsed = false;
int res = 0;
uint8_t code[2] = {};
memset(data, 0, sizeof(NfcEmvData));
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);
size_t ws = string_search_char(bank_card_string, ':');
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;
}
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);
// strlen("Number: ") = 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;
}
parsed = true;
@ -246,8 +253,24 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string
if(ws != STRING_FAILURE) {
// strlen("Exp date: ") = 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_year, 1);
nfc_device_read_hex(bank_card_string, &data->exp_mon, 1, 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);

View File

@ -34,7 +34,7 @@ typedef struct {
uint8_t sak;
NfcDeviceType device;
NfcProtocol protocol;
} NfcDeviceCommomData;
} NfcDeviceCommonData;
typedef struct {
char name[32];
@ -43,11 +43,12 @@ typedef struct {
uint8_t number[8];
uint8_t exp_mon;
uint8_t exp_year;
char cardholder[32];
uint16_t country_code;
uint16_t currency_code;
} NfcEmvData;
typedef struct {
NfcDeviceCommomData nfc_data;
NfcDeviceCommonData nfc_data;
union {
NfcEmvData emv_data;
MifareUlData mf_ul_data;

View File

@ -100,7 +100,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) {
rfalNfcDevice* dev_list;
rfalNfcDevice* dev;
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) {
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) {
NfcDeviceCommomData* data = &nfc_worker->dev_data->nfc_data;
NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateEmulate) {
if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) {
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_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
if(nfc_worker->callback) {
nfc_worker->callback(nfc_worker->context);
@ -358,7 +364,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
NfcDeviceCommomData params = {
NfcDeviceCommonData params = {
.uid = {0xCF, 0x72, 0xd4, 0x40},
.uid_len = 4,
.atqa = {0x00, 0x04},

View File

@ -18,7 +18,7 @@ void nfc_scene_delete_on_enter(void* context) {
widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
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) {
snprintf(
uid_str,

33
applications/nfc/scenes/nfc_scene_device_info.c Normal file → Executable file
View File

@ -1,6 +1,6 @@
#include "../nfc_i.h"
#define NFC_SCENE_DEVICE_INFO_TEXTBOX_CUSTOM_EVENT (0UL)
#define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL)
enum {
NfcSceneDeviceInfoUid,
@ -8,26 +8,27 @@ enum {
};
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);
}
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);
}
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(
nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_TEXTBOX_CUSTOM_EVENT);
void nfc_scene_device_info_bank_card_callback(GuiButtonType result, void* context) {
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) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
// Setup Custom Widget view
widget_add_string_element(
@ -37,7 +38,7 @@ void nfc_scene_device_info_on_enter(void* context) {
widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
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) {
snprintf(
uid_str,
@ -107,19 +108,23 @@ void nfc_scene_device_info_on_enter(void* context) {
BankCard* bank_card = nfc->bank_card;
bank_card_set_name(bank_card, emv_data->name);
bank_card_set_number(bank_card, emv_data->number);
if(!strcmp(emv_data->name, "")) {
bank_card_set_cardholder_name(bank_card, emv_data->cardholder);
}
bank_card_set_back_callback(bank_card, nfc_scene_device_info_bank_card_callback, nfc);
if(emv_data->exp_mon) {
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);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
const bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
Nfc* nfc = context;
bool consumed = false;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo);

View File

@ -5,7 +5,7 @@ const void nfc_scene_emulate_uid_on_enter(void* context) {
// Setup view
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, "")) {
nfc_text_store_set(nfc, "%s", nfc->dev.dev_name);

View File

@ -18,7 +18,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
notification_message(nfc->notifications, &sequence_success);
// 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;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");

View File

@ -1,4 +1,5 @@
#include "../nfc_i.h"
#include "../helpers/nfc_emv_parser.h"
#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;
// 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;
DialogEx* dialog_ex = nfc->dialog_ex;
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);
// Display UID and AID
string_t aid;
string_init_printf(aid, "AID:");
for(uint8_t i = 0; i < emv_data->aid_len; i++) {
string_cat_printf(aid, " %02X", emv_data->aid[i]);
string_init(aid);
bool aid_found = nfc_emv_parser_get_aid_name(emv_data->aid, emv_data->aid_len, aid);
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,

View File

@ -16,6 +16,8 @@ const void nfc_scene_read_emv_data_on_enter(void* context) {
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
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
nfc_worker_start(
nfc->worker,

View File

@ -1,4 +1,5 @@
#include "../nfc_i.h"
#include "../helpers/nfc_emv_parser.h"
void nfc_scene_read_emv_data_success_widget_callback(GuiButtonType result, void* 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) {
Nfc* nfc = (Nfc*)context;
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
nfc_device_set_name(&nfc->dev, "");
// Setup Custom Widget view
// Add frame
widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6);
// Add buttons
widget_add_button_element(
nfc->widget,
GuiButtonTypeLeft,
@ -27,8 +31,10 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
"Save",
nfc_scene_read_emv_data_success_widget_callback,
nfc);
// Add card name
widget_add_string_element(
nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev.dev_data.emv_data.name);
// Add cad number
char pan_str[32];
snprintf(
pan_str,
@ -43,9 +49,41 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
emv_data->number[6],
emv_data->number[7]);
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];
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);
// Add UID
char uid_str[32];
snprintf(
uid_str,
@ -56,9 +94,11 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
nfc_data->uid[2],
nfc_data->uid[3]);
widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str);
// Add SAK
char sak_str[16];
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak);
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str);
// Add expiration date
if(emv_data->exp_mon) {
char exp_str[16];
snprintf(

View File

@ -30,7 +30,7 @@ const void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
notification_message(nfc->notifications, &sequence_success);
// 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;
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");

View File

@ -1,5 +1,5 @@
#include "bank_card.h"
#include <gui/modules/widget.h>
#include "../helpers/nfc_emv_parser.h"
#include <m-string.h>
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) {
string_cat_printf(num_str, "%02X%02X ", number[i], number[i + 1]);
}
// Add number
widget_add_string_element(
bank_card->widget, 25, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(num_str));
widget_add_icon_element(bank_card->widget, 6, 20, &I_EMV_Chip_14x11);
bank_card->widget, 64, 32, AlignCenter, AlignTop, FontSecondary, string_get_cstr(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) {
@ -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);
}
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(name);
widget_add_string_element(bank_card->widget, 6, 37, AlignLeft, AlignTop, FontSecondary, name);
string_t country_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);
}

View File

@ -1,11 +1,10 @@
#pragma once
#include <stdint.h>
#include <gui/view.h>
#include <gui/modules/widget.h>
typedef struct BankCard BankCard;
typedef void (*BankCardBackCallback)(void);
BankCard* bank_card_alloc();
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);
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_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_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);

View File

@ -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;
}

View File

@ -1,13 +1,12 @@
ADD_SCENE(subghz, start, Start)
ADD_SCENE(subghz, analyze, Analyze)
ADD_SCENE(subghz, read, Read)
ADD_SCENE(subghz, receiver, Receiver)
ADD_SCENE(subghz, save_name, SaveName)
ADD_SCENE(subghz, save_success, SaveSuccess)
ADD_SCENE(subghz, saved, Saved)
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_static, TestStatic)
ADD_SCENE(subghz, test_carrier, TestCarrier)
ADD_SCENE(subghz, test_packet, TestPacket)
ADD_SCENE(subghz, set_type, SetType)

View 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);
}

View File

@ -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);
}

View File

@ -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_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);
}
@ -21,12 +23,57 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event
SubGhz* subghz = context;
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);
return true;
} else if(event.event == SubghzReceverEventBack) {
break;
case SubghzReceverEventBack:
scene_manager_previous_scene(subghz->scene_manager);
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;

View File

@ -19,7 +19,7 @@ const void subghz_scene_save_name_on_enter(void* context) {
set_random_name(subghz->text_store, sizeof(subghz->text_store));
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,
subghz_scene_save_name_text_input_callback,

View File

@ -25,8 +25,12 @@ const bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent e
SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
return scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart);
if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneReceiver)) {
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart);
}
return true;
}
}
return false;

View File

@ -3,7 +3,7 @@
const void subghz_scene_saved_on_enter(void* 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);
} else {
scene_manager_search_and_switch_to_previous_scene(subghz->scene_manager, SubGhzSceneStart);

View File

@ -32,31 +32,31 @@ const void subghz_scene_set_type_on_enter(void* context) {
submenu_add_item(
subghz->submenu,
"Pricenton",
"Princeton_433",
SubmenuIndexPricenton,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"Nice Flo 12bit",
"Nice Flo 12bit_433",
SubmenuIndexNiceFlo12bit,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"Nice Flo 24bit",
"Nice Flo 24bit_433",
SubmenuIndexNiceFlo24bit,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"CAME 12bit",
"CAME 12bit_433",
SubmenuIndexCAME12bit,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"CAME 24bit",
"CAME 24bit_433",
SubmenuIndexCAME24bit,
subghz_scene_set_type_submenu_callback,
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);
submenu_add_item(
subghz->submenu,
"Gate TX",
"Gate TX_433",
SubmenuIndexGateTX,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"DoorHan",
"DoorHan_433",
SubmenuIndexDoorHan,
subghz_scene_set_type_submenu_callback,
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->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
subghz->protocol_result->cnt = 0x0003;
subghz_protocol_keeloq_set_manufacture_name(subghz->protocol_result, "DoorHan");
subghz->protocol_result->code_last_found =
subghz_protocol_keeloq_gen_key(subghz->protocol_result);
generated_protocol = true;
if(subghz_protocol_keeloq_set_manufacture_name(
subghz->protocol_result, "DoorHan")) {
subghz->protocol_result->code_last_found =
subghz_protocol_keeloq_gen_key(subghz->protocol_result);
generated_protocol = true;
} else {
generated_protocol = false;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNoMan);
}
}
break;
@ -159,6 +163,8 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event
break;
}
if(generated_protocol) {
subghz->frequency = subghz_frequencies[subghz_frequencies_433_92];
subghz->preset = FuriHalSubGhzPresetOok650Async;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
return true;
}

View File

@ -1,10 +1,8 @@
#include "../subghz_i.h"
enum SubmenuIndex {
SubmenuIndexAnalyze,
SubmenuIndexRead,
SubmenuIndexSaved,
SubmenuIndexStatic,
SubmenuIndexTest,
SubmenuIndexAddManualy,
};
@ -19,12 +17,6 @@ const void subghz_scene_start_on_enter(void* context) {
if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) {
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
}
submenu_add_item(
subghz->submenu,
"Analyze",
SubmenuIndexAnalyze,
subghz_scene_start_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz);
submenu_add_item(
@ -35,8 +27,6 @@ const void subghz_scene_start_on_enter(void* context) {
SubmenuIndexAddManualy,
subghz_scene_start_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu, "Static", SubmenuIndexStatic, subghz_scene_start_submenu_callback, subghz);
submenu_add_item(
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;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexAnalyze) {
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) {
if(event.event == SubmenuIndexRead) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRead);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
return true;
} else if(event.event == SubmenuIndexSaved) {
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);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetType);
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) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest);

View File

@ -3,6 +3,7 @@
enum SubmenuIndex {
SubmenuIndexCarrier,
SubmenuIndexPacket,
SubmenuIndexStatic,
};
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);
submenu_add_item(
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(
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);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestPacket);
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;

View File

@ -1,15 +1,15 @@
#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;
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;
return false;
}
const void subghz_scene_static_on_exit(void* context) {
const void subghz_scene_test_static_on_exit(void* context) {
// SubGhz* subghz = context;
}

View File

@ -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_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);
@ -30,12 +31,18 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev
} else if(event.event == SubghzTransmitterEventSendStop) {
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
subghz_transmitter_tx_stop(subghz);
subghz_sleep();
return true;
} else if(event.event == SubghzTransmitterEventBack) {
subghz->state_notifications = NOTIFICATION_IDLE_STATE;
scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart);
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) {
if(subghz->state_notifications == NOTIFICATION_TX_STATE) {

View File

@ -70,13 +70,6 @@ SubGhz* subghz_alloc() {
view_dispatcher_add_view(
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
subghz->subghz_receiver = subghz_receiver_alloc();
view_dispatcher_add_view(
@ -121,9 +114,11 @@ SubGhz* subghz_alloc() {
subghz_test_packet_get_view(subghz->subghz_test_packet));
// Static send
subghz->subghz_static = subghz_static_alloc();
subghz->subghz_test_static = subghz_test_static_alloc();
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
subghz->worker = subghz_worker_alloc();
@ -134,8 +129,8 @@ SubGhz* subghz_alloc() {
subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse);
subghz_worker_set_context(subghz->worker, subghz->protocol);
subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/assets/subghz/keeloq_mfcodes");
subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/assets/subghz/nice_floor_s_rx");
subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/subghz/keeloq_mfcodes");
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);
@ -155,11 +150,7 @@ void subghz_free(SubGhz* subghz) {
// Static
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic);
subghz_static_free(subghz->subghz_static);
// Analyze
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewAnalyze);
subghz_analyze_free(subghz->subghz_analyze);
subghz_test_static_free(subghz->subghz_test_static);
// Receiver
view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver);

View File

@ -42,7 +42,7 @@ void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) {
}
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);
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_load_preset(FuriHalSubGhzPresetOokAsync);
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
frequency = furi_hal_subghz_set_frequency_and_path(frequency);
printf("Receiving at frequency %lu Hz\r\n", frequency);
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_count_bit = 24;
SubGhzProtocolEncoderCommon* encoder = subghz_protocol_encoder_common_alloc();
SubGhzProtocolCommonEncoder* encoder = subghz_protocol_encoder_common_alloc();
encoder->repeat = repeat;
subghz_protocol_princeton_send_key(protocol, encoder);
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);
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);
SubGhzProtocol* protocol = subghz_protocol_alloc();
subghz_protocol_load_keeloq_file(protocol, "/ext/assets/subghz/keeloq_mfcodes");
subghz_protocol_load_nice_flor_s_file(protocol, "/ext/assets/subghz/nice_floor_s_rx");
subghz_protocol_load_keeloq_file(protocol, "/ext/subghz/keeloq_mfcodes");
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);
// Configure radio
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);
hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);

View 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++;
}

View 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);

View File

@ -8,6 +8,7 @@
#include <notification/notification-messages.h>
#include "file-worker.h"
#include "../notification/notification.h"
#include "views/subghz_receiver.h"
void subghz_begin(FuriHalSubGhzPreset preset) {
furi_hal_subghz_reset();
@ -16,30 +17,59 @@ void subghz_begin(FuriHalSubGhzPreset preset) {
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_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);
furi_hal_subghz_flush_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_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_write(&gpio_cc1101_g0, true);
furi_hal_subghz_tx();
return value;
}
void subghz_idle(void) {
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();
}
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) {
SubGhz* subghz = context;
subghz->encoder = subghz_protocol_encoder_common_alloc();
@ -47,8 +77,17 @@ void subghz_transmitter_tx_start(void* context) {
//get upload
if(subghz->protocol_result->get_upload_protocol) {
if(subghz->protocol_result->get_upload_protocol(subghz->protocol_result, subghz->encoder)) {
subghz_begin(FuriHalSubGhzPresetOokAsync);
subghz_tx(433920000);
if(subghz->preset) {
subghz_begin(subghz->preset);
} else {
subghz_begin(FuriHalSubGhzPresetOok650Async);
}
if(subghz->frequency) {
subghz_tx(subghz->frequency);
} else {
subghz_tx(433920000);
}
//Start TX
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;
//Stop TX
furi_hal_subghz_stop_async_tx();
subghz_end();
subghz_protocol_encoder_common_free(subghz->encoder);
//if protocol dynamic then we save the last upload
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_t temp_str;
string_init(temp_str);
int res = 0;
int data = 0;
do {
if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
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')) {
break;
}
@ -93,16 +154,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
subghz->protocol_result =
subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str));
if(subghz->protocol_result == NULL) {
file_worker_show_error(file_worker, "Cannot parse\nfile");
break;
}
if(!subghz->protocol_result->to_load_protocol(file_worker, subghz->protocol_result)) {
file_worker_show_error(file_worker, "Cannot parse\nfile");
if(!subghz->protocol_result->to_load_protocol_from_file(
file_worker, subghz->protocol_result)) {
break;
}
loaded = true;
} while(0);
if(!loaded) {
file_worker_show_error(file_worker, "Cannot parse\nfile");
}
string_clear(temp_str);
string_clear(path);
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) {
SubGhz* subghz = context;
furi_assert(subghz->protocol_result);
FileWorker* file_worker = file_worker_alloc(false);
string_t 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)) {
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
subghz->protocol_result->to_save_string(subghz->protocol_result, temp_str);
// Prepare and write data to file
@ -157,7 +226,7 @@ bool subghz_save_protocol_to_file(void* context, const char* dev_name) {
return saved;
}
bool subghz_saved_protocol_select(SubGhz* subghz) {
bool subghz_load_protocol_from_file(SubGhz* subghz) {
furi_assert(subghz);
FileWorker* file_worker = file_worker_alloc(false);
@ -165,6 +234,8 @@ bool subghz_saved_protocol_select(SubGhz* subghz) {
string_init(protocol_file_name);
string_t temp_str;
string_init(temp_str);
int sscanf_res = 0;
int data = 0;
// Input events and views are managed by 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)) {
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')) {
break;
}
@ -206,16 +297,19 @@ bool subghz_saved_protocol_select(SubGhz* subghz) {
subghz->protocol_result =
subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str));
if(subghz->protocol_result == NULL) {
file_worker_show_error(file_worker, "Cannot parse\nfile");
break;
}
if(!subghz->protocol_result->to_load_protocol(file_worker, subghz->protocol_result)) {
file_worker_show_error(file_worker, "Cannot parse\nfile");
if(!subghz->protocol_result->to_load_protocol_from_file(
file_worker, subghz->protocol_result)) {
break;
}
res = true;
} while(0);
if(!res) {
file_worker_show_error(file_worker, "Cannot parse\nfile");
}
string_clear(temp_str);
string_clear(protocol_file_name);

View File

@ -1,11 +1,10 @@
#pragma once
#include "subghz.h"
#include "views/subghz_analyze.h"
#include "views/subghz_receiver.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_packet.h"
@ -25,12 +24,14 @@
#include <lib/subghz/subghz_worker.h>
#include <lib/subghz/protocols/subghz_protocol.h>
#include <lib/subghz/protocols/subghz_protocol_common.h>
#include "subghz_history.h"
#define SUBGHZ_TEXT_STORE_SIZE 128
#define NOTIFICATION_STARTING_STATE 0u
#define NOTIFICATION_IDLE_STATE 1u
#define NOTIFICATION_TX_STATE 2u
#define NOTIFICATION_RX_STATE 3u
extern const uint32_t subghz_frequencies[];
extern const uint32_t subghz_frequencies_count;
@ -43,10 +44,11 @@ struct SubGhz {
SubGhzWorker* worker;
SubGhzProtocol* protocol;
SubGhzProtocolCommon* protocol_result;
SubGhzProtocolEncoderCommon* encoder;
SubGhzProtocolCommonEncoder* encoder;
uint32_t frequency;
FuriHalSubGhzPreset preset;
SceneManager* scene_manager;
ViewDispatcher* view_dispatcher;
Submenu* submenu;
@ -56,11 +58,10 @@ struct SubGhz {
char text_store[SUBGHZ_TEXT_STORE_SIZE + 1];
uint8_t state_notifications;
SubghzAnalyze* subghz_analyze;
SubghzReceiver* subghz_receiver;
SubghzTransmitter* subghz_transmitter;
SubghzStatic* subghz_static;
SubghzTestStatic* subghz_test_static;
SubghzTestCarrier* subghz_test_carrier;
SubghzTestPacket* subghz_test_packet;
};
@ -68,7 +69,6 @@ struct SubGhz {
typedef enum {
SubGhzViewMenu,
SubGhzViewAnalyze,
SubGhzViewDialogEx,
SubGhzViewReceiver,
SubGhzViewPopup,
@ -81,13 +81,14 @@ typedef enum {
} SubGhzView;
void subghz_begin(FuriHalSubGhzPreset preset);
void subghz_rx(uint32_t frequency);
void subghz_tx(uint32_t frequency);
uint32_t subghz_rx(void* context, uint32_t frequency);
uint32_t subghz_tx(uint32_t frequency);
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_stop(void* context);
bool subghz_key_load(SubGhz* subghz, const char* file_path);
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);

View File

@ -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;
}

View File

@ -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);

View File

@ -1,25 +1,74 @@
#include "subghz_receiver.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/protocols/subghz_protocol_princeton.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 {
View* view;
SubghzReceiverCallback callback;
void* context;
SubGhzWorker* worker;
SubGhzProtocol* protocol;
osTimerId timer;
SubGhzHopperState hopper_state;
uint8_t hopper_timeout;
uint32_t event_key_sequence;
};
typedef struct {
string_t text;
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;
void subghz_receiver_set_callback(
@ -32,48 +81,393 @@ void subghz_receiver_set_callback(
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(
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;
});
}
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) {
bool scrollbar = model->history_item > 4;
string_t str_buff;
char buffer[64];
uint32_t frequency;
string_init(str_buff);
canvas_clear(canvas);
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");
if(model->protocol && model->protocol->to_save_string &&
strcmp(model->protocol->name, "KeeLoq")) {
elements_button_right(canvas, "Save");
switch(model->scene) {
case ReceiverSceneMain:
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
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) {
furi_assert(context);
uint8_t scene = 0;
SubghzReceiver* subghz_receiver = context;
if(event->type != InputTypeShort) return false;
bool can_be_saved = false;
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
can_be_saved =
(model->protocol && model->protocol->to_save_string &&
strcmp(model->protocol->name, "KeeLoq"));
scene = model->scene;
return false;
});
if(event->key == InputKeyBack) {
return false;
} else if(event->key == InputKeyLeft) {
subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context);
} else if(can_be_saved && event->key == InputKeyRight) {
subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context);
bool can_be_saved = false;
switch(scene) {
case ReceiverSceneMain:
if(event->key == InputKeyBack && event->type == InputTypeShort) {
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;
@ -86,7 +480,88 @@ void subghz_receiver_text_callback(string_t text, void* context) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
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;
});
}
@ -94,21 +569,37 @@ void subghz_receiver_text_callback(string_t text, void* context) {
void subghz_receiver_enter(void* context) {
furi_assert(context);
SubghzReceiver* subghz_receiver = context;
//Start CC1101 Rx
subghz_begin(FuriHalSubGhzPresetOok650Async);
with_view_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;
});
subghz_protocol_enable_dump(
subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver);
}
void subghz_receiver_exit(void* context) {
furi_assert(context);
SubghzReceiver* subghz_receiver = context;
osTimerStop(subghz_receiver->timer);
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_clean(model->text);
return true;
});
// Stop CC1101 Rx
subghz_rx_end(subghz_receiver->worker);
subghz_sleep();
}
SubghzReceiver* subghz_receiver_alloc() {
@ -126,8 +617,13 @@ SubghzReceiver* subghz_receiver_alloc() {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_init(model->text);
model->history = subghz_history_alloc();
return true;
});
subghz_receiver->timer =
osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL);
subghz_receiver->hopper_state = SubGhzHopperStateOFF;
return subghz_receiver;
}
@ -137,8 +633,10 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) {
with_view_model(
subghz_receiver->view, (SubghzReceiverModel * model) {
string_clear(model->text);
return true;
subghz_history_free(model->history);
return false;
});
osTimerDelete(subghz_receiver->timer);
view_free(subghz_receiver->view);
free(subghz_receiver);
}
@ -147,3 +645,44 @@ View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) {
furi_assert(subghz_receiver);
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);
}

View File

@ -2,10 +2,20 @@
#include <gui/view.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 {
SubghzReceverEventOK,
SubghzReceverEventConfig,
SubghzReceverEventMain,
SubghzReceverEventSave,
SubghzReceverEventBack,
SubghzReceverEventMore,
SubghzReceverEventSendStart,
SubghzReceverEventSendStop,
SubghzReceverEventSendHistoryFull,
} SubghzReceverEvent;
typedef struct SubghzReceiver SubghzReceiver;
@ -23,4 +33,17 @@ void subghz_receiver_free(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);

View File

@ -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);

View File

@ -71,41 +71,37 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
furi_assert(context);
SubghzTestCarrier* subghz_test_carrier = context;
if(event->key == InputKeyBack) {
if(event->key == InputKeyBack || event->type != InputTypeShort) {
return false;
}
with_view_model(
subghz_test_carrier->view, (SubghzTestCarrierModel * model) {
osTimerStop(subghz_test_carrier->timer);
furi_hal_subghz_idle();
if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
if(model->frequency > 0) model->frequency--;
} else if(event->key == InputKeyRight) {
if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
} else if(event->key == InputKeyDown) {
if(model->path > 0) model->path--;
} else if(event->key == InputKeyUp) {
if(model->path < FuriHalSubGhzPath868) model->path++;
} else if(event->key == InputKeyOk) {
if(model->status == SubghzTestCarrierModelStatusTx) {
model->status = SubghzTestCarrierModelStatusRx;
} else {
model->status = SubghzTestCarrierModelStatusTx;
}
if(event->key == InputKeyLeft) {
if(model->frequency > 0) model->frequency--;
} else if(event->key == InputKeyRight) {
if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
} else if(event->key == InputKeyDown) {
if(model->path > 0) model->path--;
} else if(event->key == InputKeyUp) {
if(model->path < FuriHalSubGhzPath868) model->path++;
} else if(event->key == InputKeyOk) {
if(model->status == SubghzTestCarrierModelStatusTx) {
model->status = SubghzTestCarrierModelStatusRx;
} else {
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) {
hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
furi_hal_subghz_rx();
osTimerStart(subghz_test_carrier->timer, 1024 / 4);
} else {
hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
hal_gpio_write(&gpio_cc1101_g0, true);
@ -123,7 +119,7 @@ void subghz_test_carrier_enter(void* context) {
SubghzTestCarrier* subghz_test_carrier = context;
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);
@ -159,8 +155,11 @@ void subghz_test_carrier_rssi_timer_callback(void* context) {
with_view_model(
subghz_test_carrier->view, (SubghzTestCarrierModel * model) {
model->rssi = furi_hal_subghz_get_rssi();
return true;
if(model->status == SubghzTestCarrierModelStatusRx) {
model->rssi = furi_hal_subghz_get_rssi();
return true;
}
return false;
});
}
@ -170,7 +169,7 @@ SubghzTestCarrier* subghz_test_carrier_alloc() {
// View allocation and configuration
subghz_test_carrier->view = view_alloc();
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_draw_callback(subghz_test_carrier->view, (ViewDrawCallback)subghz_test_carrier_draw);
view_set_input_callback(subghz_test_carrier->view, subghz_test_carrier_input);

View File

@ -116,7 +116,7 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) {
furi_assert(context);
SubghzTestPacket* instance = context;
if(event->key == InputKeyBack) {
if(event->key == InputKeyBack || event->type != InputTypeShort) {
return false;
}
@ -128,28 +128,26 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) {
furi_hal_subghz_stop_async_tx();
}
if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
if(model->frequency > 0) model->frequency--;
} else if(event->key == InputKeyRight) {
if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
} else if(event->key == InputKeyDown) {
if(model->path > 0) model->path--;
} else if(event->key == InputKeyUp) {
if(model->path < FuriHalSubGhzPath868) model->path++;
} else if(event->key == InputKeyOk) {
if(model->status == SubghzTestPacketModelStatusTx) {
model->status = SubghzTestPacketModelStatusRx;
} else {
model->status = SubghzTestPacketModelStatusTx;
}
if(event->key == InputKeyLeft) {
if(model->frequency > 0) model->frequency--;
} else if(event->key == InputKeyRight) {
if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
} else if(event->key == InputKeyDown) {
if(model->path > 0) model->path--;
} else if(event->key == InputKeyUp) {
if(model->path < FuriHalSubGhzPath868) model->path++;
} else if(event->key == InputKeyOk) {
if(model->status == SubghzTestPacketModelStatusTx) {
model->status = SubghzTestPacketModelStatusRx;
} else {
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) {
furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance);
} else {
@ -168,7 +166,7 @@ void subghz_test_packet_enter(void* context) {
SubghzTestPacket* instance = context;
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
with_view_model(
instance->view, (SubghzTestPacketModel * model) {
@ -210,7 +208,7 @@ SubghzTestPacket* subghz_test_packet_alloc() {
// View allocation and configuration
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_draw_callback(instance->view, (ViewDrawCallback)subghz_test_packet_draw);
view_set_input_callback(instance->view, subghz_test_packet_input);

View File

@ -1,4 +1,4 @@
#include "subghz_static.h"
#include "subghz_test_static.h"
#include "../subghz_i.h"
#include <math.h>
@ -8,30 +8,30 @@
#include <notification/notification-messages.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,
0x0074BADD,
0x0074BADB,
0x00E34A4E,
};
struct SubghzStatic {
struct SubghzTestStatic {
View* view;
SubGhzEncoderPrinceton* encoder;
};
typedef enum {
SubghzStaticStatusRx,
SubghzStaticStatusTx,
} SubghzStaticStatus;
SubghzTestStaticStatusRx,
SubghzTestStaticStatusTx,
} SubghzTestStaticStatus;
typedef struct {
uint8_t frequency;
uint32_t real_frequency;
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];
canvas_set_color(canvas, ColorBlack);
@ -52,24 +52,21 @@ void subghz_static_draw(Canvas* canvas, SubghzStaticModel* model) {
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);
SubghzStatic* instance = context;
SubghzTestStatic* instance = context;
if(event->key == InputKeyBack) {
return false;
}
with_view_model(
instance->view, (SubghzStaticModel * model) {
bool reconfigure = false;
instance->view, (SubghzTestStaticModel * model) {
if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
if(model->frequency > 0) model->frequency--;
reconfigure = true;
} else if(event->key == InputKeyRight) {
if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
reconfigure = true;
} else if(event->key == InputKeyDown) {
if(model->button > 0) model->button--;
} else if(event->key == InputKeyUp) {
@ -77,28 +74,29 @@ bool subghz_static_input(InputEvent* event, void* context) {
}
}
if(reconfigure) {
furi_hal_subghz_idle();
model->real_frequency =
furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
furi_hal_subghz_tx();
}
model->real_frequency = subghz_frequencies[model->frequency];
if(event->key == InputKeyOk) {
NotificationApp* notification = furi_record_open("notification");
if(event->type == InputTypePress) {
NotificationApp* notification = furi_record_open("notification");
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(
instance->encoder, subghz_static_keys[model->button], 20);
instance->encoder, subghz_test_static_keys[model->button], 10000);
furi_hal_subghz_start_async_tx(
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();
notification_message(notification, &sequence_reset_red);
furi_record_close("notification");
}
furi_record_close("notification");
}
return true;
@ -107,58 +105,55 @@ bool subghz_static_input(InputEvent* event, void* context) {
return true;
}
void subghz_static_enter(void* context) {
void subghz_test_static_enter(void* context) {
furi_assert(context);
SubghzStatic* instance = context;
SubghzTestStatic* instance = context;
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_write(&gpio_cc1101_g0, false);
with_view_model(
instance->view, (SubghzStaticModel * model) {
instance->view, (SubghzTestStaticModel * model) {
model->frequency = subghz_frequencies_433_92;
model->real_frequency =
furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
model->real_frequency = subghz_frequencies[model->frequency];
model->button = 0;
return true;
});
furi_hal_subghz_tx();
}
void subghz_static_exit(void* context) {
void subghz_test_static_exit(void* context) {
furi_assert(context);
furi_hal_subghz_sleep();
}
SubghzStatic* subghz_static_alloc() {
SubghzStatic* instance = furi_alloc(sizeof(SubghzStatic));
SubghzTestStatic* subghz_test_static_alloc() {
SubghzTestStatic* instance = furi_alloc(sizeof(SubghzTestStatic));
// View allocation and configuration
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_draw_callback(instance->view, (ViewDrawCallback)subghz_static_draw);
view_set_input_callback(instance->view, subghz_static_input);
view_set_enter_callback(instance->view, subghz_static_enter);
view_set_exit_callback(instance->view, subghz_static_exit);
view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_static_draw);
view_set_input_callback(instance->view, subghz_test_static_input);
view_set_enter_callback(instance->view, subghz_test_static_enter);
view_set_exit_callback(instance->view, subghz_test_static_exit);
instance->encoder = subghz_encoder_princeton_alloc();
return instance;
}
void subghz_static_free(SubghzStatic* instance) {
void subghz_test_static_free(SubghzTestStatic* instance) {
furi_assert(instance);
subghz_encoder_princeton_free(instance->encoder);
view_free(instance->view);
free(instance);
}
View* subghz_static_get_view(SubghzStatic* instance) {
View* subghz_test_static_get_view(SubghzTestStatic* instance) {
furi_assert(instance);
return instance->view;
}

View 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);

View File

@ -7,8 +7,7 @@
#include <input/input.h>
#include <gui/elements.h>
#include <notification/notification-messages.h>
#include <assets_icons.h>
#include <lib/subghz/protocols/subghz_protocol_keeloq.h>
struct SubghzTransmitter {
View* view;
@ -19,6 +18,8 @@ struct SubghzTransmitter {
typedef struct {
string_t text;
uint16_t scene;
uint32_t real_frequency;
FuriHalSubGhzPreset preset;
SubGhzProtocolCommon* protocol;
} 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) {
char buffer[64];
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
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) {
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) {
furi_assert(context);
SubghzTransmitter* subghz_transmitter = context;
bool can_be_send = false;
bool can_be_sent = false;
if(event->key == InputKeyBack) {
return false;
}
with_view_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);
model->protocol->to_string(model->protocol, model->text);
return true;
});
//if(event->type != InputTypeShort) return false;
if(event->key == InputKeyBack) {
return false;
} else if(can_be_send && event->key == InputKeyOk && event->type == InputTypePress) {
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context);
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);
return true;
}
@ -96,6 +163,7 @@ void subghz_transmitter_enter(void* context) {
SubghzTransmitter* subghz_transmitter = context;
with_view_model(
subghz_transmitter->view, (SubghzTransmitterModel * model) {
string_clean(model->text);
model->protocol->to_string(model->protocol, model->text);
return true;
});

View File

@ -7,6 +7,7 @@ typedef enum {
SubghzTransmitterEventSendStart,
SubghzTransmitterEventSendStop,
SubghzTransmitterEventBack,
SubghzTransmitterEventNoMan,
} SubghzTransmitterEvent;
typedef struct SubghzTransmitter SubghzTransmitter;
@ -27,3 +28,7 @@ View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter);
void subghz_transmitter_set_protocol(
SubghzTransmitter* subghz_transmitter,
SubGhzProtocolCommon* protocol);
void subghz_transmitter_set_frequency_preset(
SubghzTransmitter* subghz_transmitter,
uint32_t frequency,
FuriHalSubGhzPreset preset);

View File

@ -1,11 +1,12 @@
#include <furi.h>
#include "../minunit.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_necext_test_data.srcdata"
#include "test_data/irda_samsung_test_data.srcdata"
#include "test_data/irda_rc6_test_data.srcdata"
#include "test_data/irda_rc5_test_data.srcdata"
#define RUN_ENCODER(data, expected) \
run_encoder((data), COUNT_OF(data), (expected), COUNT_OF(expected))
@ -153,16 +154,19 @@ MU_TEST(test_decoder_samsung32) {
}
MU_TEST(test_mix) {
RUN_DECODER(test_decoder_rc5_input2, test_decoder_rc5_expected2);
RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1);
// can use encoder data for decoding, but can't do opposite
RUN_DECODER(test_encoder_rc6_expected1, test_encoder_rc6_input1);
RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_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_rc5_input1, test_decoder_rc5_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_rc6_input1, test_decoder_rc6_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);
}
@ -187,6 +191,25 @@ MU_TEST(test_decoder_necext1) {
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) {
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_samsung32_all, COUNT_OF(test_samsung32_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_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_nec1);
MU_RUN_TEST(test_decoder_nec2);
MU_RUN_TEST(test_decoder_samsung32);
MU_RUN_TEST(test_decoder_necext1);
MU_RUN_TEST(test_mix);
MU_RUN_TEST(test_decoder_rc6);
MU_RUN_TEST(test_encoder_rc6);
MU_RUN_TEST(test_encoder_decoder_all);
}
int run_minunit_test_irda_decoder_encoder() {

View File

@ -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},
};

View File

@ -15,17 +15,17 @@ _____---------______--____--__--__------____--____--__----____--__----__--__--__
*/
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,
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,
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
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,
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,
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,
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,
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
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,
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,
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, 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,
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
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,
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,
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,
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,
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
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,
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,
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[] = {
@ -54,14 +54,14 @@ const IrdaMessage test_encoder_rc6_input1[] = {
};
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
};

View File

@ -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[] = {_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[] = {_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[] = {_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[] = {_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[] = {_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[] = {_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[] = {_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_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_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_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};
@ -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_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_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_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};
@ -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_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 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_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_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};

View File

@ -14,6 +14,7 @@ extern const Icon I_125_10px;
extern const Icon I_ButtonRightSmall_3x5;
extern const Icon I_ButtonLeft_4x7;
extern const Icon I_ButtonLeftSmall_3x5;
extern const Icon I_DFU_128x50;
extern const Icon I_Warning_30x23;
extern const Icon I_ButtonRight_4x7;
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_Flipper_young_80x60;
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_DoorLeft_8x56;
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_U2F_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_EMV_Chip_14x11;
extern const Icon I_Health_16x16;
extern const Icon I_FaceCharging_29x14;
extern const Icon I_BatteryBody_52x28;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

View 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

View 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

View 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

View File

@ -13,13 +13,57 @@
#include <furi-hal.h>
#include <u8g2.h>
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_DFU_128x50[] = {
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,
};
// Boot request enum
@ -138,8 +182,6 @@ void target_version_save(void) {
void target_usb_wire_reset() {
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() {
@ -155,10 +197,9 @@ void target_display_init() {
u8g2_ClearBuffer(&fb);
u8g2_SetDrawColor(&fb, 0x01);
u8g2_SetFont(&fb, u8g2_font_helvB08_tf);
u8g2_DrawStr(&fb, 2, 8, "Recovery & Update Mode");
u8g2_DrawXBM(&fb, 49, 14, 30, 23, I_Warning_30x23_0);
u8g2_DrawStr(&fb, 2, 50, "DFU Bootloader activated");
u8g2_DrawStr(&fb, 6, 62, "www.flipp.dev/recovery");
u8g2_DrawXBM(&fb, 0, 64 - 50, 128, 50, I_DFU_128x50);
u8g2_DrawStr(&fb, 2, 8, "Update & Recovery Mode");
u8g2_DrawStr(&fb, 2, 21, "DFU started");
// Send buffer
u8g2_SetPowerSave(&fb, 0);
u8g2_SendBuffer(&fb);

View File

@ -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

View File

@ -1,37 +1,30 @@
#include "check.h"
#include "furi-hal-task.h"
#include <furi-hal-console.h>
#include <stdio.h>
void __furi_abort(void);
// TODO printf doesnt work in ISR context
void __furi_check(void) {
printf("assertion failed in release mode, switch to debug mode to see full assert info");
__furi_abort();
void __furi_print_name(void) {
furi_hal_console_puts("\r\n\033[0;31m[E]");
if(task_is_isr_context()) {
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_debug(const char* file, int line, const char* function, const char* condition) {
printf(
"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);
// }
}
void __furi_check(void) {
__furi_print_name();
furi_hal_console_puts("assertion failed\r\n");
__furi_abort();
}

View File

@ -38,7 +38,6 @@ extern "C" {
// !NDEBUG
void __furi_check(void);
void __furi_check_debug(const char* file, int line, const char* function, const char* condition);
#ifdef __cplusplus
}

View File

@ -31,3 +31,12 @@
#ifndef COUNT_OF
#define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
#endif
#ifndef FURI_SWAP
#define FURI_SWAP(x, y) \
do { \
typeof(x) SWAP = x; \
x = y; \
y = SWAP; \
} while(0)
#endif

View File

@ -1,10 +1,10 @@
FROM ubuntu:focal
FROM ubuntu:hirsute
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
ca-certificates \
build-essential \
python3 \
python-lxml \
python3-lxml \
git \
clang-format-12 \
dfu-util \
@ -14,10 +14,10 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-instal
wget && \
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" && \
tar xjf gcc-arm-none-eabi-10-2020-q4-major-$(uname -m)-linux.tar.bz2 && \
rm gcc-arm-none-eabi-10-2020-q4-major-$(uname -m)-linux.tar.bz2 && \
cd gcc-arm-none-eabi-10-2020-q4-major/bin/ && \
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.3-2021.07-$(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.3-2021.07/bin/ && \
rm -rf ../share && \
for file in * ; do ln -s "${PWD}/${file}" "/usr/bin/${file}" ; done && \
cd / && arm-none-eabi-gcc -v && arm-none-eabi-gdb -v

Some files were not shown because too many files have changed in this diff Show More