Merge branch 'release-candidate' into release
81
.github/workflows/build.yml
vendored
@ -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
|
||||
|
||||
6
.github/workflows/lint_c.yml
vendored
@ -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 }}
|
||||
```
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
48
applications/gui/modules/widget_elements/widget_element_frame.c
Executable file
@ -0,0 +1,48 @@
|
||||
#include "widget_element_i.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
uint8_t radius;
|
||||
} GuiFrameModel;
|
||||
|
||||
static void gui_frame_draw(Canvas* canvas, WidgetElement* element) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(element);
|
||||
GuiFrameModel* model = element->model;
|
||||
canvas_draw_rframe(canvas, model->x, model->y, model->width, model->height, model->radius);
|
||||
}
|
||||
|
||||
static void gui_frame_free(WidgetElement* gui_frame) {
|
||||
furi_assert(gui_frame);
|
||||
|
||||
free(gui_frame->model);
|
||||
free(gui_frame);
|
||||
}
|
||||
|
||||
WidgetElement* widget_element_frame_create(
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
uint8_t width,
|
||||
uint8_t height,
|
||||
uint8_t radius) {
|
||||
// Allocate and init model
|
||||
GuiFrameModel* model = furi_alloc(sizeof(GuiFrameModel));
|
||||
model->x = x;
|
||||
model->y = y;
|
||||
model->width = width;
|
||||
model->height = height;
|
||||
model->radius = radius;
|
||||
|
||||
// Allocate and init Element
|
||||
WidgetElement* gui_frame = furi_alloc(sizeof(WidgetElement));
|
||||
gui_frame->parent = NULL;
|
||||
gui_frame->input = NULL;
|
||||
gui_frame->draw = gui_frame_draw;
|
||||
gui_frame->free = gui_frame_free;
|
||||
gui_frame->model = model;
|
||||
|
||||
return gui_frame;
|
||||
}
|
||||
@ -44,5 +44,13 @@ WidgetElement* widget_element_button_create(
|
||||
ButtonCallback callback,
|
||||
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);
|
||||
@ -1,5 +1,4 @@
|
||||
#include "widget_element_i.h"
|
||||
#include <m-string.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
49
applications/nfc/helpers/nfc_emv_parser.c
Executable file
@ -0,0 +1,49 @@
|
||||
#include "nfc_emv_parser.h"
|
||||
|
||||
#include <file-worker.h>
|
||||
|
||||
static bool
|
||||
nfc_emv_parser_get_value(const char* file_path, string_t key, char delimiter, string_t value) {
|
||||
bool found = false;
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
|
||||
if(file_worker_open(file_worker, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
if(file_worker_get_value_from_key(file_worker, key, delimiter, value)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name) {
|
||||
bool result = false;
|
||||
string_t key;
|
||||
string_init(key);
|
||||
for(uint8_t i = 0; i < aid_len; i++) {
|
||||
string_cat_printf(key, "%02X", aid[i]);
|
||||
}
|
||||
result = nfc_emv_parser_get_value("/ext/nfc/emv/aid.nfc", key, ' ', aid_name);
|
||||
string_clear(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name) {
|
||||
bool result = false;
|
||||
string_t key;
|
||||
string_init_printf(key, "%04X", country_code);
|
||||
result = nfc_emv_parser_get_value("/ext/nfc/emv/country_code.nfc", key, ' ', country_name);
|
||||
string_clear(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name) {
|
||||
bool result = false;
|
||||
string_t key;
|
||||
string_init_printf(key, "%04X", currency_code);
|
||||
result = nfc_emv_parser_get_value("/ext/nfc/emv/currency_code.nfc", key, ' ', currency_name);
|
||||
string_clear(key);
|
||||
return result;
|
||||
}
|
||||
27
applications/nfc/helpers/nfc_emv_parser.h
Executable file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <m-string.h>
|
||||
|
||||
/** Get EMV application name by number
|
||||
* @param aid - AID number array
|
||||
* @param aid_len - AID length
|
||||
* @param aid_name - string to keep AID name
|
||||
* @return - true if AID found, false otherwies
|
||||
*/
|
||||
bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name);
|
||||
|
||||
/** Get country name by country code
|
||||
* @param country_code - ISO 3166 country code
|
||||
* @param country_name - string to keep country name
|
||||
* @return - true if country found, false otherwies
|
||||
*/
|
||||
bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name);
|
||||
|
||||
/** Get currency name by currency code
|
||||
* @param currency_code - ISO 3166 currency code
|
||||
* @param currency_name - string to keep currency name
|
||||
* @return - true if currency found, false otherwies
|
||||
*/
|
||||
bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name);
|
||||
@ -54,7 +54,7 @@ void nfc_cli_emulate(Cli* cli, string_t args, void* context) {
|
||||
printf("Emulating NFC-A Type: T2T UID: CF72D440 SAK: 20 ATQA: 00/04\r\n");
|
||||
printf("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},
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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},
|
||||
|
||||
@ -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
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
const void subghz_scene_analyze_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewAnalyze);
|
||||
}
|
||||
|
||||
const bool subghz_scene_analyze_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
notification_message(subghz->notifications, &sequence_blink_blue_10);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const void subghz_scene_analyze_on_exit(void* context) {
|
||||
// SubGhz* subghz = context;
|
||||
}
|
||||
@ -1,13 +1,12 @@
|
||||
ADD_SCENE(subghz, start, Start)
|
||||
ADD_SCENE(subghz, 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)
|
||||
|
||||
48
applications/subghz/scenes/subghz_scene_no_man.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define SCENE_NO_MAN_CUSTOM_EVENT (11UL)
|
||||
|
||||
void subghz_scene_no_man_popup_callback(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_NO_MAN_CUSTOM_EVENT);
|
||||
}
|
||||
|
||||
const void subghz_scene_no_man_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
Popup* popup = subghz->popup;
|
||||
popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51);
|
||||
popup_set_header(popup, "No manufactory key", 13, 8, AlignLeft, AlignBottom);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_set_context(popup, subghz);
|
||||
popup_set_callback(popup, subghz_scene_no_man_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
|
||||
}
|
||||
|
||||
const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneStart);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const void subghz_scene_no_man_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
Popup* popup = subghz->popup;
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
popup_set_icon(popup, 0, 0, NULL);
|
||||
popup_set_callback(popup, NULL);
|
||||
popup_set_context(popup, NULL);
|
||||
popup_set_timeout(popup, 0);
|
||||
popup_disable_timeout(popup);
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define GUBGHZ_READ_CUSTOM_EVENT (10UL)
|
||||
|
||||
void subghz_read_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
subghz->protocol_result = parser;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, GUBGHZ_READ_CUSTOM_EVENT);
|
||||
}
|
||||
void subghz_scene_read_callback(DialogExResult result, void* context) {
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, result);
|
||||
}
|
||||
|
||||
const void subghz_scene_read_on_enter(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Setup view
|
||||
DialogEx* dialog_ex = subghz->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "SubGhz 433.92", 36, 6, AlignLeft, AlignCenter);
|
||||
dialog_ex_set_icon(dialog_ex, 10, 12, &I_RFIDDolphinReceive_97x61);
|
||||
|
||||
//Start CC1101 rx
|
||||
subghz_begin(FuriHalSubGhzPresetOokAsync);
|
||||
subghz_rx(433920000);
|
||||
|
||||
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->worker);
|
||||
subghz_worker_start(subghz->worker);
|
||||
subghz_protocol_enable_dump(subghz->protocol, subghz_read_protocol_callback, subghz);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewDialogEx);
|
||||
}
|
||||
|
||||
const bool subghz_scene_read_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhz* subghz = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GUBGHZ_READ_CUSTOM_EVENT) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
|
||||
notification_message(subghz->notifications, &sequence_success);
|
||||
return true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
notification_message(subghz->notifications, &sequence_blink_blue_10);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const void subghz_scene_read_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Stop CC1101
|
||||
subghz_worker_stop(subghz->worker);
|
||||
furi_hal_subghz_stop_async_rx();
|
||||
subghz_end();
|
||||
|
||||
DialogEx* dialog_ex = subghz->dialog_ex;
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
}
|
||||
@ -13,7 +13,9 @@ const void subghz_scene_receiver_on_enter(void* context) {
|
||||
|
||||
subghz_receiver_set_callback(subghz_receiver, subghz_scene_receiver_callback, subghz);
|
||||
|
||||
subghz_receiver_set_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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
164
applications/subghz/subghz_history.c
Normal file
@ -0,0 +1,164 @@
|
||||
#include "subghz_history.h"
|
||||
#include <lib/subghz/protocols/subghz_protocol_keeloq.h>
|
||||
#include <lib/subghz/protocols/subghz_protocol_star_line.h>
|
||||
#include <lib/subghz/protocols/subghz_protocol_princeton.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <m-string.h>
|
||||
|
||||
#define SUBGHZ_HISTORY_MAX 50
|
||||
|
||||
typedef struct SubGhzHistoryStruct SubGhzHistoryStruct;
|
||||
|
||||
struct SubGhzHistoryStruct {
|
||||
const char* name;
|
||||
const char* manufacture_name;
|
||||
uint8_t type_protocol;
|
||||
uint8_t code_count_bit;
|
||||
uint64_t code_found;
|
||||
uint16_t te;
|
||||
FuriHalSubGhzPreset preset;
|
||||
uint32_t real_frequency;
|
||||
};
|
||||
|
||||
struct SubGhzHistory {
|
||||
uint32_t last_update_timestamp;
|
||||
uint16_t last_index_write;
|
||||
uint64_t code_last_found;
|
||||
SubGhzHistoryStruct history[SUBGHZ_HISTORY_MAX];
|
||||
SubGhzProtocolCommonLoad data;
|
||||
};
|
||||
|
||||
SubGhzHistory* subghz_history_alloc(void) {
|
||||
SubGhzHistory* instance = furi_alloc(sizeof(SubGhzHistory));
|
||||
return instance;
|
||||
}
|
||||
|
||||
void subghz_history_free(SubGhzHistory* instance) {
|
||||
furi_assert(instance);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void subghz_history_set_frequency_preset(
|
||||
SubGhzHistory* instance,
|
||||
uint16_t idx,
|
||||
uint32_t frequency,
|
||||
FuriHalSubGhzPreset preset) {
|
||||
furi_assert(instance);
|
||||
if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return;
|
||||
instance->history[idx].preset = preset;
|
||||
instance->history[idx].real_frequency = frequency;
|
||||
}
|
||||
|
||||
uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx) {
|
||||
furi_assert(instance);
|
||||
return instance->history[idx].real_frequency;
|
||||
}
|
||||
|
||||
FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) {
|
||||
furi_assert(instance);
|
||||
return instance->history[idx].preset;
|
||||
}
|
||||
|
||||
void subghz_history_clean(SubGhzHistory* instance) {
|
||||
furi_assert(instance);
|
||||
instance->last_index_write = 0;
|
||||
instance->code_last_found = 0;
|
||||
}
|
||||
|
||||
uint16_t subghz_history_get_item(SubGhzHistory* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->last_index_write;
|
||||
}
|
||||
|
||||
uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx) {
|
||||
furi_assert(instance);
|
||||
return instance->history[idx].type_protocol;
|
||||
}
|
||||
|
||||
const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx) {
|
||||
furi_assert(instance);
|
||||
return instance->history[idx].name;
|
||||
}
|
||||
|
||||
SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx) {
|
||||
furi_assert(instance);
|
||||
instance->data.code_found = instance->history[idx].code_found;
|
||||
instance->data.code_count_bit = instance->history[idx].code_count_bit;
|
||||
instance->data.param1 = instance->history[idx].te;
|
||||
return &instance->data;
|
||||
}
|
||||
bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) {
|
||||
furi_assert(instance);
|
||||
if(instance->last_index_write == SUBGHZ_HISTORY_MAX) {
|
||||
if(output != NULL) string_printf(output, "Memory is FULL");
|
||||
return true;
|
||||
}
|
||||
if(output != NULL)
|
||||
string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
|
||||
return false;
|
||||
}
|
||||
void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) {
|
||||
if(instance->history[idx].code_count_bit < 33) {
|
||||
string_printf(
|
||||
output,
|
||||
"%s %lX",
|
||||
instance->history[idx].name,
|
||||
(uint32_t)(instance->history[idx].code_found & 0xFFFFFFFF));
|
||||
} else {
|
||||
string_t str_buff;
|
||||
string_init(str_buff);
|
||||
if(strcmp(instance->history[idx].name, "KeeLoq") == 0) {
|
||||
string_set(str_buff, "KL ");
|
||||
string_cat(str_buff, instance->history[idx].manufacture_name);
|
||||
} else if(strcmp(instance->history[idx].name, "Star Line") == 0) {
|
||||
string_set(str_buff, "SL ");
|
||||
string_cat(str_buff, instance->history[idx].manufacture_name);
|
||||
} else {
|
||||
string_set(str_buff, instance->history[idx].name);
|
||||
}
|
||||
|
||||
string_printf(
|
||||
output,
|
||||
"%s %lX%08lX",
|
||||
string_get_cstr(str_buff),
|
||||
(uint32_t)(instance->history[idx].code_found >> 32),
|
||||
(uint32_t)(instance->history[idx].code_found & 0xFFFFFFFF));
|
||||
string_clear(str_buff);
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_history_add_to_history(SubGhzHistory* instance, void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(context);
|
||||
SubGhzProtocolCommon* protocol = context;
|
||||
|
||||
if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return;
|
||||
if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) &&
|
||||
((millis() - instance->last_update_timestamp) < 500)) {
|
||||
instance->last_update_timestamp = millis();
|
||||
return;
|
||||
}
|
||||
|
||||
instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF;
|
||||
instance->last_update_timestamp = millis();
|
||||
|
||||
instance->history[instance->last_index_write].te = 0;
|
||||
instance->history[instance->last_index_write].manufacture_name = NULL;
|
||||
instance->history[instance->last_index_write].name = protocol->name;
|
||||
instance->history[instance->last_index_write].code_count_bit = protocol->code_last_count_bit;
|
||||
instance->history[instance->last_index_write].code_found = protocol->code_last_found;
|
||||
if(strcmp(protocol->name, "KeeLoq") == 0) {
|
||||
instance->history[instance->last_index_write].manufacture_name =
|
||||
subghz_protocol_keeloq_find_and_get_manufacture_name(protocol);
|
||||
} else if(strcmp(protocol->name, "Star Line") == 0) {
|
||||
instance->history[instance->last_index_write].manufacture_name =
|
||||
subghz_protocol_star_line_find_and_get_manufacture_name(protocol);
|
||||
} else if(strcmp(protocol->name, "Princeton") == 0) {
|
||||
instance->history[instance->last_index_write].te =
|
||||
subghz_protocol_princeton_get_te(protocol);
|
||||
}
|
||||
instance->history[instance->last_index_write].type_protocol = protocol->type_protocol;
|
||||
|
||||
instance->last_index_write++;
|
||||
}
|
||||
106
applications/subghz/subghz_history.h
Normal file
@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/subghz/protocols/subghz_protocol_common.h>
|
||||
|
||||
typedef struct SubGhzHistory SubGhzHistory;
|
||||
|
||||
/** Allocate SubGhzHistory
|
||||
*
|
||||
* @return SubGhzHistory*
|
||||
*/
|
||||
SubGhzHistory* subghz_history_alloc(void);
|
||||
|
||||
/** Free SubGhzHistory
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
*/
|
||||
void subghz_history_free(SubGhzHistory* instance);
|
||||
|
||||
/** Clear history
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
*/
|
||||
void subghz_history_clean(SubGhzHistory* instance);
|
||||
|
||||
/** Set frequency and preset to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @param frequency - frequency Hz
|
||||
* @param preset - FuriHalSubGhzPreset preset
|
||||
*/
|
||||
void subghz_history_set_frequency_preset(
|
||||
SubGhzHistory* instance,
|
||||
uint16_t idx,
|
||||
uint32_t frequency,
|
||||
FuriHalSubGhzPreset preset);
|
||||
|
||||
/** Get frequency to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return frequency - frequency Hz
|
||||
*/
|
||||
uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get preset to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return preset - FuriHalSubGhzPreset preset
|
||||
*/
|
||||
FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get history index write
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @return idx - current record index
|
||||
*/
|
||||
uint16_t subghz_history_get_item(SubGhzHistory* instance);
|
||||
|
||||
/** Get type protocol to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return type - type protocol
|
||||
*/
|
||||
uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get name protocol to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return name - const char* name protocol
|
||||
*/
|
||||
const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx);
|
||||
|
||||
/** Get string item menu to history[idx]
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param output - string_t output
|
||||
* @param idx - record index
|
||||
*/
|
||||
void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx);
|
||||
|
||||
/** Get string the remaining number of records to history
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param output - string_t output
|
||||
* @return bool - is FUUL
|
||||
*/
|
||||
bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output);
|
||||
|
||||
/** Add protocol to history
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param context - SubGhzProtocolCommon context
|
||||
*/
|
||||
void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
|
||||
|
||||
/** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
|
||||
*
|
||||
* @param instance - SubGhzHistory instance
|
||||
* @param idx - record index
|
||||
* @return SubGhzProtocolCommonLoad*
|
||||
*/
|
||||
SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
|
||||
@ -8,6 +8,7 @@
|
||||
#include <notification/notification-messages.h>
|
||||
#include "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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -1,233 +0,0 @@
|
||||
#include "subghz_analyze.h"
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <furi.h>
|
||||
#include <furi-hal.h>
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
#include <notification/notification-messages.h>
|
||||
|
||||
#include <lib/subghz/subghz_worker.h>
|
||||
#include <lib/subghz/protocols/subghz_protocol.h>
|
||||
|
||||
#include <assets_icons.h>
|
||||
|
||||
struct SubghzAnalyze {
|
||||
View* view;
|
||||
SubGhzWorker* worker;
|
||||
SubGhzProtocol* protocol;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t frequency;
|
||||
uint32_t real_frequency;
|
||||
uint32_t counter;
|
||||
string_t text;
|
||||
uint16_t scene;
|
||||
SubGhzProtocolCommon parser;
|
||||
} SubghzAnalyzeModel;
|
||||
|
||||
static const char subghz_symbols[] = {'-', '\\', '|', '/'};
|
||||
|
||||
void subghz_analyze_draw(Canvas* canvas, SubghzAnalyzeModel* model) {
|
||||
char buffer[64];
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"Analyze: %03ld.%03ldMHz %c",
|
||||
model->real_frequency / 1000000 % 1000,
|
||||
model->real_frequency / 1000 % 1000,
|
||||
subghz_symbols[model->counter % 4]);
|
||||
canvas_draw_str(canvas, 0, 8, buffer);
|
||||
|
||||
switch(model->scene) {
|
||||
case 1:
|
||||
canvas_draw_icon(canvas, 0, 10, &I_RFIDDolphinReceive_97x61);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_box(canvas, 80, 12, 20, 20);
|
||||
canvas_invert_color(canvas);
|
||||
canvas_draw_icon(canvas, 75, 18, &I_sub1_10px);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 90, 38, AlignCenter, AlignTop, "Detecting\r\nSubGhz");
|
||||
break;
|
||||
|
||||
default:
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text(canvas, 0, 20, string_get_cstr(model->text));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool subghz_analyze_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubghzAnalyze* subghz_analyze = context;
|
||||
|
||||
if(event->type != InputTypeShort) return false;
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
with_view_model(
|
||||
subghz_analyze->view, (SubghzAnalyzeModel * model) {
|
||||
bool model_updated = false;
|
||||
|
||||
if(event->key == InputKeyLeft) {
|
||||
if(model->frequency > 0) model->frequency--;
|
||||
model_updated = true;
|
||||
} else if(event->key == InputKeyRight) {
|
||||
if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
|
||||
model_updated = true;
|
||||
}
|
||||
|
||||
if(model_updated) {
|
||||
furi_hal_subghz_idle();
|
||||
model->real_frequency =
|
||||
furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
|
||||
furi_hal_subghz_rx();
|
||||
}
|
||||
|
||||
return model_updated;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void subghz_analyze_text_callback(string_t text, void* context) {
|
||||
furi_assert(context);
|
||||
SubghzAnalyze* subghz_analyze = context;
|
||||
|
||||
with_view_model(
|
||||
subghz_analyze->view, (SubghzAnalyzeModel * model) {
|
||||
model->counter++;
|
||||
string_set(model->text, text);
|
||||
model->scene = 0;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void subghz_analyze_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
|
||||
furi_assert(context);
|
||||
SubghzAnalyze* subghz_analyze = context;
|
||||
char buffer[64];
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%s\r\n"
|
||||
"K:%lX%lX\r\n"
|
||||
"SN:%lX\r\n"
|
||||
"BTN:%X",
|
||||
parser->name,
|
||||
(uint32_t)(parser->code_found >> 32),
|
||||
(uint32_t)(parser->code_found & 0x00000000FFFFFFFF),
|
||||
parser->serial,
|
||||
parser->btn);
|
||||
|
||||
with_view_model(
|
||||
subghz_analyze->view, (SubghzAnalyzeModel * model) {
|
||||
model->counter++;
|
||||
model->parser = *parser;
|
||||
string_set(model->text, buffer);
|
||||
model->scene = 0;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void subghz_analyze_enter(void* context) {
|
||||
furi_assert(context);
|
||||
SubghzAnalyze* subghz_analyze = context;
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_idle();
|
||||
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
|
||||
|
||||
with_view_model(
|
||||
subghz_analyze->view, (SubghzAnalyzeModel * model) {
|
||||
model->frequency = subghz_frequencies_433_92;
|
||||
model->real_frequency =
|
||||
furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
|
||||
model->scene = 1;
|
||||
return true;
|
||||
});
|
||||
|
||||
hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz_analyze->worker);
|
||||
|
||||
subghz_worker_start(subghz_analyze->worker);
|
||||
|
||||
furi_hal_subghz_flush_rx();
|
||||
furi_hal_subghz_rx();
|
||||
}
|
||||
|
||||
void subghz_analyze_exit(void* context) {
|
||||
furi_assert(context);
|
||||
SubghzAnalyze* subghz_analyze = context;
|
||||
|
||||
subghz_worker_stop(subghz_analyze->worker);
|
||||
|
||||
furi_hal_subghz_stop_async_rx();
|
||||
furi_hal_subghz_sleep();
|
||||
}
|
||||
|
||||
SubghzAnalyze* subghz_analyze_alloc() {
|
||||
SubghzAnalyze* subghz_analyze = furi_alloc(sizeof(SubghzAnalyze));
|
||||
|
||||
// View allocation and configuration
|
||||
subghz_analyze->view = view_alloc();
|
||||
view_allocate_model(subghz_analyze->view, ViewModelTypeLocking, sizeof(SubghzAnalyzeModel));
|
||||
view_set_context(subghz_analyze->view, subghz_analyze);
|
||||
view_set_draw_callback(subghz_analyze->view, (ViewDrawCallback)subghz_analyze_draw);
|
||||
view_set_input_callback(subghz_analyze->view, subghz_analyze_input);
|
||||
view_set_enter_callback(subghz_analyze->view, subghz_analyze_enter);
|
||||
view_set_exit_callback(subghz_analyze->view, subghz_analyze_exit);
|
||||
|
||||
with_view_model(
|
||||
subghz_analyze->view, (SubghzAnalyzeModel * model) {
|
||||
string_init(model->text);
|
||||
return true;
|
||||
});
|
||||
|
||||
subghz_analyze->worker = subghz_worker_alloc();
|
||||
subghz_analyze->protocol = subghz_protocol_alloc();
|
||||
|
||||
subghz_worker_set_overrun_callback(
|
||||
subghz_analyze->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset);
|
||||
subghz_worker_set_pair_callback(
|
||||
subghz_analyze->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse);
|
||||
subghz_worker_set_context(subghz_analyze->worker, subghz_analyze->protocol);
|
||||
|
||||
subghz_protocol_load_keeloq_file(
|
||||
subghz_analyze->protocol, "/ext/assets/subghz/keeloq_mfcodes");
|
||||
subghz_protocol_load_nice_flor_s_file(
|
||||
subghz_analyze->protocol, "/ext/assets/subghz/nice_floor_s_rx");
|
||||
subghz_protocol_enable_dump_text(
|
||||
subghz_analyze->protocol, subghz_analyze_text_callback, subghz_analyze);
|
||||
|
||||
return subghz_analyze;
|
||||
}
|
||||
|
||||
void subghz_analyze_free(SubghzAnalyze* subghz_analyze) {
|
||||
furi_assert(subghz_analyze);
|
||||
|
||||
subghz_protocol_free(subghz_analyze->protocol);
|
||||
subghz_worker_free(subghz_analyze->worker);
|
||||
|
||||
with_view_model(
|
||||
subghz_analyze->view, (SubghzAnalyzeModel * model) {
|
||||
string_clear(model->text);
|
||||
return true;
|
||||
});
|
||||
view_free(subghz_analyze->view);
|
||||
free(subghz_analyze);
|
||||
}
|
||||
|
||||
View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze) {
|
||||
furi_assert(subghz_analyze);
|
||||
return subghz_analyze->view;
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct SubghzAnalyze SubghzAnalyze;
|
||||
|
||||
SubghzAnalyze* subghz_analyze_alloc();
|
||||
|
||||
void subghz_analyze_free(SubghzAnalyze* subghz_analyze);
|
||||
|
||||
View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze);
|
||||
@ -1,25 +1,74 @@
|
||||
#include "subghz_receiver.h"
|
||||
#include "../subghz_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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct SubghzStatic SubghzStatic;
|
||||
|
||||
SubghzStatic* subghz_static_alloc();
|
||||
|
||||
void subghz_static_free(SubghzStatic* subghz_static);
|
||||
|
||||
View* subghz_static_get_view(SubghzStatic* subghz_static);
|
||||
@ -71,41 +71,37 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
11
applications/subghz/views/subghz_test_static.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct SubghzTestStatic SubghzTestStatic;
|
||||
|
||||
SubghzTestStatic* subghz_test_static_alloc();
|
||||
|
||||
void subghz_test_static_free(SubghzTestStatic* subghz_static);
|
||||
|
||||
View* subghz_test_static_get_view(SubghzTestStatic* subghz_static);
|
||||
@ -7,8 +7,7 @@
|
||||
#include <input/input.h>
|
||||
#include <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;
|
||||
});
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -0,0 +1,160 @@
|
||||
/*
|
||||
_______----__--____----__--____--__----____----__--__--__--__
|
||||
| 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
|
||||
s1 s2 t | address | command |
|
||||
*/
|
||||
|
||||
const uint32_t test_decoder_rc5x_input1[] = {
|
||||
27000 + 888, 1776, 888, 888, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888,
|
||||
};
|
||||
|
||||
const IrdaMessage test_decoder_rc5x_expected1[] = {
|
||||
{IrdaProtocolRC5X, 0x13, 0x10, false}, // toggle 0
|
||||
};
|
||||
|
||||
/*
|
||||
_______--__----____----__--____--__----____----__--__--__--__
|
||||
| 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
|
||||
s1 s2 t | address | command |
|
||||
*/
|
||||
|
||||
const uint32_t test_decoder_rc5_input1[] = {
|
||||
27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888,
|
||||
};
|
||||
|
||||
const IrdaMessage test_decoder_rc5_expected1[] = {
|
||||
{IrdaProtocolRC5, 0x13, 0x10, false}, // toggle 0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
_______--__--__--__----__--____--__----____----__--__--__--__
|
||||
| 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
|
||||
s1 s2 t | address | command |
|
||||
*/
|
||||
|
||||
const uint32_t test_decoder_rc5_input2[] = {
|
||||
27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888,
|
||||
};
|
||||
|
||||
const IrdaMessage test_decoder_rc5_expected2[] = {
|
||||
{IrdaProtocolRC5, 0x13, 0x10, false}, // toggle 1
|
||||
};
|
||||
|
||||
/*
|
||||
_______--__----____----__--____--__----____----__--__--____--
|
||||
| 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
|
||||
s1 s2 t | address | command |
|
||||
*/
|
||||
|
||||
const uint32_t test_decoder_rc5_input3[] = {
|
||||
27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888,
|
||||
};
|
||||
|
||||
const IrdaMessage test_decoder_rc5_expected3[] = {
|
||||
{IrdaProtocolRC5, 0x13, 0x11, false}, // toggle 0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
_______--__--__--__----__--____--__----____----__--__--____--
|
||||
| 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
|
||||
s1 s2 t | address | command |
|
||||
*/
|
||||
|
||||
const uint32_t test_decoder_rc5_input4[] = {
|
||||
27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888,
|
||||
};
|
||||
|
||||
const IrdaMessage test_decoder_rc5_expected4[] = {
|
||||
{IrdaProtocolRC5, 0x13, 0x11, false}, // toggle 1
|
||||
};
|
||||
|
||||
/*
|
||||
_______--__----____--__--__--__--__--__--__--__--__--__--__--
|
||||
| 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
|
||||
s1 s2 t | address | command |
|
||||
*/
|
||||
|
||||
const uint32_t test_decoder_rc5_input5[] = {
|
||||
27000 + 888, 888, 888, 1776, 1776, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888,
|
||||
};
|
||||
|
||||
const IrdaMessage test_decoder_rc5_expected5[] = {
|
||||
{IrdaProtocolRC5, 0x1F, 0x3F, false}, // toggle 0
|
||||
};
|
||||
|
||||
/*
|
||||
_______--__--__--__--__--__--__--__--__--__--__--__--__--__--
|
||||
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
|
||||
s1 s2 t | address | command |
|
||||
*/
|
||||
|
||||
const uint32_t test_decoder_rc5_input6[] = {
|
||||
27000 + 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888,
|
||||
};
|
||||
|
||||
const IrdaMessage test_decoder_rc5_expected6[] = {
|
||||
{IrdaProtocolRC5, 0x1F, 0x3F, false}, // toggle 1
|
||||
};
|
||||
|
||||
|
||||
const uint32_t test_decoder_rc5_input_all_repeats[] = {
|
||||
27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888,
|
||||
27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888,
|
||||
27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888,
|
||||
27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888,
|
||||
27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 1776, 888,
|
||||
27000 + 888, 888, 888, 888, 888, 888, 888, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888,
|
||||
27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888,
|
||||
27000 + 888, 888, 888, 1776, 1776, 1776, 888, 888, 1776, 888, 888, 1776, 1776, 1776, 888, 888, 888, 888, 888, 888,
|
||||
27000 + 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888,
|
||||
27000 + 888, 888, 888, 1776, 1776, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888,
|
||||
27000 + 888, 888, 888, 1776, 1776, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888,
|
||||
};
|
||||
|
||||
const IrdaMessage test_decoder_rc5_expected_all_repeats[] = {
|
||||
{IrdaProtocolRC5, 0x13, 0x11, false}, // toggle 0
|
||||
{IrdaProtocolRC5, 0x13, 0x11, false}, // toggle 1
|
||||
{IrdaProtocolRC5, 0x13, 0x11, true}, // toggle 1
|
||||
{IrdaProtocolRC5, 0x13, 0x11, true}, // toggle 1
|
||||
{IrdaProtocolRC5, 0x13, 0x11, false}, // toggle 0
|
||||
{IrdaProtocolRC5, 0x13, 0x10, false}, // toggle 1
|
||||
{IrdaProtocolRC5, 0x13, 0x10, false}, // toggle 0
|
||||
{IrdaProtocolRC5, 0x13, 0x10, true}, // toggle 0
|
||||
{IrdaProtocolRC5, 0x1F, 0x3F, false}, // toggle 1
|
||||
{IrdaProtocolRC5, 0x1F, 0x3F, false}, // toggle 0
|
||||
{IrdaProtocolRC5, 0x1F, 0x3F, true}, // toggle 0
|
||||
};
|
||||
|
||||
|
||||
const IrdaMessage test_rc5_all[] = {
|
||||
{IrdaProtocolRC5, 0x1F, 0x3F, false},
|
||||
{IrdaProtocolRC5, 0x00, 0x00, false},
|
||||
{IrdaProtocolRC5, 0x10, 0x01, false},
|
||||
{IrdaProtocolRC5, 0x01, 0x20, false},
|
||||
{IrdaProtocolRC5, 0x01, 0x20, false},
|
||||
{IrdaProtocolRC5, 0x01, 0x20, true},
|
||||
{IrdaProtocolRC5, 0x01, 0x20, true},
|
||||
{IrdaProtocolRC5, 0x01, 0x20, true},
|
||||
{IrdaProtocolRC5, 0x01, 0x20, true},
|
||||
{IrdaProtocolRC5, 0x1F, 0x3F, false},
|
||||
{IrdaProtocolRC5, 0x0A, 0x2A, false},
|
||||
{IrdaProtocolRC5, 0x15, 0x15, false},
|
||||
{IrdaProtocolRC5, 0x15, 0x15, true},
|
||||
|
||||
{IrdaProtocolRC5X, 0x1F, 0x3F, false},
|
||||
{IrdaProtocolRC5X, 0x00, 0x00, false},
|
||||
{IrdaProtocolRC5X, 0x10, 0x01, false},
|
||||
{IrdaProtocolRC5X, 0x01, 0x20, false},
|
||||
{IrdaProtocolRC5X, 0x01, 0x20, false},
|
||||
{IrdaProtocolRC5X, 0x01, 0x20, true},
|
||||
{IrdaProtocolRC5X, 0x01, 0x20, true},
|
||||
{IrdaProtocolRC5X, 0x01, 0x20, true},
|
||||
{IrdaProtocolRC5X, 0x01, 0x20, true},
|
||||
{IrdaProtocolRC5X, 0x1F, 0x3F, false},
|
||||
{IrdaProtocolRC5X, 0x0A, 0x2A, false},
|
||||
{IrdaProtocolRC5X, 0x15, 0x15, false},
|
||||
{IrdaProtocolRC5X, 0x15, 0x15, true},
|
||||
};
|
||||
|
||||
@ -15,17 +15,17 @@ _____---------______--____--__--__------____--____--__----____--__----__--__--__
|
||||
*/
|
||||
|
||||
const uint32_t test_decoder_rc6_input1[] = {
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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;
|
||||
|
||||
BIN
assets/icons/Common/DFU_128x50.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
assets/icons/GubGHz/Scanning_123x52.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/GubGHz/quest_7x8.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/GubGHz/unlock_7x8.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/NFC/Detailed_chip_17x13.png
Normal file
|
After Width: | Height: | Size: 981 B |
148
assets/resources/nfc/emv/aid.nfc
Normal file
@ -0,0 +1,148 @@
|
||||
A00000000305076010 VISA ELO Credit
|
||||
A0000000031010 VISA Debit/Credit (Classic)
|
||||
A000000003101001 VISA Credit
|
||||
A000000003101002 VISA Debit
|
||||
A0000000032010 VISA Electron
|
||||
A0000000032020 VISA
|
||||
A0000000033010 VISA Interlink
|
||||
A0000000034010 VISA Specific
|
||||
A0000000035010 VISA Specific
|
||||
A0000000036010 Domestic Visa Cash
|
||||
A0000000036020 International Visa Cash
|
||||
A0000000038002 VISA Auth EMV-CAP (DPA)
|
||||
A0000000038010 VISA Plus
|
||||
A0000000039010 VISA Loyalty
|
||||
A000000003999910 VISA Proprietary ATM
|
||||
A00000000401 MasterCard PayPass
|
||||
A0000000041010 MasterCard Global
|
||||
A00000000410101213 MasterCard Credit
|
||||
A00000000410101215 MasterCard Credit
|
||||
A0000000042010 MasterCard Specific
|
||||
A0000000043010 MasterCard Specific
|
||||
A0000000043060 Maestro (Debit)
|
||||
A000000004306001 Maestro (Debit)
|
||||
A0000000044010 MasterCard Specific
|
||||
A0000000045010 MasterCard Specific
|
||||
A0000000046000 Cirrus
|
||||
A0000000048002 SecureCode EMV-CAP
|
||||
A0000000049999 MasterCard PayPass
|
||||
A0000000050001 Maestro UK
|
||||
A0000000050002 Solo
|
||||
A00000002401 Self Service
|
||||
A000000025 American Express
|
||||
A0000000250000 American Express
|
||||
A00000002501 American Express
|
||||
A000000025010402 American Express
|
||||
A000000025010701 ExpressPay
|
||||
A000000025010801 American Express
|
||||
A0000000291010 Link / American Express
|
||||
A0000000421010 Cartes Bancaire EMV Card
|
||||
A0000000426010 Apple Pay
|
||||
A00000006510 JCB
|
||||
A0000000651010 JCB J Smart Credit
|
||||
A00000006900 Moneo
|
||||
A000000077010000021000000000003B Visa AEPN
|
||||
A000000098 Debit Card
|
||||
A0000000980848 Debit Card
|
||||
A0000001211010 Dankort VISA GEM Vision
|
||||
A0000001410001 PagoBANCOMAT
|
||||
A0000001523010 Discover, Pulse D Pas
|
||||
A0000001524010 Discover
|
||||
A0000001544442 Banricompras Debito
|
||||
A000000172950001 BAROC Taiwan
|
||||
A0000002281010 SPAN (M/Chip)
|
||||
A0000002282010 SPAN (VIS)
|
||||
A0000002771010 INTERAC
|
||||
A00000031510100528 Currence PuC
|
||||
A0000003156020 Chipknip
|
||||
A0000003591010028001 Girocard EAPS
|
||||
A0000003710001 InterSwitch Verve Card
|
||||
A0000004540010 Etranzact Genesis Card
|
||||
A0000004540011 Etranzact Genesis Card 2
|
||||
A0000004766C GOOGLE_PAYMENT
|
||||
A0000005241010 RuPay
|
||||
A0000006723010 TROY chip credit card
|
||||
A0000006723020 TROY chip debit card
|
||||
A0000007705850 XTRAPOWER
|
||||
B012345678 Maestro TEST
|
||||
D27600002545500100 Girocard
|
||||
D5780000021010 Bankaxept
|
||||
F0000000030001 BRADESCO
|
||||
A000000003000000 (VISA) Card Manager
|
||||
A000000003534441 Schlumberger SD
|
||||
A0000000035350 Security Domain
|
||||
A000000003535041 Security Domain
|
||||
A0000000040000 MasterCard Card Manager
|
||||
A000000018434D Gemplus card manager
|
||||
A000000018434D00 Gemplus Security Domain
|
||||
A0000000960200 Proton WISD
|
||||
A0000001510000 Global Platform SD
|
||||
A00000015153504341534400 CASD_AID
|
||||
A000000476A010 GSD_MANAGER_AID
|
||||
A000000476A110 GSD_MANAGER_AID
|
||||
315041592E5359532E4444463031 Visa PSE
|
||||
325041592E5359532E4444463031 Visa PPSE
|
||||
A0000000042203 MasterCard Specific
|
||||
A0000000045555 APDULogger
|
||||
A0000000090001FF44FF1289 Orange
|
||||
A0000000101030 Maestro-CH
|
||||
A00000001800 Gemplus
|
||||
A0000000181001 gemplus util packages
|
||||
A000000025010104 American Express
|
||||
A00000002949034010100001 HSBC
|
||||
A00000002949282010100000 Barclay
|
||||
A00000005945430100 Girocard Electronic Cash
|
||||
A0000000980840 Visa Common Debit
|
||||
A0000001570010 AMEX
|
||||
A0000001570020 MasterCard
|
||||
A0000001570021 Maestro
|
||||
A0000001570022 Maestro
|
||||
A0000001570023 CASH
|
||||
A0000001570030 VISA
|
||||
A0000001570031 VISA
|
||||
A0000001570040 JCB
|
||||
A0000001570050 Postcard
|
||||
A0000001570051 Postcard
|
||||
A0000001570100 MCard
|
||||
A0000001570104 MyOne
|
||||
A000000157010C WIRCard
|
||||
A000000157010D Power Card
|
||||
A0000001574443 DINERS CLUB
|
||||
A0000001574444 Supercard Plus
|
||||
A00000022820101010 SPAN
|
||||
A000000308000010000100 ID-ONE PIV BIO
|
||||
A0000003241010 Discover Zip
|
||||
A000000333010101 UnionPay Debit
|
||||
A000000333010102 UnionPay Credit
|
||||
A000000333010103 UnionPay Quasi Credit
|
||||
A000000333010106 UnionPay Electronic Cash
|
||||
A000000333010108 U.S. UnionPay Common Debit
|
||||
A000000337102000 Classic
|
||||
A000000337101001 Prepaye Online
|
||||
A000000337102001 Prepaye Possibile Offiline
|
||||
A000000337601001 Porte Monnaie Electronique
|
||||
A0000006581010 MIR Credit
|
||||
A0000006581011 MIR Credit
|
||||
A0000006582010 MIR Debit
|
||||
D040000001000002 Paylife Quick IEP
|
||||
D040000002000002 RFU
|
||||
D040000003000002 POS
|
||||
D040000004000002 ATM
|
||||
D04000000B000002 Retail
|
||||
D04000000C000002 Bank_Data
|
||||
D04000000D000002 Shopping
|
||||
D040000013000001 DF_UNI_Kepler1
|
||||
D040000013000001 DF_Schüler1
|
||||
D040000013000002 DF_UNI_Kepler2
|
||||
D040000013000002 DF_Schüler2
|
||||
D040000014000001 DF_Mensa
|
||||
D040000015000001 DF_UNI_Ausweis
|
||||
D040000015000001 DF_Ausweis
|
||||
D0400000190001 EMV ATM Maestro
|
||||
D0400000190002 EMV POS Maestro
|
||||
D0400000190003 EMV ATM MasterCard
|
||||
D0400000190004 EMV POS MasterCard
|
||||
D276000025 Girocard
|
||||
D27600002547410100 Girocard ATM
|
||||
D7560000010101 Reka Card
|
||||
D7560000300101 M Budget
|
||||
249
assets/resources/nfc/emv/country_code.nfc
Normal file
@ -0,0 +1,249 @@
|
||||
0004 AFG
|
||||
0008 ALB
|
||||
0010 ATA
|
||||
0012 DZA
|
||||
0016 ASM
|
||||
0020 AND
|
||||
0024 AGO
|
||||
0028 ATG
|
||||
0031 AZE
|
||||
0032 ARG
|
||||
0036 AUS
|
||||
0040 AUT
|
||||
0044 BHS
|
||||
0048 BHR
|
||||
0050 BGD
|
||||
0051 ARM
|
||||
0052 BRB
|
||||
0056 BEL
|
||||
0060 BMU
|
||||
0064 BTN
|
||||
0068 BOL
|
||||
0070 BIH
|
||||
0072 BWA
|
||||
0074 BVT
|
||||
0076 BRA
|
||||
0084 BLZ
|
||||
0086 IOT
|
||||
0090 SLB
|
||||
0092 VGB
|
||||
0096 BRN
|
||||
0100 BGR
|
||||
0104 MMR
|
||||
0108 BDI
|
||||
0112 BLR
|
||||
0116 KHM
|
||||
0120 CMR
|
||||
0124 CAN
|
||||
0132 CPV
|
||||
0136 CYM
|
||||
0140 CAF
|
||||
0144 LKA
|
||||
0148 TCD
|
||||
0152 CHL
|
||||
0156 CHN
|
||||
0158 TWN
|
||||
0162 CXR
|
||||
0166 CCK
|
||||
0170 COL
|
||||
0174 COM
|
||||
0175 MYT
|
||||
0178 COG
|
||||
0180 COD
|
||||
0184 COK
|
||||
0188 CRI
|
||||
0191 HRV
|
||||
0192 CUB
|
||||
0196 CYP
|
||||
0203 CZE
|
||||
0204 BEN
|
||||
0208 DNK
|
||||
0212 DMA
|
||||
0214 DOM
|
||||
0218 ECU
|
||||
0222 SLV
|
||||
0226 GNQ
|
||||
0231 ETH
|
||||
0232 ERI
|
||||
0233 EST
|
||||
0234 FRO
|
||||
0238 FLK
|
||||
0239 SGS
|
||||
0242 FJI
|
||||
0246 FIN
|
||||
0248 ALA
|
||||
0250 FRA
|
||||
0254 GUF
|
||||
0258 PYF
|
||||
0260 ATF
|
||||
0262 DJI
|
||||
0266 GAB
|
||||
0268 GEO
|
||||
0270 GMB
|
||||
0275 PSE
|
||||
0276 DEU
|
||||
0288 GHA
|
||||
0292 GIB
|
||||
0296 KIR
|
||||
0300 GRC
|
||||
0304 GRL
|
||||
0308 GRD
|
||||
0312 GLP
|
||||
0316 GUM
|
||||
0320 GTM
|
||||
0324 GIN
|
||||
0328 GUY
|
||||
0332 HTI
|
||||
0334 HMD
|
||||
0336 VAT
|
||||
0340 HND
|
||||
0344 HKG
|
||||
0348 HUN
|
||||
0352 ISL
|
||||
0356 IND
|
||||
0360 IDN
|
||||
0364 IRN
|
||||
0368 IRQ
|
||||
0372 IRL
|
||||
0376 ISR
|
||||
0380 ITA
|
||||
0384 CIV
|
||||
0388 JAM
|
||||
0392 JPN
|
||||
0398 KAZ
|
||||
0400 JOR
|
||||
0404 KEN
|
||||
0408 PRK
|
||||
0410 KOR
|
||||
0414 KWT
|
||||
0417 KGZ
|
||||
0418 LAO
|
||||
0422 LBN
|
||||
0426 LSO
|
||||
0428 LVA
|
||||
0430 LBR
|
||||
0434 LBY
|
||||
0438 LIE
|
||||
0440 LTU
|
||||
0442 LUX
|
||||
0446 MAC
|
||||
0450 MDG
|
||||
0454 MWI
|
||||
0458 MYS
|
||||
0462 MDV
|
||||
0466 MLI
|
||||
0470 MLT
|
||||
0474 MTQ
|
||||
0478 MRT
|
||||
0480 MUS
|
||||
0484 MEX
|
||||
0492 MCO
|
||||
0496 MNG
|
||||
0498 MDA
|
||||
0499 MNE
|
||||
0500 MSR
|
||||
0504 MAR
|
||||
0508 MOZ
|
||||
0512 OMN
|
||||
0516 NAM
|
||||
0520 NRU
|
||||
0524 NPL
|
||||
0528 NLD
|
||||
0531 CUW
|
||||
0533 ABW
|
||||
0534 SXM
|
||||
0535 BES
|
||||
0540 NCL
|
||||
0548 VUT
|
||||
0554 NZL
|
||||
0558 NIC
|
||||
0562 NER
|
||||
0566 NGA
|
||||
0570 NIU
|
||||
0574 NFK
|
||||
0578 NOR
|
||||
0580 MNP
|
||||
0581 UMI
|
||||
0583 FSM
|
||||
0584 MHL
|
||||
0585 PLW
|
||||
0586 PAK
|
||||
0591 PAN
|
||||
0598 PNG
|
||||
0600 PRY
|
||||
0604 PER
|
||||
0608 PHL
|
||||
0612 PCN
|
||||
0616 POL
|
||||
0620 PRT
|
||||
0624 GNB
|
||||
0626 TLS
|
||||
0630 PRI
|
||||
0634 QAT
|
||||
0638 REU
|
||||
0642 ROU
|
||||
0643 RUS
|
||||
0646 RWA
|
||||
0652 BLM
|
||||
0654 SHN
|
||||
0659 KNA
|
||||
0660 AIA
|
||||
0662 LCA
|
||||
0663 MAF
|
||||
0666 SPM
|
||||
0670 VCT
|
||||
0674 SMR
|
||||
0678 STP
|
||||
0682 SAU
|
||||
0686 SEN
|
||||
0688 SRB
|
||||
0690 SYC
|
||||
0694 SLE
|
||||
0702 SGP
|
||||
0703 SVK
|
||||
0704 VNM
|
||||
0705 SVN
|
||||
0706 SOM
|
||||
0710 ZAF
|
||||
0716 ZWE
|
||||
0724 ESP
|
||||
0728 SSD
|
||||
0729 SDN
|
||||
0732 ESH
|
||||
0740 SUR
|
||||
0744 SJM
|
||||
0748 SWZ
|
||||
0752 SWE
|
||||
0756 CHE
|
||||
0760 SYR
|
||||
0762 TJK
|
||||
0764 THA
|
||||
0768 TGO
|
||||
0772 TKL
|
||||
0776 TON
|
||||
0780 TTO
|
||||
0784 ARE
|
||||
0788 TUN
|
||||
0792 TUR
|
||||
0795 TKM
|
||||
0796 TCA
|
||||
0798 TUV
|
||||
0800 UGA
|
||||
0804 UKR
|
||||
0807 MKD
|
||||
0818 EGY
|
||||
0826 GBR
|
||||
0831 GGY
|
||||
0832 JEY
|
||||
0833 IMN
|
||||
0834 TZA
|
||||
0840 USA
|
||||
0850 VIR
|
||||
0854 BFA
|
||||
0858 URY
|
||||
0860 UZB
|
||||
0862 VEN
|
||||
0876 WLF
|
||||
0882 WSM
|
||||
0887 YEM
|
||||
0894 ZMB
|
||||
168
assets/resources/nfc/emv/currency_code.nfc
Normal file
@ -0,0 +1,168 @@
|
||||
0997 USN
|
||||
0994 XSU
|
||||
0990 CLF
|
||||
0986 BRL
|
||||
0985 PLN
|
||||
0984 BOV
|
||||
0981 GEL
|
||||
0980 UAH
|
||||
0979 MXV
|
||||
0978 EUR
|
||||
0977 BAM
|
||||
0976 CDF
|
||||
0975 BGN
|
||||
0973 AOA
|
||||
0972 TJS
|
||||
0971 AFN
|
||||
0970 COU
|
||||
0969 MGA
|
||||
0968 SRD
|
||||
0967 ZMW
|
||||
0965 XUA
|
||||
0960 XDR
|
||||
0953 XPF
|
||||
0952 XOF
|
||||
0951 XCD
|
||||
0950 XAF
|
||||
0949 TRY
|
||||
0948 CHW
|
||||
0947 CHE
|
||||
0946 RON
|
||||
0944 AZN
|
||||
0943 MZN
|
||||
0941 RSD
|
||||
0940 UYI
|
||||
0938 SDG
|
||||
0937 VEF
|
||||
0936 GHS
|
||||
0934 TMT
|
||||
0933 BYN
|
||||
0932 ZWL
|
||||
0931 CUC
|
||||
0930 STN
|
||||
0929 MRU
|
||||
0901 TWD
|
||||
0886 YER
|
||||
0882 WST
|
||||
0860 UZS
|
||||
0858 UYU
|
||||
0840 USD
|
||||
0834 TZS
|
||||
0826 GBP
|
||||
0818 EGP
|
||||
0807 MKD
|
||||
0800 UGX
|
||||
0788 TND
|
||||
0784 AED
|
||||
0780 TTD
|
||||
0776 TOP
|
||||
0764 THB
|
||||
0760 SYP
|
||||
0756 CHF
|
||||
0752 SEK
|
||||
0748 SZL
|
||||
0728 SSP
|
||||
0710 ZAR
|
||||
0706 SOS
|
||||
0704 VND
|
||||
0702 SGD
|
||||
0694 SLL
|
||||
0690 SCR
|
||||
0682 SAR
|
||||
0654 SHP
|
||||
0646 RWF
|
||||
0643 RUB
|
||||
0634 QAR
|
||||
0608 PHP
|
||||
0604 PEN
|
||||
0600 PYG
|
||||
0598 PGK
|
||||
0590 PAB
|
||||
0586 PKR
|
||||
0578 NOK
|
||||
0566 NGN
|
||||
0558 NIO
|
||||
0554 NZD
|
||||
0548 VUV
|
||||
0533 AWG
|
||||
0532 ANG
|
||||
0524 NPR
|
||||
0516 NAD
|
||||
0512 OMR
|
||||
0504 MAD
|
||||
0498 MDL
|
||||
0496 MNT
|
||||
0484 MXN
|
||||
0480 MUR
|
||||
0462 MVR
|
||||
0458 MYR
|
||||
0454 MWK
|
||||
0446 MOP
|
||||
0434 LYD
|
||||
0430 LRD
|
||||
0426 LSL
|
||||
0422 LBP
|
||||
0418 LAK
|
||||
0417 KGS
|
||||
0414 KWD
|
||||
0410 KRW
|
||||
0408 KPW
|
||||
0404 KES
|
||||
0400 JOD
|
||||
0398 KZT
|
||||
0392 JPY
|
||||
0388 JMD
|
||||
0376 ILS
|
||||
0368 IQD
|
||||
0364 IRR
|
||||
0360 IDR
|
||||
0356 INR
|
||||
0352 ISK
|
||||
0348 HUF
|
||||
0344 HKD
|
||||
0340 HNL
|
||||
0332 HTG
|
||||
0328 GYD
|
||||
0324 GNF
|
||||
0320 GTQ
|
||||
0292 GIP
|
||||
0270 GMD
|
||||
0262 DJF
|
||||
0242 FJD
|
||||
0238 FKP
|
||||
0232 ERN
|
||||
0230 ETB
|
||||
0222 SVC
|
||||
0214 DOP
|
||||
0208 DKK
|
||||
0203 CZK
|
||||
0192 CUP
|
||||
0191 HRK
|
||||
0188 CRC
|
||||
0174 KMF
|
||||
0170 COP
|
||||
0156 CNY
|
||||
0152 CLP
|
||||
0144 LKR
|
||||
0136 KYD
|
||||
0132 CVE
|
||||
0124 CAD
|
||||
0116 KHR
|
||||
0108 BIF
|
||||
0104 MMK
|
||||
0096 BND
|
||||
0090 SBD
|
||||
0084 BZD
|
||||
0072 BWP
|
||||
0068 BOB
|
||||
0064 BTN
|
||||
0060 BMD
|
||||
0052 BBD
|
||||
0051 AMD
|
||||
0050 BDT
|
||||
0048 BHD
|
||||
0044 BSD
|
||||
0036 AUD
|
||||
0032 ARS
|
||||
0012 DZD
|
||||
0008 ALL
|
||||
@ -13,13 +13,57 @@
|
||||
#include <furi-hal.h>
|
||||
#include <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);
|
||||
|
||||
@ -1,144 +0,0 @@
|
||||
#include <furi.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
struct used for handling SPI info.
|
||||
*/
|
||||
typedef struct {
|
||||
SPI_HandleTypeDef* spi;
|
||||
PubSubCallback cb;
|
||||
void* ctx;
|
||||
} SpiHandle;
|
||||
|
||||
/*
|
||||
For transmit/receive data use `spi_xfer` function.
|
||||
|
||||
* `tx_data` and `rx_data` size must be equal (and equal `len`)
|
||||
* `cb` called after spi operation is completed, `(NULL, ctx)` passed to callback.
|
||||
*/
|
||||
bool spi_xfer(
|
||||
SPI_HandleTypeDef* spi,
|
||||
uint8_t* tx_data,
|
||||
uint8_t* rx_data,
|
||||
size_t len,
|
||||
PubSubCallback cb,
|
||||
void* ctx);
|
||||
|
||||
/*
|
||||
Blocking verison:
|
||||
*/
|
||||
static inline bool
|
||||
spi_xfer_block(SPI_HandleTypeDef* spi, uint8_t* tx_data, uint8_t* rx_data, size_t len) {
|
||||
semaphoreInfo s;
|
||||
osSemaphore block = createSemaphoreStatic(s);
|
||||
if(!spi_xfer(spi, tx_data, rx_data, len, RELEASE_SEMAPHORE, (void*)block)) {
|
||||
osReleaseSemaphore(block);
|
||||
return false;
|
||||
}
|
||||
osWaitSemaphore(block);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Common implementation of SPI bus: serial interface + CS pin
|
||||
*/
|
||||
typedef struct {
|
||||
GpioPin* cs; ///< CS pin
|
||||
ValueMutex* spi; ///< <SpiHandle*>
|
||||
} SpiBus;
|
||||
|
||||
/*
|
||||
For dedicated work with one device there is `SpiDevice` entity.
|
||||
It contains ValueMutex around SpiBus: after you acquire device
|
||||
you can acquire spi to work with it (don't forget SPI bus is shared
|
||||
around many device, release it after every transaction as quick as possible).
|
||||
*/
|
||||
typedef struct {
|
||||
ValueMutex* bus; ///< <SpiBus*>
|
||||
} SpiDevice;
|
||||
|
||||
##SPI IRQ device
|
||||
|
||||
/*
|
||||
Many devices (like CC1101 and NFC) present as SPI bus and IRQ line.
|
||||
For work with it there is special entity `SpiIrqDevice`.
|
||||
Use `subscribe_pubsub` for subscribinq to irq events.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
ValueMutex* bus; ///< <SpiBus*>
|
||||
PubSub* irq;
|
||||
} SpiIrqDevice;
|
||||
|
||||
/*
|
||||
Special implementation of SPI bus: serial interface + CS, Res, D/I lines.
|
||||
*/
|
||||
typedef struct {
|
||||
GpioPin* cs; ///< CS pin
|
||||
GpioPin* res; ///< reset pin
|
||||
GpioPin* di; ///< D/I pin
|
||||
ValueMutex* spi; ///< <SPI_HandleTypeDef*>
|
||||
} DisplayBus;
|
||||
|
||||
typedef struct {
|
||||
ValueMutex* bus; ///< <DisplayBus*>
|
||||
} DisplayDevice;
|
||||
|
||||
/*
|
||||
# SPI devices (F2)
|
||||
|
||||
* `/dev/sdcard` - SD card SPI, `SpiDevice`
|
||||
* `/dev/cc1101_bus` - Sub-GHz radio (CC1101), `SpiIrqDevice`
|
||||
* `/dev/nfc` - NFC (ST25R3916), `SpiIrqDevice`
|
||||
* `/dev/display` - `DisplayDevice`
|
||||
* `/dev/spiext` - External SPI (warning! Lock PA4, PA5, PA6, PA7)
|
||||
|
||||
### Application example
|
||||
|
||||
```C
|
||||
// Be careful, this function called from IRQ context
|
||||
void handle_irq(void* _arg, void* _ctx) {
|
||||
}
|
||||
|
||||
void cc1101_example() {
|
||||
SpiIrqDevice* cc1101_device = open_input("/dev/cc1101_bus");
|
||||
if(cc1101_device == NULL) return; // bus not available, critical error
|
||||
|
||||
subscribe_pubsub(cc1101_device->irq, handle_irq, NULL);
|
||||
|
||||
{
|
||||
// acquire device as device bus
|
||||
SpiBus* spi_bus = acquire_mutex(cc1101_device->bus, 0);
|
||||
if(spi_bus == NULL) {
|
||||
printf("Device busy\n");
|
||||
// wait for device
|
||||
spi_bus = acquire_mutex_block(cc1101_device->bus);
|
||||
}
|
||||
|
||||
// make transaction
|
||||
uint8_t request[4] = {0xDE, 0xAD, 0xBE, 0xEF};
|
||||
uint8_t response[4];
|
||||
|
||||
{
|
||||
SPI_HandleTypeDef* spi = acquire_mutex_block(spi_bus->spi);
|
||||
|
||||
gpio_write(spi_bus->cs, false);
|
||||
spi_xfer_block(spi, request, response, 4);
|
||||
gpio_write(spi_bus->cs, true);
|
||||
|
||||
release_mutex(cc1101_device->spi, spi);
|
||||
}
|
||||
|
||||
// release device (device bus)
|
||||
release_mutex(cc1101_device->bus, spi_bus);
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,37 +1,30 @@
|
||||
#include "check.h"
|
||||
#include "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();
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||