mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
Merge branch 'dev' of https://github.com/DarkFlippers/unleashed-firmware into xfw-dev
This commit is contained in:
16
.vscode/example/tasks.json
vendored
16
.vscode/example/tasks.json
vendored
@@ -13,7 +13,7 @@
|
||||
"label": "[Debug] Build",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt"
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (ST-Link)",
|
||||
@@ -25,7 +25,7 @@
|
||||
"label": "[Debug] Flash (ST-Link)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash"
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (blackmagic)",
|
||||
@@ -37,7 +37,7 @@
|
||||
"label": "[Debug] Flash (blackmagic)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash_blackmagic"
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_blackmagic"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (JLink)",
|
||||
@@ -49,7 +49,7 @@
|
||||
"label": "[Debug] Flash (JLink)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 jflash"
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 jflash"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build update bundle",
|
||||
@@ -61,7 +61,7 @@
|
||||
"label": "[Debug] Build update bundle",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt updater_package"
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack updater_package"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Build updater",
|
||||
@@ -73,13 +73,13 @@
|
||||
"label": "[Debug] Build updater",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt updater_all"
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack updater_all"
|
||||
},
|
||||
{
|
||||
"label": "[Debug] Flash (USB, w/o resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash_usb"
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_usb"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (USB, w/o resources)",
|
||||
@@ -97,7 +97,7 @@
|
||||
"label": "[Debug] Flash (USB, with resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "./fbt FORCE=1 flash_usb_full"
|
||||
"command": "./fbt FIRMWARE_APP_SET=debug_pack FORCE=1 flash_usb_full"
|
||||
},
|
||||
{
|
||||
"label": "[Release] Flash (USB, with resources)",
|
||||
|
||||
@@ -3,7 +3,10 @@ App(
|
||||
name="Sub-GHz Remote",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="subghz_remote_app",
|
||||
cdefines=["APP_SUBGHZREMOTE"],
|
||||
cdefines=[
|
||||
"APP_SUBGHZREMOTE",
|
||||
"SUBREM_LIGHT",
|
||||
],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
|
||||
18
applications/external/subghz_remote/helpers/subrem_custom_event.h
vendored
Normal file
18
applications/external/subghz_remote/helpers/subrem_custom_event.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
//SubmenuIndex
|
||||
SubmenuIndexSubRemOpenMapFile,
|
||||
SubmenuIndexSubRemRemoteView,
|
||||
SubmenuIndexSubRemAbout,
|
||||
|
||||
//SubRemCustomEvent
|
||||
SubRemCustomEventViewRemoteStartUP = 100,
|
||||
SubRemCustomEventViewRemoteStartDOWN,
|
||||
SubRemCustomEventViewRemoteStartLEFT,
|
||||
SubRemCustomEventViewRemoteStartRIGHT,
|
||||
SubRemCustomEventViewRemoteStartOK,
|
||||
SubRemCustomEventViewRemoteBack,
|
||||
SubRemCustomEventViewRemoteStop,
|
||||
SubRemCustomEventViewRemoteForcedStop,
|
||||
} SubRemCustomEvent;
|
||||
32
applications/external/subghz_remote/helpers/subrem_types.h
vendored
Normal file
32
applications/external/subghz_remote/helpers/subrem_types.h
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
// TODO: File version/type logic
|
||||
// #define SUBREM_APP_APP_FILE_VERSION 1
|
||||
// #define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file"
|
||||
#define SUBREM_APP_EXTENSION ".txt"
|
||||
|
||||
typedef enum {
|
||||
SubRemSubKeyNameUp = (0U),
|
||||
SubRemSubKeyNameDown,
|
||||
SubRemSubKeyNameLeft,
|
||||
SubRemSubKeyNameRight,
|
||||
SubRemSubKeyNameOk,
|
||||
SubRemSubKeyNameMaxCount,
|
||||
} SubRemSubKeyName;
|
||||
|
||||
typedef enum {
|
||||
SubRemViewSubmenu,
|
||||
SubRemViewWidget,
|
||||
SubRemViewPopup,
|
||||
SubRemViewTextInput,
|
||||
SubRemViewIDRemote,
|
||||
} SubRemViewID;
|
||||
|
||||
typedef enum {
|
||||
SubRemLoadMapStateBack = 0,
|
||||
SubRemLoadMapStateError,
|
||||
SubRemLoadMapStateOK,
|
||||
} SubRemLoadMapState;
|
||||
30
applications/external/subghz_remote/scenes/subrem_scene.c
vendored
Normal file
30
applications/external/subghz_remote/scenes/subrem_scene.c
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const subrem_scene_on_enter_handlers[])(void*) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const subrem_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const subrem_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "subrem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers subrem_scene_handlers = {
|
||||
.on_enter_handlers = subrem_scene_on_enter_handlers,
|
||||
.on_event_handlers = subrem_scene_on_event_handlers,
|
||||
.on_exit_handlers = subrem_scene_on_exit_handlers,
|
||||
.scene_num = SubRemSceneNum,
|
||||
};
|
||||
29
applications/external/subghz_remote/scenes/subrem_scene.h
vendored
Normal file
29
applications/external/subghz_remote/scenes/subrem_scene.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) SubRemScene##id,
|
||||
typedef enum {
|
||||
#include "subrem_scene_config.h"
|
||||
SubRemSceneNum,
|
||||
} SubRemScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers subrem_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "subrem_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
3
applications/external/subghz_remote/scenes/subrem_scene_config.h
vendored
Normal file
3
applications/external/subghz_remote/scenes/subrem_scene_config.h
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
ADD_SCENE(subrem, start, Start)
|
||||
ADD_SCENE(subrem, openmapfile, OpenMapFile)
|
||||
ADD_SCENE(subrem, remote, Remote)
|
||||
41
applications/external/subghz_remote/scenes/subrem_scene_openmapfile.c
vendored
Normal file
41
applications/external/subghz_remote/scenes/subrem_scene_openmapfile.c
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
void subrem_scene_openmapfile_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
SubRemLoadMapState load_state = subrem_load_from_file(app);
|
||||
|
||||
if(load_state == SubRemLoadMapStateError) {
|
||||
#ifdef SUBREM_LIGHT
|
||||
dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file");
|
||||
#else
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
|
||||
dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter);
|
||||
dialog_message_set_text(message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_message_set_buttons(message, "Back", NULL, NULL);
|
||||
dialog_message_show(app->dialogs, message);
|
||||
|
||||
dialog_message_free(message);
|
||||
#endif
|
||||
}
|
||||
if(load_state == SubRemLoadMapStateOK) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneRemote);
|
||||
} else {
|
||||
// TODO: Map Preset Reset
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SubRemSceneStart)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool subrem_scene_openmapfile_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_openmapfile_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
130
applications/external/subghz_remote/scenes/subrem_scene_remote.c
vendored
Normal file
130
applications/external/subghz_remote/scenes/subrem_scene_remote.c
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../views/remote.h"
|
||||
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
#define TAG "SubRemScenRemote"
|
||||
|
||||
void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void subrem_scene_remote_raw_callback_end_tx(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewRemoteForcedStop);
|
||||
}
|
||||
|
||||
static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) {
|
||||
uint8_t ret = 0;
|
||||
|
||||
if(event_id == SubRemCustomEventViewRemoteStartUP) {
|
||||
ret = SubRemSubKeyNameUp;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartDOWN) {
|
||||
ret = SubRemSubKeyNameDown;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartLEFT) {
|
||||
ret = SubRemSubKeyNameLeft;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartRIGHT) {
|
||||
ret = SubRemSubKeyNameRight;
|
||||
} else if(event_id == SubRemCustomEventViewRemoteStartOK) {
|
||||
ret = SubRemSubKeyNameOk;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool subrem_scene_remote_update_data_show(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
bool ret = false;
|
||||
|
||||
subrem_view_remote_add_data_to_show(
|
||||
app->subrem_remote_view,
|
||||
furi_string_get_cstr(app->subs_preset[0]->label),
|
||||
furi_string_get_cstr(app->subs_preset[1]->label),
|
||||
furi_string_get_cstr(app->subs_preset[2]->label),
|
||||
furi_string_get_cstr(app->subs_preset[3]->label),
|
||||
furi_string_get_cstr(app->subs_preset[4]->label));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subrem_scene_remote_on_enter(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
subrem_scene_remote_update_data_show(app);
|
||||
|
||||
subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote);
|
||||
}
|
||||
|
||||
bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubRemCustomEventViewRemoteBack) {
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SubRemSceneOpenMapFile)) {
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SubRemSceneStart)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if(
|
||||
event.event == SubRemCustomEventViewRemoteStartUP ||
|
||||
event.event == SubRemCustomEventViewRemoteStartDOWN ||
|
||||
event.event == SubRemCustomEventViewRemoteStartLEFT ||
|
||||
event.event == SubRemCustomEventViewRemoteStartRIGHT ||
|
||||
event.event == SubRemCustomEventViewRemoteStartOK) {
|
||||
// Start sending sub
|
||||
subrem_tx_stop_sub(app, true);
|
||||
app->chusen_sub = subrem_scene_remote_event_to_index(event.event);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading);
|
||||
if(subrem_tx_start_sub(
|
||||
app,
|
||||
app->subs_preset[app->chusen_sub],
|
||||
subrem_scene_remote_raw_callback_end_tx)) {
|
||||
subrem_view_remote_set_presed_btn(app->subrem_remote_view, app->chusen_sub);
|
||||
subrem_view_remote_set_state(
|
||||
app->subrem_remote_view, SubRemViewRemoteStateSending);
|
||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
||||
} else {
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle);
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventViewRemoteForcedStop) {
|
||||
subrem_tx_stop_sub(app, true);
|
||||
subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
return true;
|
||||
} else if(event.event == SubRemCustomEventViewRemoteStop) {
|
||||
if(subrem_tx_stop_sub(app, false)) {
|
||||
subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// } else if(event.type == SceneManagerEventTypeTick) {
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
|
||||
void subrem_scene_remote_on_exit(void* context) {
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
subrem_tx_stop_sub(app, true);
|
||||
|
||||
subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0);
|
||||
subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle);
|
||||
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
||||
74
applications/external/subghz_remote/scenes/subrem_scene_start.c
vendored
Normal file
74
applications/external/subghz_remote/scenes/subrem_scene_start.c
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "../subghz_remote_app_i.h"
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
|
||||
void subrem_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
SubGhzRemoteApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void subrem_scene_start_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Open Map File",
|
||||
SubmenuIndexSubRemOpenMapFile,
|
||||
subrem_scene_start_submenu_callback,
|
||||
app);
|
||||
#if FURI_DEBUG
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Remote_Debug",
|
||||
SubmenuIndexSubRemRemoteView,
|
||||
subrem_scene_start_submenu_callback,
|
||||
app);
|
||||
#endif
|
||||
// submenu_add_item(
|
||||
// submenu,
|
||||
// "About",
|
||||
// SubmenuIndexSubGhzRemoteAbout,
|
||||
// subrem_scene_start_submenu_callback,
|
||||
// app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu);
|
||||
}
|
||||
|
||||
bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexSubRemOpenMapFile) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile);
|
||||
consumed = true;
|
||||
}
|
||||
// } else if(event.event == SubmenuIndexSubRemAbout) {
|
||||
// scene_manager_next_scene(app->scene_manager, SubRemSceneAbout);
|
||||
// consumed = true;
|
||||
// }
|
||||
#if FURI_DEBUG
|
||||
else if(event.event == SubmenuIndexSubRemRemoteView) {
|
||||
scene_manager_next_scene(app->scene_manager, SubRemSceneRemote);
|
||||
consumed = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void subrem_scene_start_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SubGhzRemoteApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
1156
applications/external/subghz_remote/subghz_remote_app.c
vendored
1156
applications/external/subghz_remote/subghz_remote_app.c
vendored
File diff suppressed because it is too large
Load Diff
448
applications/external/subghz_remote/subghz_remote_app_i.c
vendored
Normal file
448
applications/external/subghz_remote/subghz_remote_app_i.c
vendored
Normal file
@@ -0,0 +1,448 @@
|
||||
#include "subghz_remote_app_i.h"
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
|
||||
// #include <lib/subghz/protocols/keeloq.h>
|
||||
// #include <lib/subghz/protocols/star_line.h>
|
||||
|
||||
#include <lib/subghz/blocks/custom_btn.h>
|
||||
|
||||
#define TAG "SubGhzRemote"
|
||||
|
||||
static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = {
|
||||
[SubRemSubKeyNameUp] = {"UP", "ULABEL"},
|
||||
[SubRemSubKeyNameDown] = {"DOWN", "DLABEL"},
|
||||
[SubRemSubKeyNameLeft] = {"LEFT", "LLABEL"},
|
||||
[SubRemSubKeyNameRight] = {"RIGHT", "RLABEL"},
|
||||
[SubRemSubKeyNameOk] = {"OK", "OKLABEL"},
|
||||
};
|
||||
|
||||
static bool
|
||||
subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) {
|
||||
const char* preset_name = "";
|
||||
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
||||
preset_name = "AM270";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
||||
preset_name = "AM650";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
||||
preset_name = "FM238";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
||||
preset_name = "FM476";
|
||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
|
||||
// preset_name = "CUSTOM";
|
||||
return false;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown preset");
|
||||
return false;
|
||||
}
|
||||
size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, preset_name);
|
||||
freq_preset->data = subghz_setting_get_preset_data(setting, preset_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
SubRemSubFilePreset* subrem_sub_file_preset_alloc() {
|
||||
SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset));
|
||||
|
||||
sub_preset->fff_data = flipper_format_string_alloc();
|
||||
sub_preset->file_path = furi_string_alloc();
|
||||
sub_preset->protocaol_name = furi_string_alloc();
|
||||
sub_preset->label = furi_string_alloc_set_str("N/A");
|
||||
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
|
||||
return sub_preset;
|
||||
}
|
||||
|
||||
void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) {
|
||||
furi_assert(sub_preset);
|
||||
|
||||
furi_string_free(sub_preset->label);
|
||||
furi_string_free(sub_preset->protocaol_name);
|
||||
furi_string_free(sub_preset->file_path);
|
||||
flipper_format_free(sub_preset->fff_data);
|
||||
|
||||
free(sub_preset);
|
||||
}
|
||||
|
||||
static void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) {
|
||||
furi_assert(sub_preset);
|
||||
|
||||
furi_string_set_str(sub_preset->label, "N/A");
|
||||
furi_string_reset(sub_preset->protocaol_name);
|
||||
furi_string_reset(sub_preset->file_path);
|
||||
|
||||
Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data);
|
||||
stream_clean(fff_data_stream);
|
||||
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
}
|
||||
|
||||
void subrem_map_preset_reset(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
subrem_sub_file_preset_reset(app->subs_preset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) {
|
||||
furi_assert(app);
|
||||
bool ret = false;
|
||||
SubRemSubFilePreset* sub_preset;
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = app->subs_preset[i];
|
||||
if(!flipper_format_read_string(
|
||||
fff_data_file, map_file_labels[i][0], sub_preset->file_path)) {
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]);
|
||||
#endif
|
||||
sub_preset->type = SubGhzProtocolTypeUnknown;
|
||||
} else if(!flipper_format_rewind(fff_data_file)) {
|
||||
// Rewind error
|
||||
} else if(!flipper_format_read_string(
|
||||
fff_data_file, map_file_labels[i][1], sub_preset->label)) {
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]);
|
||||
#endif
|
||||
path_extract_filename(sub_preset->file_path, sub_preset->label, true);
|
||||
} else {
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"%-5s: %s %s",
|
||||
map_file_labels[i][0],
|
||||
furi_string_get_cstr(sub_preset->label),
|
||||
furi_string_get_cstr(sub_preset->file_path));
|
||||
ret = true;
|
||||
}
|
||||
flipper_format_rewind(fff_data_file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) {
|
||||
furi_assert(flipper_format);
|
||||
furi_assert(dev_file_name);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
|
||||
|
||||
bool saved = false;
|
||||
FuriString* file_dir = furi_string_alloc();
|
||||
|
||||
path_extract_dirname(dev_file_name, file_dir);
|
||||
do {
|
||||
//removing additional fields
|
||||
flipper_format_delete_key(flipper_format, "Repeat");
|
||||
//flipper_format_delete_key(flipper_format, "Manufacture");
|
||||
|
||||
if(!storage_simply_remove(storage, dev_file_name)) {
|
||||
break;
|
||||
}
|
||||
//ToDo check Write
|
||||
stream_seek(flipper_format_stream, 0, StreamOffsetFromStart);
|
||||
stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS);
|
||||
|
||||
saved = true;
|
||||
} while(0);
|
||||
furi_string_free(file_dir);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return saved;
|
||||
}
|
||||
|
||||
bool subrem_tx_start_sub(
|
||||
SubGhzRemoteApp* app,
|
||||
SubRemSubFilePreset* sub_preset,
|
||||
SubGhzProtocolEncoderRAWCallbackEnd callback) {
|
||||
furi_assert(app);
|
||||
furi_assert(sub_preset);
|
||||
bool ret = false;
|
||||
|
||||
subrem_tx_stop_sub(app, true);
|
||||
|
||||
if(sub_preset->type == SubGhzProtocolTypeUnknown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label));
|
||||
|
||||
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
|
||||
keeloq_reset_original_btn();
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
do {
|
||||
flipper_format_rewind(sub_preset->fff_data); //
|
||||
|
||||
app->transmitter = subghz_transmitter_alloc_init(
|
||||
app->environment, furi_string_get_cstr(sub_preset->protocaol_name));
|
||||
|
||||
if(app->transmitter) {
|
||||
if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) !=
|
||||
SubGhzProtocolStatusOk) {
|
||||
FURI_LOG_E(TAG, "Deserialize error!");
|
||||
break;
|
||||
}
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_idle();
|
||||
furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
furi_hal_subghz_idle();
|
||||
|
||||
furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency);
|
||||
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
if(!furi_hal_subghz_tx()) {
|
||||
FURI_LOG_E(TAG, "Sending not allowed");
|
||||
break;
|
||||
}
|
||||
|
||||
if(sub_preset->type == SubGhzProtocolTypeRAW) {
|
||||
subghz_protocol_raw_file_encoder_worker_set_callback_end(
|
||||
(SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(
|
||||
app->transmitter),
|
||||
callback,
|
||||
app);
|
||||
}
|
||||
|
||||
furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter);
|
||||
|
||||
ret = true;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
app->tx_running = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void subghz_tx_stop(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
//Stop TX
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
|
||||
subghz_transmitter_stop(app->transmitter);
|
||||
subghz_transmitter_free(app->transmitter);
|
||||
furi_hal_subghz_idle();
|
||||
}
|
||||
|
||||
bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) {
|
||||
furi_assert(app);
|
||||
SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub];
|
||||
|
||||
if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) {
|
||||
// SubRemSubKeyTypeRawKey)) {
|
||||
if(app->tx_running) {
|
||||
subghz_tx_stop(app);
|
||||
|
||||
if(sub_preset->type == SubGhzProtocolTypeDynamic) {
|
||||
subrem_save_protocol_to_file(
|
||||
sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path));
|
||||
|
||||
keeloq_reset_mfname();
|
||||
keeloq_reset_kl_type();
|
||||
keeloq_reset_original_btn();
|
||||
subghz_custom_btns_reset();
|
||||
star_line_reset_mfname();
|
||||
star_line_reset_kl_type();
|
||||
}
|
||||
|
||||
app->tx_running = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) {
|
||||
furi_assert(app);
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
uint32_t temp_data32;
|
||||
bool ret = false;
|
||||
bool sub_preset_loaded = false;
|
||||
SubRemSubFilePreset* sub_preset;
|
||||
|
||||
for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) {
|
||||
sub_preset = app->subs_preset[i];
|
||||
sub_preset_loaded = false;
|
||||
if(furi_string_empty(sub_preset->file_path)) {
|
||||
// FURI_LOG_I(TAG, "Empty file path");
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(
|
||||
fff_data_file, furi_string_get_cstr(sub_preset->file_path))) {
|
||||
FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path));
|
||||
break;
|
||||
}
|
||||
|
||||
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect header");
|
||||
break;
|
||||
}
|
||||
|
||||
if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) ||
|
||||
(!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) &&
|
||||
temp_data32 == SUBGHZ_KEY_FILE_VERSION) {
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Type or version mismatch");
|
||||
break;
|
||||
}
|
||||
|
||||
//Load frequency
|
||||
if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
|
||||
FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency");
|
||||
sub_preset->freq_preset.frequency =
|
||||
subghz_setting_get_default_frequency(app->setting);
|
||||
} else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) {
|
||||
FURI_LOG_E(TAG, "This frequency can only be used for RX");
|
||||
break;
|
||||
} else {
|
||||
sub_preset->freq_preset.frequency = temp_data32;
|
||||
}
|
||||
|
||||
//Load preset
|
||||
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing Preset");
|
||||
break;
|
||||
}
|
||||
|
||||
if(!subrem_set_preset_data(
|
||||
app->setting, &sub_preset->freq_preset, furi_string_get_cstr(temp_str))) {
|
||||
FURI_LOG_E(TAG, "Cannot load preset.");
|
||||
break;
|
||||
}
|
||||
|
||||
//Load protocol
|
||||
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing Protocol");
|
||||
break;
|
||||
}
|
||||
|
||||
FlipperFormat* fff_data = sub_preset->fff_data;
|
||||
if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
|
||||
//if RAW
|
||||
subghz_protocol_raw_gen_fff_data(
|
||||
fff_data, furi_string_get_cstr(sub_preset->file_path));
|
||||
} else {
|
||||
stream_copy_full(
|
||||
flipper_format_get_raw_stream(fff_data_file),
|
||||
flipper_format_get_raw_stream(fff_data));
|
||||
}
|
||||
|
||||
const SubGhzProtocolRegistry* protocol_registry_items =
|
||||
subghz_environment_get_protocol_registry(app->environment);
|
||||
|
||||
const SubGhzProtocol* protocol = subghz_protocol_registry_get_by_name(
|
||||
protocol_registry_items, furi_string_get_cstr(temp_str));
|
||||
|
||||
if(!protocol) {
|
||||
FURI_LOG_E(TAG, "Protocol not found");
|
||||
break;
|
||||
} else if(protocol->flag & SubGhzProtocolFlag_Send) {
|
||||
if((protocol->type == SubGhzProtocolTypeStatic) ||
|
||||
(protocol->type == SubGhzProtocolTypeDynamic) ||
|
||||
// (protocol->type == SubGhzProtocolTypeBinRAW) || // TODO: BINRAW
|
||||
(protocol->type == SubGhzProtocolTypeRAW)) {
|
||||
sub_preset->type = protocol->type;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unsuported Protocol");
|
||||
break;
|
||||
}
|
||||
|
||||
furi_string_set(sub_preset->protocaol_name, temp_str);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Protocol does not support transmission");
|
||||
}
|
||||
|
||||
sub_preset_loaded = true;
|
||||
ret |= true;
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label));
|
||||
#endif
|
||||
} while(false);
|
||||
|
||||
// TODO:
|
||||
// Load file state logic
|
||||
// Label depending on the state
|
||||
|
||||
if(!sub_preset_loaded) {
|
||||
furi_string_set_str(sub_preset->label, "N/A");
|
||||
}
|
||||
|
||||
flipper_format_file_close(fff_data_file);
|
||||
}
|
||||
furi_string_free(temp_str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) {
|
||||
furi_assert(app);
|
||||
furi_assert(file_path);
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Load Map File Start");
|
||||
#endif
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
bool ret = false;
|
||||
#if FURI_DEBUG
|
||||
FURI_LOG_I(TAG, "Open Map File..");
|
||||
#endif
|
||||
subrem_map_preset_reset(app);
|
||||
|
||||
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
FURI_LOG_E(TAG, "Could not open MAP file %s", file_path);
|
||||
} else {
|
||||
if(!subrem_map_preset_load(app, fff_data_file)) {
|
||||
FURI_LOG_E(TAG, "Could no Sub file path in MAP file");
|
||||
// ret = // error for popup
|
||||
} else if(
|
||||
(flipper_format_file_close(fff_data_file)) &&
|
||||
(subrem_map_preset_check(app, fff_data_file))) {
|
||||
FURI_LOG_I(TAG, "Load Map File Seccesful");
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Popup for error or return error type
|
||||
if(!ret) {
|
||||
FURI_LOG_E(TAG, "Broken Map File");
|
||||
}
|
||||
|
||||
flipper_format_file_close(fff_data_file);
|
||||
flipper_format_free(fff_data_file);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
FuriString* file_path = furi_string_alloc();
|
||||
SubRemLoadMapState ret = SubRemLoadMapStateBack;
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_sub1_10px);
|
||||
browser_options.base_path = SUBREM_APP_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
if(!dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options)) {
|
||||
} else if(subrem_map_file_load(app, furi_string_get_cstr(app->file_path))) {
|
||||
ret = SubRemLoadMapStateOK;
|
||||
} else {
|
||||
ret = SubRemLoadMapStateError;
|
||||
}
|
||||
|
||||
furi_string_free(file_path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
84
applications/external/subghz_remote/subghz_remote_app_i.h
vendored
Normal file
84
applications/external/subghz_remote/subghz_remote_app_i.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/subrem_types.h"
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include "views/remote.h"
|
||||
|
||||
#include "scenes/subrem_scene.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <storage/storage.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include <lib/subghz/protocols/raw.h>
|
||||
|
||||
#include <lib/subghz/subghz_setting.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
|
||||
#define SUBREM_APP_FOLDER EXT_PATH("subghz/remote")
|
||||
#define SUBREM_MAX_LEN_NAME 64
|
||||
|
||||
typedef struct {
|
||||
uint32_t frequency;
|
||||
uint8_t* data;
|
||||
} FreqPreset;
|
||||
|
||||
// Sub File preset
|
||||
typedef struct {
|
||||
FlipperFormat* fff_data;
|
||||
FreqPreset freq_preset;
|
||||
FuriString* file_path;
|
||||
FuriString* protocaol_name;
|
||||
FuriString* label;
|
||||
SubGhzProtocolType type;
|
||||
} SubRemSubFilePreset;
|
||||
|
||||
SubRemSubFilePreset* subrem_sub_file_preset_alloc();
|
||||
|
||||
void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset);
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Submenu* submenu;
|
||||
FuriString* file_path;
|
||||
char file_name_tmp[SUBREM_MAX_LEN_NAME];
|
||||
|
||||
SubRemViewRemote* subrem_remote_view;
|
||||
|
||||
SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount];
|
||||
|
||||
SubGhzSetting* setting;
|
||||
SubGhzEnvironment* environment;
|
||||
SubGhzReceiver* receiver;
|
||||
SubGhzTransmitter* transmitter;
|
||||
|
||||
bool tx_running;
|
||||
|
||||
uint8_t chusen_sub;
|
||||
|
||||
// TODO: LoadFileError
|
||||
} SubGhzRemoteApp;
|
||||
|
||||
SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app);
|
||||
|
||||
bool subrem_tx_start_sub(
|
||||
SubGhzRemoteApp* app,
|
||||
SubRemSubFilePreset* sub_preset,
|
||||
SubGhzProtocolEncoderRAWCallbackEnd callback);
|
||||
|
||||
bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced);
|
||||
302
applications/external/subghz_remote/views/remote.c
vendored
Normal file
302
applications/external/subghz_remote/views/remote.c
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
#include "remote.h"
|
||||
#include "../subghz_remote_app_i.h"
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 16
|
||||
|
||||
struct SubRemViewRemote {
|
||||
View* view;
|
||||
SubRemViewRemoteCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
// TODO: model
|
||||
typedef struct {
|
||||
// FuriString* up_label;
|
||||
// FuriString* down_label;
|
||||
// FuriString* left_label;
|
||||
// FuriString* right_label;
|
||||
// FuriString* ok_label;
|
||||
|
||||
char* up_label;
|
||||
char* down_label;
|
||||
char* left_label;
|
||||
char* right_label;
|
||||
char* ok_label;
|
||||
|
||||
SubRemViewRemoteState state;
|
||||
|
||||
uint8_t pressed_btn;
|
||||
} SubRemViewRemoteModel;
|
||||
|
||||
void subrem_view_remote_set_callback(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteCallback callback,
|
||||
void* context) {
|
||||
furi_assert(subrem_view_remote);
|
||||
|
||||
subrem_view_remote->callback = callback;
|
||||
subrem_view_remote->context = context;
|
||||
}
|
||||
|
||||
void subrem_view_remote_add_data_to_show(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
const char* up_label,
|
||||
const char* down_label,
|
||||
const char* left_label,
|
||||
const char* right_label,
|
||||
const char* ok_label) {
|
||||
furi_assert(subrem_view_remote);
|
||||
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
strncpy(model->up_label, up_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
strncpy(model->down_label, down_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
strncpy(model->left_label, left_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
strncpy(model->right_label, right_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
strncpy(model->ok_label, ok_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH);
|
||||
|
||||
// furi_string_set(model->up_label, up_label);
|
||||
// furi_string_set(model->down_label, down_label);
|
||||
// furi_string_set(model->left_label, left_label);
|
||||
// furi_string_set(model->right_label, right_label);
|
||||
// furi_string_set(model->ok_label, ok_label);
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn) {
|
||||
furi_assert(subrem_view_remote);
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{ model->pressed_btn = presed_btn; },
|
||||
true);
|
||||
}
|
||||
|
||||
void subrem_view_remote_set_state(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteState state) {
|
||||
furi_assert(subrem_view_remote);
|
||||
with_view_model(
|
||||
subrem_view_remote->view, SubRemViewRemoteModel * model, { model->state = state; }, true);
|
||||
}
|
||||
|
||||
void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
//Icons for Labels
|
||||
//canvas_draw_icon(canvas, 0, 0, &I_SubGHzRemote_LeftAlignedButtons_9x64);
|
||||
canvas_draw_icon(canvas, 1, 5, &I_ButtonUp_7x4);
|
||||
canvas_draw_icon(canvas, 1, 15, &I_ButtonDown_7x4);
|
||||
canvas_draw_icon(canvas, 2, 23, &I_ButtonLeft_4x7);
|
||||
canvas_draw_icon(canvas, 2, 33, &I_ButtonRight_4x7);
|
||||
canvas_draw_icon(canvas, 0, 42, &I_Ok_btn_9x9);
|
||||
canvas_draw_icon(canvas, 0, 53, &I_back_10px);
|
||||
|
||||
//Labels
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 10, 10, model->up_label);
|
||||
canvas_draw_str(canvas, 10, 20, model->down_label);
|
||||
canvas_draw_str(canvas, 10, 30, model->left_label);
|
||||
canvas_draw_str(canvas, 10, 40, model->right_label);
|
||||
canvas_draw_str(canvas, 10, 50, model->ok_label);
|
||||
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
// canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label));
|
||||
|
||||
canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit.");
|
||||
|
||||
//Status text and indicator
|
||||
canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13);
|
||||
|
||||
if(model->state == SubRemViewRemoteStateIdle) {
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle");
|
||||
} else {
|
||||
switch(model->state) {
|
||||
case SubRemViewRemoteStateSending:
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Send");
|
||||
break;
|
||||
case SubRemViewRemoteStateLoading:
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Load");
|
||||
break;
|
||||
default:
|
||||
#if FURI_DEBUG
|
||||
canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Wrong_state");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
switch(model->pressed_btn) {
|
||||
case SubRemSubKeyNameUp:
|
||||
canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up_7x9);
|
||||
break;
|
||||
case SubRemSubKeyNameDown:
|
||||
canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180);
|
||||
break;
|
||||
case SubRemSubKeyNameLeft:
|
||||
canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270);
|
||||
break;
|
||||
case SubRemSubKeyNameRight:
|
||||
canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90);
|
||||
break;
|
||||
case SubRemSubKeyNameOk:
|
||||
canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Repeat indicator
|
||||
//canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:");
|
||||
//canvas_draw_icon(canvas, 115, 39, &I_SubGHzRemote_Repeat_12x14);
|
||||
//canvas_draw_str_aligned(canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat));
|
||||
}
|
||||
|
||||
bool subrem_view_remote_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
SubRemViewRemote* subrem_view_remote = context;
|
||||
|
||||
if(event->key == InputKeyBack && event->type == InputTypeLong) {
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
strcpy(model->up_label, "N/A");
|
||||
strcpy(model->down_label, "N/A");
|
||||
strcpy(model->left_label, "N/A");
|
||||
strcpy(model->right_label, "N/A");
|
||||
strcpy(model->ok_label, "N/A");
|
||||
},
|
||||
false);
|
||||
subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{ model->pressed_btn = 0; },
|
||||
true);
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteForcedStop, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
return true;
|
||||
}
|
||||
// BACK button processing end
|
||||
|
||||
if(event->key == InputKeyUp && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyDown && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartDOWN, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyLeft && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartLEFT, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyRight && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartRIGHT, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypePress) {
|
||||
subrem_view_remote->callback(
|
||||
SubRemCustomEventViewRemoteStartOK, subrem_view_remote->context);
|
||||
return true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
subrem_view_remote->callback(SubRemCustomEventViewRemoteStop, subrem_view_remote->context);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void subrem_view_remote_enter(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
void subrem_view_remote_exit(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
SubRemViewRemote* subrem_view_remote_alloc() {
|
||||
SubRemViewRemote* subrem_view_remote = malloc(sizeof(SubRemViewRemote));
|
||||
|
||||
// View allocation and configuration
|
||||
subrem_view_remote->view = view_alloc();
|
||||
view_allocate_model(
|
||||
subrem_view_remote->view, ViewModelTypeLocking, sizeof(SubRemViewRemoteModel));
|
||||
view_set_context(subrem_view_remote->view, subrem_view_remote);
|
||||
view_set_draw_callback(subrem_view_remote->view, (ViewDrawCallback)subrem_view_remote_draw);
|
||||
view_set_input_callback(subrem_view_remote->view, subrem_view_remote_input);
|
||||
view_set_enter_callback(subrem_view_remote->view, subrem_view_remote_enter);
|
||||
view_set_exit_callback(subrem_view_remote->view, subrem_view_remote_exit);
|
||||
|
||||
with_view_model(
|
||||
subrem_view_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
model->state = SubRemViewRemoteStateIdle;
|
||||
|
||||
model->up_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
model->down_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
model->left_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
model->right_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
model->ok_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1);
|
||||
|
||||
strcpy(model->up_label, "N/A");
|
||||
strcpy(model->down_label, "N/A");
|
||||
strcpy(model->left_label, "N/A");
|
||||
strcpy(model->right_label, "N/A");
|
||||
strcpy(model->ok_label, "N/A");
|
||||
|
||||
// model->up_label = furi_string_alloc_set_str("N/A");
|
||||
// model->down_label = furi_string_alloc_set_str("N/A");
|
||||
// model->left_label = furi_string_alloc_set_str("N/A");
|
||||
// model->right_label = furi_string_alloc_set_str("N/A");
|
||||
// model->ok_label = furi_string_alloc_set_str("N/A");
|
||||
|
||||
model->pressed_btn = 0;
|
||||
},
|
||||
true);
|
||||
return subrem_view_remote;
|
||||
}
|
||||
|
||||
void subrem_view_remote_free(SubRemViewRemote* subghz_remote) {
|
||||
furi_assert(subghz_remote);
|
||||
|
||||
with_view_model(
|
||||
subghz_remote->view,
|
||||
SubRemViewRemoteModel * model,
|
||||
{
|
||||
free(model->up_label);
|
||||
free(model->down_label);
|
||||
free(model->left_label);
|
||||
free(model->right_label);
|
||||
free(model->ok_label);
|
||||
|
||||
// furi_string_free(model->up_label);
|
||||
// furi_string_free(model->down_label);
|
||||
// furi_string_free(model->left_label);
|
||||
// furi_string_free(model->right_label);
|
||||
// furi_string_free(model->ok_label);
|
||||
},
|
||||
true);
|
||||
view_free(subghz_remote->view);
|
||||
free(subghz_remote);
|
||||
}
|
||||
|
||||
View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote) {
|
||||
furi_assert(subrem_view_remote);
|
||||
return subrem_view_remote->view;
|
||||
}
|
||||
38
applications/external/subghz_remote/views/remote.h
vendored
Normal file
38
applications/external/subghz_remote/views/remote.h
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/subrem_custom_event.h"
|
||||
|
||||
typedef enum {
|
||||
SubRemViewRemoteStateIdle,
|
||||
SubRemViewRemoteStateLoading,
|
||||
SubRemViewRemoteStateSending,
|
||||
} SubRemViewRemoteState;
|
||||
|
||||
typedef struct SubRemViewRemote SubRemViewRemote;
|
||||
|
||||
typedef void (*SubRemViewRemoteCallback)(SubRemCustomEvent event, void* context);
|
||||
|
||||
void subrem_view_remote_set_callback(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteCallback callback,
|
||||
void* context);
|
||||
|
||||
SubRemViewRemote* subrem_view_remote_alloc();
|
||||
|
||||
void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote);
|
||||
|
||||
View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote);
|
||||
|
||||
void subrem_view_remote_add_data_to_show(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
const char* up_label,
|
||||
const char* down_label,
|
||||
const char* left_label,
|
||||
const char* right_label,
|
||||
const char* ok_label);
|
||||
|
||||
void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn);
|
||||
void subrem_view_remote_set_state(
|
||||
SubRemViewRemote* subrem_view_remote,
|
||||
SubRemViewRemoteState state);
|
||||
@@ -97,20 +97,13 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = {
|
||||
NO_ARGS,
|
||||
FOCUS_CONSOLE_END,
|
||||
SHOW_STOPSCAN_TIP},
|
||||
{"Sniff PMKID on channel",
|
||||
{""},
|
||||
1,
|
||||
{"sniffpmkid -c"},
|
||||
INPUT_ARGS,
|
||||
{"Sniff PMKID",
|
||||
{"ap", "channel"},
|
||||
2,
|
||||
{"sniffpmkid -d -l", "sniffpmkid -c"},
|
||||
TOGGLE_ARGS,
|
||||
FOCUS_CONSOLE_END,
|
||||
SHOW_STOPSCAN_TIP},
|
||||
{"Sniff pmkid on selected aps",
|
||||
{""},
|
||||
1,
|
||||
{"sniffpmkid -d -l"},
|
||||
NO_ARGS,
|
||||
FOCUS_CONSOLE_END,
|
||||
NO_TIP},
|
||||
{"Channel",
|
||||
{"get", "set"},
|
||||
2,
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <lib/toolbox/path.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
|
||||
#define NUM_MENU_ITEMS (19)
|
||||
#define NUM_MENU_ITEMS (18)
|
||||
|
||||
#define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096)
|
||||
#define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512)
|
||||
|
||||
@@ -187,11 +187,16 @@ int32_t lfrfid_app(char* args) {
|
||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
||||
} else {
|
||||
furi_string_set(app->file_path, args);
|
||||
lfrfid_load_key_data(app, app->file_path, true);
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
||||
if(lfrfid_load_key_data(app, app->file_path, true)) {
|
||||
view_dispatcher_attach_to_gui(
|
||||
app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
|
||||
DOLPHIN_DEED(DolphinDeedRfidEmulate);
|
||||
} else {
|
||||
// TODO: exit properly
|
||||
lfrfid_free(app);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -296,6 +296,7 @@ int32_t nfc_app(char* p) {
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
} else {
|
||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||
|
||||
@@ -204,7 +204,6 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
||||
furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n");
|
||||
break;
|
||||
}
|
||||
// Set tag general data
|
||||
} else if(type == FuriHalNfcTypeF) {
|
||||
// Set NFC-F data
|
||||
furi_string_cat_printf(temp_str, "ISO 18092 (NFC-F)\n");
|
||||
@@ -260,7 +259,8 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
|
||||
for(size_t i = 0; i < sizeof(nfc_data->f_data.pmm); i++) {
|
||||
furi_string_cat_printf(temp_str, " %02X", nfc_data->f_data.pmm[i]);
|
||||
}
|
||||
} else { // FuriHalNfcTypeA
|
||||
} else {
|
||||
// Set tag general data
|
||||
char iso_type = FURI_BIT(nfc_data->a_data.sak, 5) ? '4' : '3';
|
||||
furi_string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type);
|
||||
furi_string_cat_printf(temp_str, "UID:");
|
||||
|
||||
@@ -10,7 +10,10 @@ App(
|
||||
"cli",
|
||||
"dialogs",
|
||||
],
|
||||
provides=["subghz_start"],
|
||||
provides=[
|
||||
"subghz_start",
|
||||
"subghz_load_extended_settings",
|
||||
],
|
||||
icon="A_Sub1ghz_14",
|
||||
stack_size=3 * 1024,
|
||||
order=10,
|
||||
@@ -23,3 +26,11 @@ App(
|
||||
requires=["subghz"],
|
||||
order=40,
|
||||
)
|
||||
|
||||
App(
|
||||
appid="subghz_load_extended_settings",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="subghz_extended_freq",
|
||||
requires=["storage", "subghz"],
|
||||
order=650,
|
||||
)
|
||||
|
||||
@@ -36,6 +36,8 @@ typedef enum {
|
||||
SubmenuIndexCAME24bit868,
|
||||
SubmenuIndexCAMETwee,
|
||||
SubmenuIndexCAMESpace,
|
||||
SubmenuIndexCameAtomo433,
|
||||
SubmenuIndexCameAtomo868,
|
||||
SubmenuIndexPricenton433,
|
||||
SubmenuIndexPricenton315,
|
||||
SubmenuIndexBETT_433,
|
||||
|
||||
@@ -266,6 +266,34 @@ bool subghz_txrx_gen_alutech_at_4n_protocol(
|
||||
return res;
|
||||
}
|
||||
|
||||
bool subghz_txrx_gen_came_atomo_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint32_t serial,
|
||||
uint16_t cnt) {
|
||||
SubGhzTxRx* txrx = context;
|
||||
|
||||
bool res = false;
|
||||
|
||||
txrx->transmitter =
|
||||
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_CAME_ATOMO_NAME);
|
||||
subghz_txrx_set_preset(txrx, preset_name, frequency, NULL, 0);
|
||||
|
||||
if(txrx->transmitter && subghz_protocol_came_atomo_create_data(
|
||||
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
||||
txrx->fff_data,
|
||||
serial,
|
||||
cnt,
|
||||
txrx->preset)) {
|
||||
res = true;
|
||||
}
|
||||
|
||||
subghz_transmitter_free(txrx->transmitter);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool subghz_txrx_gen_somfy_telis_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
|
||||
@@ -108,6 +108,13 @@ bool subghz_txrx_gen_somfy_telis_protocol(
|
||||
uint8_t btn,
|
||||
uint16_t cnt);
|
||||
|
||||
bool subghz_txrx_gen_came_atomo_protocol(
|
||||
void* context,
|
||||
const char* preset_name,
|
||||
uint32_t frequency,
|
||||
uint32_t serial,
|
||||
uint16_t cnt);
|
||||
|
||||
/**
|
||||
* Generate data SecPlus v2 protocol
|
||||
*
|
||||
|
||||
@@ -25,11 +25,14 @@ const char* const debug_pin_text[DEBUG_P_COUNT] = {
|
||||
"17(1W)",
|
||||
};
|
||||
|
||||
#define DEBUG_COUNTER_COUNT 3
|
||||
#define DEBUG_COUNTER_COUNT 6
|
||||
const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = {
|
||||
"+1",
|
||||
"+2",
|
||||
"+3",
|
||||
"+4",
|
||||
"+5",
|
||||
"+10",
|
||||
};
|
||||
|
||||
static void subghz_scene_ext_module_changed(VariableItem* item) {
|
||||
@@ -71,6 +74,15 @@ static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) {
|
||||
case 2:
|
||||
furi_hal_subghz_set_rolling_counter_mult(3);
|
||||
break;
|
||||
case 3:
|
||||
furi_hal_subghz_set_rolling_counter_mult(4);
|
||||
break;
|
||||
case 4:
|
||||
furi_hal_subghz_set_rolling_counter_mult(5);
|
||||
break;
|
||||
case 5:
|
||||
furi_hal_subghz_set_rolling_counter_mult(10);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -140,24 +152,58 @@ void subghz_scene_radio_settings_on_enter(void* context) {
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, timestamp_names_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Counter incr.",
|
||||
DEBUG_COUNTER_COUNT,
|
||||
subghz_scene_receiver_config_set_debug_counter,
|
||||
subghz);
|
||||
switch(furi_hal_subghz_get_rolling_counter_mult()) {
|
||||
case 1:
|
||||
value_index = 0;
|
||||
break;
|
||||
case 2:
|
||||
value_index = 1;
|
||||
break;
|
||||
case 3:
|
||||
value_index = 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Counter incr.",
|
||||
DEBUG_COUNTER_COUNT,
|
||||
subghz_scene_receiver_config_set_debug_counter,
|
||||
subghz);
|
||||
switch(furi_hal_subghz_get_rolling_counter_mult()) {
|
||||
case 1:
|
||||
value_index = 0;
|
||||
break;
|
||||
case 2:
|
||||
value_index = 1;
|
||||
break;
|
||||
case 3:
|
||||
value_index = 2;
|
||||
break;
|
||||
case 4:
|
||||
value_index = 3;
|
||||
break;
|
||||
case 5:
|
||||
value_index = 4;
|
||||
break;
|
||||
case 10:
|
||||
value_index = 5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
item = variable_item_list_add(
|
||||
subghz->variable_item_list,
|
||||
"Counter incr.",
|
||||
3,
|
||||
subghz_scene_receiver_config_set_debug_counter,
|
||||
subghz);
|
||||
switch(furi_hal_subghz_get_rolling_counter_mult()) {
|
||||
case 1:
|
||||
value_index = 0;
|
||||
break;
|
||||
case 2:
|
||||
value_index = 1;
|
||||
break;
|
||||
case 3:
|
||||
value_index = 2;
|
||||
break;
|
||||
default:
|
||||
// Reset to default value
|
||||
value_index = 0;
|
||||
furi_hal_subghz_set_rolling_counter_mult(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, debug_counter_text[value_index]);
|
||||
|
||||
@@ -227,12 +227,20 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
break;
|
||||
case SubGhzCustomEventViewReceiverDeleteItem:
|
||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||
subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
|
||||
|
||||
subghz_view_receiver_disable_draw_callback(subghz->subghz_receiver);
|
||||
|
||||
subghz_history_delete_item(subghz->history, subghz->idx_menu_chosen);
|
||||
subghz_view_receiver_delete_element_callback(subghz->subghz_receiver);
|
||||
|
||||
subghz_view_receiver_enable_draw_callback(subghz->subghz_receiver);
|
||||
|
||||
subghz_scene_receiver_update_statusbar(subghz);
|
||||
if(subghz_history_get_last_index(subghz->history) == 0) {
|
||||
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case SubGhzCustomEventViewReceiverConfig:
|
||||
|
||||
@@ -199,6 +199,18 @@ void subghz_scene_set_type_on_enter(void* context) {
|
||||
SubmenuIndexCAMETwee,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"CAME Atomo 433MHz",
|
||||
SubmenuIndexCameAtomo433,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"CAME Atomo 868MHz",
|
||||
SubmenuIndexCameAtomo868,
|
||||
subghz_scene_set_type_submenu_callback,
|
||||
subghz);
|
||||
submenu_add_item(
|
||||
subghz->submenu,
|
||||
"KL: CAME Space 433MHz",
|
||||
@@ -534,6 +546,14 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
|
||||
}
|
||||
break;
|
||||
case SubmenuIndexCameAtomo433:
|
||||
generated_protocol = subghz_txrx_gen_came_atomo_protocol(
|
||||
subghz->txrx, "AM650", 433920000, (key & 0x0FFFFFFF) | 0x10000000, 0x0003);
|
||||
break;
|
||||
case SubmenuIndexCameAtomo868:
|
||||
generated_protocol = subghz_txrx_gen_came_atomo_protocol(
|
||||
subghz->txrx, "AM650", 868350000, (key & 0x0FFFFFFF) | 0x10000000, 0x0003);
|
||||
break;
|
||||
case SubmenuIndexBFTMitto:
|
||||
generated_protocol = subghz_txrx_gen_keeloq_bft_protocol(
|
||||
subghz->txrx,
|
||||
|
||||
19
applications/main/subghz/subghz_extended_freq.c
Normal file
19
applications/main/subghz/subghz_extended_freq.c
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_subghz_i.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
void subghz_extended_freq() {
|
||||
bool is_extended_i = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
|
||||
if(flipper_format_file_open_existing(file, "/ext/subghz/assets/extend_range.txt")) {
|
||||
flipper_format_read_bool(file, "use_ext_range_at_own_risk", &is_extended_i, 1);
|
||||
}
|
||||
|
||||
furi_hal_subghz_set_extended_frequency(is_extended_i);
|
||||
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
@@ -73,6 +73,7 @@ typedef struct {
|
||||
SubGhzViewReceiverMode mode;
|
||||
uint8_t u_rssi;
|
||||
size_t scroll_counter;
|
||||
bool nodraw;
|
||||
} SubGhzViewReceiverModel;
|
||||
|
||||
void subghz_view_receiver_set_mode(
|
||||
@@ -243,40 +244,48 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
|
||||
bool scrollbar = model->history_item > 4;
|
||||
FuriString* str_buff = furi_string_alloc();
|
||||
|
||||
SubGhzReceiverMenuItem* item_menu;
|
||||
if(!model->nodraw) {
|
||||
SubGhzReceiverMenuItem* item_menu;
|
||||
|
||||
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
|
||||
size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0);
|
||||
item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx);
|
||||
furi_string_set(str_buff, item_menu->item_str);
|
||||
size_t scroll_counter = model->scroll_counter;
|
||||
if(model->idx == idx) {
|
||||
subghz_view_receiver_draw_frame(canvas, i, scrollbar);
|
||||
if(scroll_counter < SCROLL_DELAY) {
|
||||
// Show time of signal one moment
|
||||
furi_string_set(str_buff, item_menu->time);
|
||||
scroll_counter = 0;
|
||||
} else {
|
||||
scroll_counter -= SCROLL_DELAY;
|
||||
for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
|
||||
size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0);
|
||||
item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx);
|
||||
if(item_menu == NULL) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
scroll_counter = 0;
|
||||
if(item_menu->type == 0) {
|
||||
break;
|
||||
}
|
||||
furi_string_set(str_buff, item_menu->item_str);
|
||||
size_t scroll_counter = model->scroll_counter;
|
||||
if(model->idx == idx) {
|
||||
subghz_view_receiver_draw_frame(canvas, i, scrollbar);
|
||||
if(scroll_counter < SCROLL_DELAY) {
|
||||
// Show time of signal one moment
|
||||
furi_string_set(str_buff, item_menu->time);
|
||||
scroll_counter = 0;
|
||||
} else {
|
||||
scroll_counter -= SCROLL_DELAY;
|
||||
}
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
scroll_counter = 0;
|
||||
}
|
||||
canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
|
||||
elements_scrollable_text_line(
|
||||
canvas,
|
||||
15,
|
||||
9 + i * FRAME_HEIGHT,
|
||||
(scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX),
|
||||
str_buff,
|
||||
scroll_counter,
|
||||
(model->idx != idx),
|
||||
false);
|
||||
furi_string_reset(str_buff);
|
||||
}
|
||||
if(scrollbar) {
|
||||
elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
|
||||
}
|
||||
canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
|
||||
elements_scrollable_text_line(
|
||||
canvas,
|
||||
15,
|
||||
9 + i * FRAME_HEIGHT,
|
||||
(scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX),
|
||||
str_buff,
|
||||
scroll_counter,
|
||||
(model->idx != idx),
|
||||
false);
|
||||
furi_string_reset(str_buff);
|
||||
}
|
||||
if(scrollbar) {
|
||||
elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
|
||||
}
|
||||
furi_string_free(str_buff);
|
||||
|
||||
@@ -469,29 +478,12 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
|
||||
SubGhzViewReceiverModel * model,
|
||||
{
|
||||
if(model->history_item != 0) {
|
||||
SubGhzReceiverMenuItemArray_it_t it;
|
||||
// SubGhzReceiverMenuItem* target_item =
|
||||
// SubGhzReceiverMenuItemArray_get(model->history->data, model->idx);
|
||||
SubGhzReceiverMenuItemArray_it_last(it, model->history->data);
|
||||
while(!SubGhzReceiverMenuItemArray_end_p(it)) {
|
||||
SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it);
|
||||
|
||||
if(it->index == (size_t)(model->idx)) {
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->time);
|
||||
item->type = 0;
|
||||
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
|
||||
}
|
||||
|
||||
SubGhzReceiverMenuItemArray_previous(it);
|
||||
}
|
||||
|
||||
// Callback
|
||||
subghz_receiver->callback(
|
||||
SubGhzCustomEventViewReceiverDeleteItem, subghz_receiver->context);
|
||||
}
|
||||
},
|
||||
true);
|
||||
false);
|
||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
subghz_receiver->view,
|
||||
@@ -542,6 +534,7 @@ void subghz_view_receiver_exit(void* context) {
|
||||
model->idx = 0;
|
||||
model->list_offset = 0;
|
||||
model->history_item = 0;
|
||||
model->nodraw = false;
|
||||
},
|
||||
false);
|
||||
furi_timer_stop(subghz_receiver->timer);
|
||||
@@ -576,6 +569,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
|
||||
model->history_stat_str = furi_string_alloc();
|
||||
model->progress_str = furi_string_alloc();
|
||||
model->bar_show = SubGhzViewReceiverBarShowDefault;
|
||||
model->nodraw = false;
|
||||
model->history = malloc(sizeof(SubGhzReceiverHistory));
|
||||
SubGhzReceiverMenuItemArray_init(model->history->data);
|
||||
},
|
||||
@@ -633,6 +627,23 @@ void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_rec
|
||||
subghz_receiver->view,
|
||||
SubGhzViewReceiverModel * model,
|
||||
{
|
||||
SubGhzReceiverMenuItemArray_it_t it;
|
||||
// SubGhzReceiverMenuItem* target_item =
|
||||
// SubGhzReceiverMenuItemArray_get(model->history->data, model->idx);
|
||||
SubGhzReceiverMenuItemArray_it_last(it, model->history->data);
|
||||
while(!SubGhzReceiverMenuItemArray_end_p(it)) {
|
||||
SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it);
|
||||
|
||||
if(it->index == (size_t)(model->idx)) {
|
||||
furi_string_free(item->item_str);
|
||||
furi_string_free(item->time);
|
||||
item->type = 0;
|
||||
SubGhzReceiverMenuItemArray_remove(model->history->data, it);
|
||||
}
|
||||
|
||||
SubGhzReceiverMenuItemArray_previous(it);
|
||||
}
|
||||
|
||||
if(model->history_item == 5) {
|
||||
if(model->idx >= 2) {
|
||||
model->idx = model->history_item - 1;
|
||||
@@ -645,7 +656,20 @@ void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_rec
|
||||
}
|
||||
},
|
||||
true);
|
||||
furi_delay_ms(200);
|
||||
}
|
||||
|
||||
void subghz_view_receiver_enable_draw_callback(SubGhzViewReceiver* subghz_receiver) {
|
||||
furi_assert(subghz_receiver);
|
||||
|
||||
with_view_model(
|
||||
subghz_receiver->view, SubGhzViewReceiverModel * model, { model->nodraw = false; }, true);
|
||||
}
|
||||
|
||||
void subghz_view_receiver_disable_draw_callback(SubGhzViewReceiver* subghz_receiver) {
|
||||
furi_assert(subghz_receiver);
|
||||
|
||||
with_view_model(
|
||||
subghz_receiver->view, SubGhzViewReceiverModel * model, { model->nodraw = true; }, true);
|
||||
}
|
||||
|
||||
void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
|
||||
|
||||
@@ -49,4 +49,8 @@ void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint
|
||||
|
||||
void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
void subghz_view_receiver_enable_draw_callback(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
void subghz_view_receiver_disable_draw_callback(SubGhzViewReceiver* subghz_receiver);
|
||||
|
||||
void subghz_view_receiver_exit(void* context);
|
||||
|
||||
@@ -64,7 +64,19 @@ bool xtreme_app_apply(XtremeApp* app) {
|
||||
}
|
||||
|
||||
if(app->save_subghz) {
|
||||
furi_hal_subghz_set_is_extended(app->subghz_extend);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
do {
|
||||
if(!flipper_format_file_open_always(file, "/ext/subghz/assets/extend_range.txt"))
|
||||
break;
|
||||
if(!flipper_format_write_header_cstr(file, "Flipper SubGhz Setting File", 1)) break;
|
||||
if(!flipper_format_write_comment_cstr(
|
||||
file, "Whether to allow extended ranges that can break your flipper"))
|
||||
break;
|
||||
if(!flipper_format_write_bool(
|
||||
file, "use_ext_range_at_own_risk", &app->subghz_extend, 1))
|
||||
break;
|
||||
} while(0);
|
||||
flipper_format_free(file);
|
||||
}
|
||||
|
||||
if(app->save_name) {
|
||||
@@ -249,11 +261,13 @@ XtremeApp* xtreme_app_alloc() {
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
|
||||
if(flipper_format_file_open_existing(file, "/ext/subghz/assets/extend_range.txt")) {
|
||||
flipper_format_read_bool(file, "use_ext_range_at_own_risk", &app->subghz_extend, 1);
|
||||
}
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
app->subghz_extend = furi_hal_subghz_get_is_extended();
|
||||
|
||||
strlcpy(app->device_name, furi_hal_version_get_name_ptr(), FURI_HAL_VERSION_ARRAY_NAME_LENGTH);
|
||||
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
|
||||
BIN
assets/resources/badkb/assets/layouts/fr-FR-mac.kl
Normal file
BIN
assets/resources/badkb/assets/layouts/fr-FR-mac.kl
Normal file
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 2nd May, 2023
|
||||
# Last Checked 2nd May, 2023
|
||||
# Last Updated 17th May, 2023
|
||||
# Last Checked 17th May, 2023
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
@@ -1770,3 +1770,51 @@ type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 645 17766 3059 8884 533 461 557 1427 560 435 584 433 534 458 534 458 534 458 588 404 587 405 586 1399 586 407 584 408 558 1429 555 1457 502 491 525 1460 528 1458 554 1431 554 1431 555 1431 554 438 555 438 554 439 553 440 553 464 528 464 528 464 529 465 528 465 526 467 526 467 527 465 553 439 554 439 554 438 554 439 554 439 553 439 554 439 553 439 553 439 554 440 552 464 528 464 528 465 528 466 527 466 501 492 525 468 526 466 527 466 553 439 554 439 553 440 552 1433 553 1433 553 2936 3024 8893 552 1458 527 465 528 465 527 467 526 467 500 493 524 468 526 467 526 467 552 1434 552 441 552 441 552 1435 550 465 528 1458 527 1458 528 1459 527 1485 501 1485 500 1486 501 491 527 466 528 465 528 465 527 465 528 465 527 465 528 465 528 465 527 465 528 465 527 466 527 466 527 492 500 492 501 492 500 493 500 493 500 492 526 466 527 465 527 465 527 465 527 466 527 466 527 466 527 465 527 466 526 466 527 466 526 467 526 493 499 493 474 518 499 494 500 493 526 2936 3025 8918 526 1459 527 466 527 466 527 466 526 466 527 466 526 467 526 467 525 467 526 1460 525 493 499 493 498 495 498 495 499 493 500 493 525 1460 527 1460 525 1460 526 1460 525 1460 526 1460 526 468 525 1487 499 1487 497 495 498 495 499 493 500 1486 525 1460 525 1460 525 467 525 467 526 467 525 467 526 468 524 1462 524 468 524 494 498 1488 497 1488 499 494 499 493 525 468 525 1461 524 468 525 468 524 468 525 468 525 468 524 468 525 469 524 494 498 494 499 1488 473 1514 524
|
||||
#
|
||||
name: POWER
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 46 00 00 00
|
||||
#
|
||||
name: TEMP+
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 07 00 00 00
|
||||
#
|
||||
name: TEMP-
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 0C 00 00 00
|
||||
#
|
||||
name: TIMER
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 42 00 00 00
|
||||
#
|
||||
name: MODE
|
||||
type: parsed
|
||||
protocol: NEC
|
||||
address: 00 00 00 00
|
||||
command: 09 00 00 00
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9464 4442 637 583 601 584 601 584 601 584 600 582 603 580 604 580 630 555 629 1637 627 1665 598 1668 571 1696 569 1696 594 1672 594 1672 592 1674 593 1673 593 591 594 1673 593 1672 593 591 591 593 569 616 568 616 593 593 591 1674 593 592 593 593 592 1675 592 1675 592 1700 568 1700 568 39559 9409 2272 567 96244 9461 2246 594
|
||||
#
|
||||
name: SWING
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9505 4415 688 531 602 584 602 585 601 584 601 581 604 580 605 580 605 581 628 1636 628 1665 599 1667 597 1670 595 1671 595 1671 596 1672 595 1673 595 1673 595 592 594 591 595 1672 595 590 595 590 595 591 594 591 594 590 595 1672 595 1672 595 591 594 1672 595 1672 595 1672 595 1672 595 39565 9410 2244 592 96225 9442 2244 592
|
||||
#
|
||||
name: TIMER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9515 4477 575 611 576 551 636 610 576 611 575 610 576 581 606 580 606 580 606 1661 631 1639 628 1666 600 1667 599 1671 596 1673 595 1673 595 1673 595 593 594 617 570 594 593 1674 594 617 570 617 570 617 570 617 570 1699 569 1699 569 1699 569 618 569 1699 569 1698 570 1698 570 1699 569
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 14th Apr, 2023
|
||||
# Last Checked 2nd May, 2023
|
||||
# Last Checked 17th May, 2023
|
||||
#
|
||||
name: POWER
|
||||
type: parsed
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 2nd May, 2023
|
||||
# Last Checked 2nd May, 2023
|
||||
# Last Updated 17th May, 2023
|
||||
# Last Checked 17th May, 2023
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
@@ -1503,3 +1503,33 @@ type: parsed
|
||||
protocol: NEC
|
||||
address: 80 00 00 00
|
||||
command: 1A 00 00 00
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1370 314 1375 320 519 1167 1370 322 1339 350 465 1221 467 1222 467 1222 466 1221 467 1221 467 1221 1317 7067 1317 372 1341 349 491 1198 1340 352 1337 353 486 1202 486 1226 462 1226 462 1227 461 1227 462 1227 1311 7073 1312 378 1311 378 462 1227 1311 378 1312 378 462 1227 462 1227 461 1227 462 1227 461 1227 461 1227 1311 7074 1311 378 1311 378 462 1227 1311 379 1310 379 461 1228 461 1228 460 1228 460 1228 460 1229 459 1228 1310 7076 1309 381 1309 380 460 1229 1310 381 1309 381 458 1230 458 1230 459 1230 459 1230 459 1230 458 1230 1309 7077 1309 380 1310 380 460 1229 1310 380 1310 380 459 1229 460 1229 459 1229 460 1229 459 1229 459 1229 1310 7075 1310 379 1310 380 459 1229 1310 380 1310 379 460 1229 460 1229 459 1229 460 1228 460 1229 459 1229 1310 7074 1310 380 1310 379 460 1229 1310 379 1310 379 460 1229 459 1229 459 1229 460 1229 460 1229 460 1228 1311
|
||||
#
|
||||
name: SPEED+
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1394 321 1369 321 520 1141 1397 321 1368 321 519 1142 495 1194 495 1194 494 1195 494 1195 1366 351 491 7891 1341 350 1337 353 487 1201 1337 354 1336 354 487 1202 487 1202 487 1202 487 1202 487 1202 1336 354 487 7900 1336 354 1337 354 486 1202 1337 354 1336 354 487 1202 487 1202 487 1203 486 1202 487 1202 1336 354 487 7901 1335 354 1336 354 487 1203 1335 354 1336 355 486 1203 486 1203 486 1203 486 1203 486 1203 1335 355 486 7900 1335 355 1335 355 486 1203 1335 355 1335 355 486 1203 486 1204 485 1204 485 1204 485 1203 1335 356 485 7900 1334 356 1334 356 485 1204 1334 356 1334 356 485 1204 485 1204 484 1204 485 1204 485 1204 1333 357 484 7901 1333 357 1333 380 460 1228 1310 380 1310 380 460 1228 460 1228 460 1228 460 1228 460 1228 1310 380 460 7924 1309 380 1310 380 460 1229 1309 380 1310 380 460 1229 459 1229 460 1229 459 1230 459 1230 1309 381 458
|
||||
#
|
||||
name: ROTATE
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1343 372 1318 372 467 1194 1346 372 1318 372 467 1193 525 1164 1400 319 495 1166 523 1166 523 1167 521 7890 1344 347 1340 350 489 1200 1339 351 1339 351 488 1201 488 1201 1338 351 488 1201 488 1201 488 1201 488 7899 1338 352 1338 352 487 1201 1339 352 1338 352 488 1201 488 1201 1339 352 487 1202 487 1201 488 1201 488 7899 1338 352 1338 352 487 1201 1338 352 1338 352 487 1202 487 1202 1337 353 486 1202 487 1202 487 1202 487 7900 1337 353 1337 353 486 1202 1338 353 1337 353 486 1202 487 1202 1338 353 486 1202 487 1202 487 1202 487 7900 1337 353 1337 353 486 1203 1336 354 1336 354 485 1203 486 1204 1335 354 485 1203 485 1203 486 1203 486 7901 1336 378 1312 355 484 1205 1335 378 1312 378 461 1227 462 1227 1313 378 461 1228 461 1228 461 1228 461 7925 1312 378 1312 378 461 1228 1311 378 1312 378 461 1228 461 1228 1312 378 461 1228 461 1228 461 1228 461
|
||||
#
|
||||
name: TIMER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1370 319 1371 321 519 1167 1371 322 1366 324 488 1198 466 1222 466 1222 1317 375 464 1221 467 1220 468 7915 1317 372 1341 350 490 1197 1340 376 1313 377 462 1226 462 1226 462 1226 1312 377 462 1226 462 1226 462 7921 1312 377 1313 377 462 1226 1312 377 1312 377 462 1226 462 1226 462 1226 1312 378 462 1226 462 1226 462 7922 1312 377 1313 377 462 1226 1313 377 1312 377 462 1226 462 1226 462 1226 1313 377 462 1226 462 1226 462 7921 1312 377 1312 377 462 1226 1312 377 1313 377 462 1226 462 1226 462 1226 1312 377 462 1226 462 1226 462 7921 1312 377 1313 377 462 1226 1313 377 1312 354 485 1202 486 1202 486 1202 1337 352 487 1202 487 1201 487 7897 1337 352 1337 351 488 1200 1339 351 1339 352 487 1201 487 1201 488 1201 1338 352 487 1201 487 1201 488 7896 1338 352 1337 352 487 1201 1337 352 1337 352 487 1201 487 1201 487 1201 1338 352 487 1201 487 1201 487
|
||||
#
|
||||
name: MODE
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 1369 349 1370 319 521 1167 1371 321 1340 349 466 1221 467 1222 467 1221 468 1221 1318 373 466 1220 468 7917 1344 347 1341 349 489 1198 1340 351 1338 352 487 1202 486 1202 486 1202 486 1202 1337 353 486 1202 486 7922 1312 377 1313 377 462 1227 1312 377 1313 378 461 1227 461 1227 462 1227 462 1227 1312 377 462 1227 461 7923 1312 378 1311 378 461 1227 1312 378 1311 377 462 1227 461 1227 461 1227 461 1227 1312 377 462 1227 462 7922 1312 378 1312 377 462 1227 1312 354 1336 354 485 1227 461 1227 461 1227 461 1203 1336 353 486 1203 486 7922 1312 353 1336 354 485 1203 1336 354 1336 354 485 1203 485 1227 461 1227 461 1227 1312 378 461 1227 461 7923 1312 378 1312 378 461 1227 1312 378 1312 378 461 1228 461 1228 461 1228 460 1228 1311 378 461 1227 461 7923 1311 378 1311 378 461 1227 1312 378 1312 378 461 1227 462 1227 461 1227 461 1227 1312 378 461 1228 461 6641 1312 378 1312 355 484 1228 1311 355 1335 378 461 1228 461 1228 460 1228 460 1228 1311 378 461 1228 460 7924 1311 379 1310 379 460 1228 1311 379 1311 379 460 1229 459 1229 459 1229 460 1229 1310 380 459 1229 459 7925 1310 380 1309 381 458 1230 1309 381 1309 381 458 1230 458 1231 457 1231 458 1231 1308 381 458 1231 457 7952 1283 407 1283 407 432 1256 1283 407 1283 407 432 1257 431 1257 432 1257 431 1257 1283 408 431 1257 431
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 2nd May, 2023
|
||||
# Last Checked 2nd May, 2023
|
||||
# Last Checked 17th May, 2023
|
||||
#
|
||||
# ON
|
||||
name: POWER
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Filetype: IR library file
|
||||
Version: 1
|
||||
# Last Updated 2nd May, 2023
|
||||
# Last Checked 2nd May, 2023
|
||||
# Last Updated 17th May, 2023
|
||||
# Last Checked 17th May, 2023
|
||||
#
|
||||
name: POWER
|
||||
type: parsed
|
||||
@@ -1973,3 +1973,77 @@ type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 273 1816 272 767 277 789 255 785 249 791 253 787 246 1818 281 785 248 765 279 1812 276 789 255 759 275 791 253 1812 276 789 255 46372 281 1808 280 785 249 791 253 787 247 793 251 1814 274 791 253 1812 276 1814 274 791 253 1812 276 1814 274 1815 273 792 252 1813 275 42172 272 1819 280 785 249 765 279 761 273 768 276 764 280 1811 277 788 246 768 276 1815 273 792 252 788 246 794 250 1815 273 791 253
|
||||
#
|
||||
# Brandt TV
|
||||
#
|
||||
name: POWER
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9346 4516 657 502 659 502 688 473 687 475 634 527 635 527 634 1662 633 528 662 1634 662 1658 635 1660 608 1687 609 1687 633 1662 634 527 634 1662 634 528 633 1663 632 529 632 530 631 1665 630 531 630 531 631 531 630 1666 630 531 630 1666 630 1666 630 532 630 1666 630 1666 630 1666 630
|
||||
#
|
||||
name: VOL+
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9348 4542 631 529 632 503 659 502 688 474 634 527 634 527 634 1661 635 528 661 1636 660 1659 634 1637 632 1687 608 1687 609 1687 609 552 632 1664 633 528 633 1663 633 529 632 1664 631 1665 631 531 630 531 631 531 631 1665 631 531 631 1666 630 531 631 531 630 1666 630 1666 630 1666 631
|
||||
#
|
||||
name: VOL-
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9376 4512 660 475 684 475 635 527 634 528 633 527 634 527 634 1662 662 525 636 1658 637 1658 637 1658 636 1659 636 1660 635 1660 635 526 635 1661 634 527 634 1662 633 1663 632 1664 631 1665 630 531 631 531 630 531 630 1666 630 531 630 531 631 531 630 531 631 1666 630 1666 630 1667 630
|
||||
#
|
||||
name: CH+
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9315 4513 657 501 660 501 659 500 661 502 688 499 661 474 634 1660 634 527 634 1660 634 1686 608 1687 607 1686 608 1686 608 1686 608 552 608 1686 608 1687 607 1687 632 530 631 1664 630 1665 630 531 630 531 630 531 630 531 630 531 630 1665 630 531 630 531 630 1665 630 1665 630 1665 630
|
||||
#
|
||||
name: CH-
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9345 4540 631 503 658 529 661 475 683 476 635 526 635 527 634 1661 634 527 662 1658 636 1659 634 1660 608 1686 609 1686 634 1661 634 527 634 1661 634 1662 633 1662 633 1663 632 1664 630 1665 630 531 630 531 630 531 630 531 631 531 630 531 630 531 630 532 629 1666 630 1666 629 1666 629
|
||||
#
|
||||
name: MUTE
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 9348 4516 657 501 660 502 659 502 659 502 688 474 634 527 634 1662 634 528 633 1687 634 1660 608 1664 631 1687 608 1687 609 1686 609 552 609 1687 608 553 632 529 633 529 632 530 631 1665 630 531 630 531 631 531 630 1666 630 1666 630 1666 630 1666 630 531 631 1666 630 1666 630 1666 630
|
||||
#
|
||||
name: POWER
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 3E 00 00 00
|
||||
command: 0C 00 00 00
|
||||
#
|
||||
name: VOL+
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 3E 00 00 00
|
||||
command: 14 00 00 00
|
||||
#
|
||||
name: VOL-
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 3E 00 00 00
|
||||
command: 15 00 00 00
|
||||
#
|
||||
name: CH+
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 3E 00 00 00
|
||||
command: 12 00 00 00
|
||||
#
|
||||
name: CH-
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 3E 00 00 00
|
||||
command: 13 00 00 00
|
||||
#
|
||||
name: MUTE
|
||||
type: parsed
|
||||
protocol: Samsung32
|
||||
address: 3E 00 00 00
|
||||
command: 0D 00 00 00
|
||||
|
||||
@@ -1455,7 +1455,6 @@ Function,+,furi_hal_subghz_enable_ext_power,_Bool,
|
||||
Function,+,furi_hal_subghz_flush_rx,void,
|
||||
Function,+,furi_hal_subghz_flush_tx,void,
|
||||
Function,+,furi_hal_subghz_get_external_power_disable,_Bool,
|
||||
Function,+,furi_hal_subghz_get_is_extended,_Bool,
|
||||
Function,+,furi_hal_subghz_get_lqi,uint8_t,
|
||||
Function,+,furi_hal_subghz_get_radio_type,SubGhzRadioType,
|
||||
Function,+,furi_hal_subghz_get_rolling_counter_mult,uint8_t,
|
||||
@@ -1482,7 +1481,6 @@ Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin*
|
||||
Function,+,furi_hal_subghz_set_external_power_disable,void,_Bool
|
||||
Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t
|
||||
Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t
|
||||
Function,+,furi_hal_subghz_set_is_extended,void,_Bool
|
||||
Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath
|
||||
Function,+,furi_hal_subghz_set_rolling_counter_mult,void,uint8_t
|
||||
Function,+,furi_hal_subghz_set_timestamp_file_names,void,_Bool
|
||||
@@ -2822,6 +2820,7 @@ Function,+,subghz_protocol_blocks_parity_bytes,uint8_t,"const uint8_t[], size_t"
|
||||
Function,+,subghz_protocol_blocks_reverse_key,uint64_t,"uint64_t, uint8_t"
|
||||
Function,+,subghz_protocol_blocks_set_bit_array,void,"_Bool, uint8_t[], size_t, size_t"
|
||||
Function,+,subghz_protocol_blocks_xor_bytes,uint8_t,"const uint8_t[], size_t"
|
||||
Function,-,subghz_protocol_came_atomo_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint16_t, SubGhzRadioPreset*"
|
||||
Function,-,subghz_protocol_decoder_alutech_at_4n_alloc,void*,SubGhzEnvironment*
|
||||
Function,-,subghz_protocol_decoder_alutech_at_4n_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*"
|
||||
Function,-,subghz_protocol_decoder_alutech_at_4n_feed,void,"void*, _Bool, uint32_t"
|
||||
|
||||
|
@@ -41,6 +41,7 @@ volatile FuriHalSubGhz furi_hal_subghz = {
|
||||
.rolling_counter_mult = 1,
|
||||
.ext_module_power_disabled = false,
|
||||
.timestamp_file_names = false,
|
||||
.extended_frequency_i = false,
|
||||
};
|
||||
|
||||
void furi_hal_subghz_select_radio_type(SubGhzRadioType state) {
|
||||
@@ -96,6 +97,10 @@ bool furi_hal_subghz_get_timestamp_file_names(void) {
|
||||
return furi_hal_subghz.timestamp_file_names;
|
||||
}
|
||||
|
||||
void furi_hal_subghz_set_extended_frequency(bool state_i) {
|
||||
furi_hal_subghz.extended_frequency_i = state_i;
|
||||
}
|
||||
|
||||
void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin) {
|
||||
furi_hal_subghz.async_mirror_pin = pin;
|
||||
}
|
||||
@@ -448,49 +453,20 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
bool furi_hal_subghz_get_is_extended() {
|
||||
bool is_extended = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
|
||||
if(flipper_format_file_open_existing(file, "/ext/subghz/assets/extend_range.txt")) {
|
||||
flipper_format_read_bool(file, "use_ext_range_at_own_risk", &is_extended, 1);
|
||||
}
|
||||
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return is_extended;
|
||||
}
|
||||
|
||||
void furi_hal_subghz_set_is_extended(bool is_extended) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
||||
|
||||
do {
|
||||
if(!flipper_format_file_open_always(file, "/ext/subghz/assets/extend_range.txt")) break;
|
||||
if(!flipper_format_write_header_cstr(file, "Flipper SubGhz Setting File", 1)) break;
|
||||
if(!flipper_format_write_comment_cstr(
|
||||
file, "Whether to allow extended ranges that can break your flipper"))
|
||||
break;
|
||||
if(!flipper_format_write_bool(file, "use_ext_range_at_own_risk", &is_extended, 1)) break;
|
||||
} while(0);
|
||||
|
||||
flipper_format_free(file);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
bool furi_hal_subghz_is_tx_allowed(uint32_t value) {
|
||||
bool is_extended = furi_hal_subghz_get_is_extended();
|
||||
bool allow_extended_for_int = furi_hal_subghz.extended_frequency_i;
|
||||
|
||||
if(!(value >= 299999755 && value <= 350000335) && // was increased from 348 to 350
|
||||
if(!(allow_extended_for_int) &&
|
||||
!(value >= 299999755 && value <= 350000335) && // was increased from 348 to 350
|
||||
!(value >= 386999938 && value <= 467750000) && // was increased from 464 to 467.75
|
||||
!(value >= 778999847 && value <= 928000000) && !(is_extended)) {
|
||||
!(value >= 778999847 && value <= 928000000)) {
|
||||
FURI_LOG_I(TAG, "Frequency blocked - outside default range");
|
||||
return false;
|
||||
} else if(
|
||||
(allow_extended_for_int) && //
|
||||
!(value >= 281000000 && value <= 361000000) &&
|
||||
!(value >= 378000000 && value <= 481000000) &&
|
||||
!(value >= 749000000 && value <= 962000000) && is_extended) {
|
||||
!(value >= 749000000 && value <= 962000000)) {
|
||||
FURI_LOG_I(TAG, "Frequency blocked - outside extended range");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -78,8 +78,9 @@ typedef struct {
|
||||
FuriHalSpiBusHandle* spi_bus_handle;
|
||||
const GpioPin* cc1101_g0_pin;
|
||||
uint8_t rolling_counter_mult;
|
||||
bool ext_module_power_disabled;
|
||||
bool timestamp_file_names;
|
||||
bool ext_module_power_disabled : 1;
|
||||
bool timestamp_file_names : 1;
|
||||
bool extended_frequency_i : 1;
|
||||
} FuriHalSubGhz;
|
||||
|
||||
extern volatile FuriHalSubGhz furi_hal_subghz;
|
||||
@@ -225,18 +226,6 @@ bool furi_hal_subghz_is_frequency_valid(uint32_t value);
|
||||
*/
|
||||
uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value);
|
||||
|
||||
/** Read extend and bypass settings values into out params
|
||||
*
|
||||
* @return is_extended bool
|
||||
*/
|
||||
bool furi_hal_subghz_get_is_extended();
|
||||
|
||||
/** Set extend and bypass settings values to file
|
||||
*
|
||||
* @param is_extended bool for extend
|
||||
*/
|
||||
void furi_hal_subghz_set_is_extended(bool is_extended);
|
||||
|
||||
/** Сheck if transmission is allowed on this frequency with your current config
|
||||
*
|
||||
* @param value frequency in Hz
|
||||
|
||||
3
firmware/targets/f7/furi_hal/furi_hal_subghz_i.h
Normal file
3
firmware/targets/f7/furi_hal/furi_hal_subghz_i.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void furi_hal_subghz_set_extended_frequency(bool state_i);
|
||||
@@ -991,11 +991,17 @@ bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
||||
if(!flipper_format_get_value_count(file, "AID", &data_cnt)) break;
|
||||
data->aid_len = data_cnt;
|
||||
if(!flipper_format_read_hex(file, "AID", data->aid, data->aid_len)) break;
|
||||
if(!flipper_format_read_string(file, "Name", temp_str)) break;
|
||||
if(!flipper_format_read_string(file, "Name", temp_str)) {
|
||||
furi_string_set_str(temp_str, "Unknown");
|
||||
}
|
||||
strlcpy(data->name, furi_string_get_cstr(temp_str), sizeof(data->name));
|
||||
if(!flipper_format_get_value_count(file, "Number", &data_cnt)) break;
|
||||
if(!flipper_format_get_value_count(file, "Number", &data_cnt)) {
|
||||
data_cnt = 0;
|
||||
}
|
||||
data->number_len = data_cnt;
|
||||
if(!flipper_format_read_hex(file, "Number", data->number, data->number_len)) break;
|
||||
if(!flipper_format_read_hex(file, "Number", data->number, data->number_len)) {
|
||||
memset(data->number, 0, sizeof(data->number));
|
||||
};
|
||||
parsed = true;
|
||||
// Load optional data
|
||||
uint8_t exp_data[2] = {};
|
||||
@@ -1401,9 +1407,8 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
|
||||
break;
|
||||
nfc_device_prepare_format_string(dev, temp_str);
|
||||
if(!flipper_format_write_string(file, "Device type", temp_str)) break;
|
||||
// Write UID, ATQA, SAK
|
||||
if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
|
||||
break;
|
||||
// Write UID
|
||||
if(!flipper_format_write_comment_cstr(file, "UID is common for all formats")) break;
|
||||
if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
|
||||
|
||||
if(dev->format != NfcDeviceSaveFormatNfcV) {
|
||||
|
||||
@@ -378,7 +378,8 @@ bool mf_classic_check_card_type(FuriHalNfcADevData* data) {
|
||||
uint8_t ATQA0 = data->atqa[0];
|
||||
uint8_t ATQA1 = data->atqa[1];
|
||||
uint8_t SAK = data->sak;
|
||||
if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) {
|
||||
if((ATQA0 == 0x44 || ATQA0 == 0x04) &&
|
||||
(SAK == 0x08 || SAK == 0x88 || SAK == 0x09 || SAK == 0x89)) {
|
||||
return true;
|
||||
} else if((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01)) {
|
||||
//skylanders support
|
||||
@@ -397,7 +398,7 @@ MfClassicType mf_classic_get_classic_type(FuriHalNfcADevData* data) {
|
||||
if((ATQA0 == 0x44 || ATQA0 == 0x04)) {
|
||||
if((SAK == 0x08 || SAK == 0x88)) {
|
||||
return MfClassicType1k;
|
||||
} else if(SAK == 0x09) {
|
||||
} else if((SAK == 0x09 || SAK == 0x89)) {
|
||||
return MfClassicTypeMini;
|
||||
}
|
||||
} else if((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01)) {
|
||||
|
||||
@@ -10,7 +10,8 @@ MifareType mifare_common_get_type(FuriHalNfcADevData* data) {
|
||||
if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
|
||||
type = MifareTypeUltralight;
|
||||
} else if(
|
||||
((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) ||
|
||||
((ATQA0 == 0x44 || ATQA0 == 0x04) &&
|
||||
(SAK == 0x08 || SAK == 0x88 || SAK == 0x09 || SAK == 0x89)) ||
|
||||
((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) ||
|
||||
((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01))) {
|
||||
type = MifareTypeClassic;
|
||||
|
||||
@@ -15,12 +15,20 @@
|
||||
|
||||
#define TAG "NfcV"
|
||||
|
||||
/* macros to map "modulate field" flag to GPIO level */
|
||||
#define GPIO_LEVEL_MODULATED NFCV_LOAD_MODULATION_POLARITY
|
||||
#define GPIO_LEVEL_UNMODULATED (!GPIO_LEVEL_MODULATED)
|
||||
|
||||
/* timing macros */
|
||||
#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f)
|
||||
#define DIGITAL_SIGNAL_UNIT_US (100000.0f)
|
||||
|
||||
ReturnCode nfcv_inventory(uint8_t* uid) {
|
||||
uint16_t received = 0;
|
||||
rfalNfcvInventoryRes res;
|
||||
ReturnCode ret = ERR_NONE;
|
||||
|
||||
for(int tries = 0; tries < 5; tries++) {
|
||||
for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) {
|
||||
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
|
||||
ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received);
|
||||
|
||||
@@ -31,7 +39,7 @@ ReturnCode nfcv_inventory(uint8_t* uid) {
|
||||
|
||||
if(ret == ERR_NONE) {
|
||||
if(uid != NULL) {
|
||||
memcpy(uid, res.UID, 8);
|
||||
memcpy(uid, res.UID, NFCV_UID_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +55,7 @@ ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* nfcv_data) {
|
||||
FURI_LOG_D(TAG, "Reading block %d/%d", block, (nfcv_data->block_num - 1));
|
||||
|
||||
ReturnCode ret = ERR_NONE;
|
||||
for(int tries = 0; tries < 5; tries++) {
|
||||
for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) {
|
||||
ret = rfalNfcvPollerReadSingleBlock(
|
||||
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block, rxBuf, sizeof(rxBuf), &received);
|
||||
|
||||
@@ -80,7 +88,7 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
|
||||
|
||||
FURI_LOG_D(TAG, "Read SYSTEM INFORMATION...");
|
||||
|
||||
for(int tries = 0; tries < 5; tries++) {
|
||||
for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) {
|
||||
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
|
||||
ret = rfalNfcvPollerGetSystemInformation(
|
||||
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, rxBuf, sizeof(rxBuf), &received);
|
||||
@@ -92,16 +100,16 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
|
||||
|
||||
if(ret == ERR_NONE) {
|
||||
nfc_data->type = FuriHalNfcTypeV;
|
||||
nfc_data->uid_len = 8;
|
||||
nfc_data->uid_len = NFCV_UID_LENGTH;
|
||||
/* UID is stored reversed in this response */
|
||||
for(int pos = 0; pos < nfc_data->uid_len; pos++) {
|
||||
nfc_data->uid[pos] = rxBuf[2 + (7 - pos)];
|
||||
nfc_data->uid[pos] = rxBuf[2 + (NFCV_UID_LENGTH - 1 - pos)];
|
||||
}
|
||||
nfcv_data->dsfid = rxBuf[10];
|
||||
nfcv_data->afi = rxBuf[11];
|
||||
nfcv_data->block_num = rxBuf[12] + 1;
|
||||
nfcv_data->block_size = rxBuf[13] + 1;
|
||||
nfcv_data->ic_ref = rxBuf[14];
|
||||
nfcv_data->dsfid = rxBuf[NFCV_UID_LENGTH + 2];
|
||||
nfcv_data->afi = rxBuf[NFCV_UID_LENGTH + 3];
|
||||
nfcv_data->block_num = rxBuf[NFCV_UID_LENGTH + 4] + 1;
|
||||
nfcv_data->block_size = rxBuf[NFCV_UID_LENGTH + 5] + 1;
|
||||
nfcv_data->ic_ref = rxBuf[NFCV_UID_LENGTH + 6];
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
" UID: %02X %02X %02X %02X %02X %02X %02X %02X",
|
||||
@@ -304,7 +312,7 @@ bool nfcv_emu_alloc(NfcVData* nfcv_data) {
|
||||
if(!nfcv_data->emu_air.nfcv_resp_unmod) {
|
||||
return false;
|
||||
}
|
||||
nfcv_data->emu_air.nfcv_resp_unmod->start_level = false;
|
||||
nfcv_data->emu_air.nfcv_resp_unmod->start_level = GPIO_LEVEL_UNMODULATED;
|
||||
nfcv_data->emu_air.nfcv_resp_unmod->edge_timings[0] =
|
||||
(uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S);
|
||||
nfcv_data->emu_air.nfcv_resp_unmod->edge_cnt = 1;
|
||||
@@ -315,7 +323,7 @@ bool nfcv_emu_alloc(NfcVData* nfcv_data) {
|
||||
if(!nfcv_data->emu_air.nfcv_resp_pulse) {
|
||||
return false;
|
||||
}
|
||||
nfcv_data->emu_air.nfcv_resp_pulse->start_level = true;
|
||||
nfcv_data->emu_air.nfcv_resp_pulse->start_level = GPIO_LEVEL_MODULATED;
|
||||
nfcv_data->emu_air.nfcv_resp_pulse->edge_timings[0] =
|
||||
(uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
|
||||
nfcv_data->emu_air.nfcv_resp_pulse->edge_timings[1] =
|
||||
@@ -329,7 +337,7 @@ bool nfcv_emu_alloc(NfcVData* nfcv_data) {
|
||||
if(!nfcv_data->emu_air.nfcv_resp_half_pulse) {
|
||||
return false;
|
||||
}
|
||||
nfcv_data->emu_air.nfcv_resp_half_pulse->start_level = true;
|
||||
nfcv_data->emu_air.nfcv_resp_half_pulse->start_level = GPIO_LEVEL_MODULATED;
|
||||
nfcv_data->emu_air.nfcv_resp_half_pulse->edge_timings[0] =
|
||||
(uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
|
||||
nfcv_data->emu_air.nfcv_resp_half_pulse->edge_cnt = 1;
|
||||
@@ -461,11 +469,10 @@ void nfcv_emu_send(
|
||||
digital_sequence_add(nfcv->emu_air.nfcv_signal, eof);
|
||||
}
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
furi_hal_gpio_write(&gpio_spi_r_mosi, GPIO_LEVEL_UNMODULATED);
|
||||
digital_sequence_set_sendtime(nfcv->emu_air.nfcv_signal, send_time);
|
||||
digital_sequence_send(nfcv->emu_air.nfcv_signal);
|
||||
FURI_CRITICAL_EXIT();
|
||||
furi_hal_gpio_write(&gpio_spi_r_mosi, false);
|
||||
furi_hal_gpio_write(&gpio_spi_r_mosi, GPIO_LEVEL_UNMODULATED);
|
||||
|
||||
if(tx_rx->sniff_tx) {
|
||||
tx_rx->sniff_tx(data, length * 8, false, tx_rx->sniff_context);
|
||||
@@ -473,14 +480,14 @@ void nfcv_emu_send(
|
||||
}
|
||||
|
||||
static void nfcv_revuidcpy(uint8_t* dst, uint8_t* src) {
|
||||
for(int pos = 0; pos < 8; pos++) {
|
||||
dst[pos] = src[7 - pos];
|
||||
for(int pos = 0; pos < NFCV_UID_LENGTH; pos++) {
|
||||
dst[pos] = src[NFCV_UID_LENGTH - 1 - pos];
|
||||
}
|
||||
}
|
||||
|
||||
static int nfcv_revuidcmp(uint8_t* dst, uint8_t* src) {
|
||||
for(int pos = 0; pos < 8; pos++) {
|
||||
if(dst[pos] != src[7 - pos]) {
|
||||
for(int pos = 0; pos < NFCV_UID_LENGTH; pos++) {
|
||||
if(dst[pos] != src[NFCV_UID_LENGTH - 1 - pos]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -517,24 +524,26 @@ void nfcv_emu_handle_packet(
|
||||
/* parse the frame data for the upcoming part 3 handling */
|
||||
ctx->flags = nfcv_data->frame[0];
|
||||
ctx->command = nfcv_data->frame[1];
|
||||
ctx->selected = (ctx->flags & RFAL_NFCV_REQ_FLAG_SELECT);
|
||||
ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) &&
|
||||
(ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
|
||||
ctx->advanced = (ctx->command >= 0xA0);
|
||||
ctx->selected = !(ctx->flags & NFCV_REQ_FLAG_INVENTORY) && (ctx->flags & NFCV_REQ_FLAG_SELECT);
|
||||
ctx->addressed = !(ctx->flags & NFCV_REQ_FLAG_INVENTORY) &&
|
||||
(ctx->flags & NFCV_REQ_FLAG_ADDRESS);
|
||||
ctx->advanced = (ctx->command >= NFCV_CMD_ADVANCED);
|
||||
ctx->address_offset = 2 + (ctx->advanced ? 1 : 0);
|
||||
ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0);
|
||||
ctx->payload_offset = ctx->address_offset + (ctx->addressed ? NFCV_UID_LENGTH : 0);
|
||||
ctx->response_flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof;
|
||||
ctx->send_time = nfcv_data->eof_timestamp + NFCV_FDT_FC(4380);
|
||||
|
||||
if(ctx->flags & RFAL_NFCV_REQ_FLAG_DATA_RATE) {
|
||||
if(ctx->flags & NFCV_REQ_FLAG_DATA_RATE) {
|
||||
ctx->response_flags |= NfcVSendFlagsHighRate;
|
||||
}
|
||||
if(ctx->flags & RFAL_NFCV_REQ_FLAG_SUB_CARRIER) {
|
||||
if(ctx->flags & NFCV_REQ_FLAG_SUB_CARRIER) {
|
||||
ctx->response_flags |= NfcVSendFlagsTwoSubcarrier;
|
||||
}
|
||||
|
||||
if(ctx->payload_offset + 2 > nfcv_data->frame_length) {
|
||||
#ifdef NFCV_VERBOSE
|
||||
FURI_LOG_D(TAG, "command 0x%02X, but packet is too short", ctx->command);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -542,6 +551,7 @@ void nfcv_emu_handle_packet(
|
||||
if(ctx->addressed) {
|
||||
uint8_t* address = &nfcv_data->frame[ctx->address_offset];
|
||||
if(nfcv_revuidcmp(address, nfc_data->uid)) {
|
||||
#ifdef NFCV_VERBOSE
|
||||
FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command);
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
@@ -565,15 +575,18 @@ void nfcv_emu_handle_packet(
|
||||
nfc_data->uid[5],
|
||||
nfc_data->uid[6],
|
||||
nfc_data->uid[7]);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(ctx->selected && !nfcv_data->selected) {
|
||||
#ifdef NFCV_VERBOSE
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"selected card shall execute command 0x%02X, but we were not selected",
|
||||
ctx->command);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -581,22 +594,42 @@ void nfcv_emu_handle_packet(
|
||||
if(ctx->emu_protocol_filter != NULL) {
|
||||
if(ctx->emu_protocol_filter(tx_rx, nfc_data, nfcv_data)) {
|
||||
if(strlen(nfcv_data->last_command) > 0) {
|
||||
#ifdef NFCV_VERBOSE
|
||||
FURI_LOG_D(
|
||||
TAG, "Received command %s (handled by filter)", nfcv_data->last_command);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch(ctx->command) {
|
||||
case ISO15693_INVENTORY: {
|
||||
if(!nfcv_data->quiet) {
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[1] = nfcv_data->dsfid;
|
||||
nfcv_revuidcpy(&ctx->response_buffer[2], nfc_data->uid);
|
||||
case NFCV_CMD_INVENTORY: {
|
||||
bool respond = false;
|
||||
|
||||
if(ctx->flags & NFCV_REQ_FLAG_AFI) {
|
||||
uint8_t afi = nfcv_data->frame[ctx->payload_offset];
|
||||
if(afi == nfcv_data->afi) {
|
||||
respond = true;
|
||||
}
|
||||
} else {
|
||||
respond = true;
|
||||
}
|
||||
|
||||
if(!nfcv_data->quiet && respond) {
|
||||
int buffer_pos = 0;
|
||||
ctx->response_buffer[buffer_pos++] = NFCV_NOERROR;
|
||||
ctx->response_buffer[buffer_pos++] = nfcv_data->dsfid;
|
||||
nfcv_revuidcpy(&ctx->response_buffer[buffer_pos], nfc_data->uid);
|
||||
buffer_pos += NFCV_UID_LENGTH;
|
||||
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 10, ctx->response_flags, ctx->send_time);
|
||||
tx_rx,
|
||||
nfcv_data,
|
||||
ctx->response_buffer,
|
||||
buffer_pos,
|
||||
ctx->response_flags,
|
||||
ctx->send_time);
|
||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
|
||||
} else {
|
||||
snprintf(
|
||||
@@ -605,18 +638,18 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_STAYQUIET: {
|
||||
case NFCV_CMD_STAY_QUIET: {
|
||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET");
|
||||
nfcv_data->quiet = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_LOCKBLOCK: {
|
||||
case NFCV_CMD_LOCK_BLOCK: {
|
||||
uint8_t block = nfcv_data->frame[ctx->payload_offset];
|
||||
nfcv_data->security_status[block] |= 0x01;
|
||||
nfcv_data->modified = true;
|
||||
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
|
||||
@@ -624,13 +657,13 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_WRITE_DSFID: {
|
||||
case NFCV_CMD_WRITE_DSFID: {
|
||||
uint8_t id = nfcv_data->frame[ctx->payload_offset];
|
||||
|
||||
if(!(nfcv_data->security_status[0] & NfcVLockBitDsfid)) {
|
||||
nfcv_data->dsfid = id;
|
||||
nfcv_data->modified = true;
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
}
|
||||
@@ -639,13 +672,13 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_WRITE_AFI: {
|
||||
case NFCV_CMD_WRITE_AFI: {
|
||||
uint8_t id = nfcv_data->frame[ctx->payload_offset];
|
||||
|
||||
if(!(nfcv_data->security_status[0] & NfcVLockBitAfi)) {
|
||||
nfcv_data->afi = id;
|
||||
nfcv_data->modified = true;
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
}
|
||||
@@ -654,12 +687,12 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_LOCK_DSFID: {
|
||||
case NFCV_CMD_LOCK_DSFID: {
|
||||
if(!(nfcv_data->security_status[0] & NfcVLockBitDsfid)) {
|
||||
nfcv_data->security_status[0] |= NfcVLockBitDsfid;
|
||||
nfcv_data->modified = true;
|
||||
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
}
|
||||
@@ -668,12 +701,12 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_LOCK_AFI: {
|
||||
case NFCV_CMD_LOCK_AFI: {
|
||||
if(!(nfcv_data->security_status[0] & NfcVLockBitAfi)) {
|
||||
nfcv_data->security_status[0] |= NfcVLockBitAfi;
|
||||
nfcv_data->modified = true;
|
||||
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
}
|
||||
@@ -682,8 +715,8 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_SELECT: {
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
case NFCV_CMD_SELECT: {
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_data->selected = true;
|
||||
nfcv_data->quiet = false;
|
||||
nfcv_emu_send(
|
||||
@@ -692,8 +725,8 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_RESET_TO_READY: {
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
case NFCV_CMD_RESET_TO_READY: {
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_data->quiet = false;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
@@ -701,24 +734,24 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_READ_MULTI_BLOCK:
|
||||
case ISO15693_READBLOCK: {
|
||||
case NFCV_CMD_READ_MULTI_BLOCK:
|
||||
case NFCV_CMD_READ_BLOCK: {
|
||||
uint8_t block = nfcv_data->frame[ctx->payload_offset];
|
||||
uint8_t blocks = 1;
|
||||
|
||||
if(ctx->command == ISO15693_READ_MULTI_BLOCK) {
|
||||
if(ctx->command == NFCV_CMD_READ_MULTI_BLOCK) {
|
||||
blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1;
|
||||
}
|
||||
|
||||
if(block + blocks <= nfcv_data->block_num) {
|
||||
uint8_t buffer_pos = 0;
|
||||
|
||||
ctx->response_buffer[buffer_pos++] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[buffer_pos++] = NFCV_NOERROR;
|
||||
|
||||
for(int block_index = 0; block_index < blocks; block_index++) {
|
||||
int block_current = block + block_index;
|
||||
/* prepend security status */
|
||||
if(ctx->flags & RFAL_NFCV_REQ_FLAG_OPTION) {
|
||||
if(ctx->flags & NFCV_REQ_FLAG_OPTION) {
|
||||
ctx->response_buffer[buffer_pos++] =
|
||||
nfcv_data->security_status[1 + block_current];
|
||||
}
|
||||
@@ -736,19 +769,24 @@ void nfcv_emu_handle_packet(
|
||||
buffer_pos,
|
||||
ctx->response_flags,
|
||||
ctx->send_time);
|
||||
} else {
|
||||
ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR;
|
||||
ctx->response_buffer[1] = NFCV_ERROR_GENERIC;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 2, ctx->response_flags, ctx->send_time);
|
||||
}
|
||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_WRITE_MULTI_BLOCK:
|
||||
case ISO15693_WRITEBLOCK: {
|
||||
case NFCV_CMD_WRITE_MULTI_BLOCK:
|
||||
case NFCV_CMD_WRITE_BLOCK: {
|
||||
uint8_t blocks = 1;
|
||||
uint8_t block = nfcv_data->frame[ctx->payload_offset];
|
||||
uint8_t data_pos = ctx->payload_offset + 1;
|
||||
|
||||
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
|
||||
if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) {
|
||||
blocks = nfcv_data->frame[data_pos] + 1;
|
||||
data_pos++;
|
||||
}
|
||||
@@ -758,7 +796,7 @@ void nfcv_emu_handle_packet(
|
||||
|
||||
if((block + blocks) <= nfcv_data->block_num &&
|
||||
(data_pos + data_len + 2) == nfcv_data->frame_length) {
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
memcpy(
|
||||
&nfcv_data->data[nfcv_data->block_size * block],
|
||||
&nfcv_data->frame[data_pos],
|
||||
@@ -767,9 +805,14 @@ void nfcv_emu_handle_packet(
|
||||
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
} else {
|
||||
ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR;
|
||||
ctx->response_buffer[1] = NFCV_ERROR_GENERIC;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 2, ctx->response_flags, ctx->send_time);
|
||||
}
|
||||
|
||||
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
|
||||
if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) {
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
sizeof(nfcv_data->last_command),
|
||||
@@ -790,24 +833,32 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_GET_SYSTEM_INFO: {
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[1] = 0x0F;
|
||||
nfcv_revuidcpy(&ctx->response_buffer[2], nfc_data->uid);
|
||||
ctx->response_buffer[10] = nfcv_data->dsfid; /* DSFID */
|
||||
ctx->response_buffer[11] = nfcv_data->afi; /* AFI */
|
||||
ctx->response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */
|
||||
ctx->response_buffer[13] = nfcv_data->block_size - 1; /* block size */
|
||||
ctx->response_buffer[14] = nfcv_data->ic_ref; /* IC reference */
|
||||
case NFCV_CMD_GET_SYSTEM_INFO: {
|
||||
int buffer_pos = 0;
|
||||
ctx->response_buffer[buffer_pos++] = NFCV_NOERROR;
|
||||
ctx->response_buffer[buffer_pos++] = NFCV_SYSINFO_FLAG_DSFID | NFCV_SYSINFO_FLAG_AFI |
|
||||
NFCV_SYSINFO_FLAG_MEMSIZE | NFCV_SYSINFO_FLAG_ICREF;
|
||||
nfcv_revuidcpy(&ctx->response_buffer[buffer_pos], nfc_data->uid);
|
||||
buffer_pos += NFCV_UID_LENGTH;
|
||||
ctx->response_buffer[buffer_pos++] = nfcv_data->dsfid; /* DSFID */
|
||||
ctx->response_buffer[buffer_pos++] = nfcv_data->afi; /* AFI */
|
||||
ctx->response_buffer[buffer_pos++] = nfcv_data->block_num - 1; /* number of blocks */
|
||||
ctx->response_buffer[buffer_pos++] = nfcv_data->block_size - 1; /* block size */
|
||||
ctx->response_buffer[buffer_pos++] = nfcv_data->ic_ref; /* IC reference */
|
||||
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 15, ctx->response_flags, ctx->send_time);
|
||||
tx_rx,
|
||||
nfcv_data,
|
||||
ctx->response_buffer,
|
||||
buffer_pos,
|
||||
ctx->response_flags,
|
||||
ctx->send_time);
|
||||
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO");
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_CUST_ECHO_MODE: {
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
case NFCV_CMD_CUST_ECHO_MODE: {
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_data->echo_mode = true;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
@@ -815,7 +866,7 @@ void nfcv_emu_handle_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_CUST_ECHO_DATA: {
|
||||
case NFCV_CMD_CUST_ECHO_DATA: {
|
||||
nfcv_emu_send(
|
||||
tx_rx,
|
||||
nfcv_data,
|
||||
@@ -837,7 +888,9 @@ void nfcv_emu_handle_packet(
|
||||
}
|
||||
|
||||
if(strlen(nfcv_data->last_command) > 0) {
|
||||
#ifdef NFCV_VERBOSE
|
||||
FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,12 +912,12 @@ void nfcv_emu_sniff_packet(
|
||||
/* parse the frame data for the upcoming part 3 handling */
|
||||
ctx->flags = nfcv_data->frame[0];
|
||||
ctx->command = nfcv_data->frame[1];
|
||||
ctx->selected = (ctx->flags & RFAL_NFCV_REQ_FLAG_SELECT);
|
||||
ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) &&
|
||||
(ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
|
||||
ctx->advanced = (ctx->command >= 0xA0);
|
||||
ctx->selected = (ctx->flags & NFCV_REQ_FLAG_SELECT);
|
||||
ctx->addressed = !(ctx->flags & NFCV_REQ_FLAG_INVENTORY) &&
|
||||
(ctx->flags & NFCV_REQ_FLAG_ADDRESS);
|
||||
ctx->advanced = (ctx->command >= NFCV_CMD_ADVANCED);
|
||||
ctx->address_offset = 2 + (ctx->advanced ? 1 : 0);
|
||||
ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0);
|
||||
ctx->payload_offset = ctx->address_offset + (ctx->addressed ? NFCV_UID_LENGTH : 0);
|
||||
|
||||
char flags_string[5];
|
||||
|
||||
@@ -872,28 +925,28 @@ void nfcv_emu_sniff_packet(
|
||||
flags_string,
|
||||
5,
|
||||
"%c%c%c%d",
|
||||
(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) ?
|
||||
(ctx->flags & NFCV_REQ_FLAG_INVENTORY) ?
|
||||
'I' :
|
||||
(ctx->addressed ? 'A' : (ctx->selected ? 'S' : '*')),
|
||||
ctx->advanced ? 'X' : ' ',
|
||||
(ctx->flags & RFAL_NFCV_REQ_FLAG_DATA_RATE) ? 'h' : 'l',
|
||||
(ctx->flags & RFAL_NFCV_REQ_FLAG_SUB_CARRIER) ? 2 : 1);
|
||||
(ctx->flags & NFCV_REQ_FLAG_DATA_RATE) ? 'h' : 'l',
|
||||
(ctx->flags & NFCV_REQ_FLAG_SUB_CARRIER) ? 2 : 1);
|
||||
|
||||
switch(ctx->command) {
|
||||
case ISO15693_INVENTORY: {
|
||||
case NFCV_CMD_INVENTORY: {
|
||||
snprintf(
|
||||
nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s INVENTORY", flags_string);
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_STAYQUIET: {
|
||||
case NFCV_CMD_STAY_QUIET: {
|
||||
snprintf(
|
||||
nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s STAYQUIET", flags_string);
|
||||
nfcv_data->quiet = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_LOCKBLOCK: {
|
||||
case NFCV_CMD_LOCK_BLOCK: {
|
||||
uint8_t block = nfcv_data->frame[ctx->payload_offset];
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
@@ -904,7 +957,7 @@ void nfcv_emu_sniff_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_WRITE_DSFID: {
|
||||
case NFCV_CMD_WRITE_DSFID: {
|
||||
uint8_t id = nfcv_data->frame[ctx->payload_offset];
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
@@ -915,7 +968,7 @@ void nfcv_emu_sniff_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_WRITE_AFI: {
|
||||
case NFCV_CMD_WRITE_AFI: {
|
||||
uint8_t id = nfcv_data->frame[ctx->payload_offset];
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
@@ -926,7 +979,7 @@ void nfcv_emu_sniff_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_LOCK_DSFID: {
|
||||
case NFCV_CMD_LOCK_DSFID: {
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
sizeof(nfcv_data->last_command),
|
||||
@@ -935,30 +988,30 @@ void nfcv_emu_sniff_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_LOCK_AFI: {
|
||||
case NFCV_CMD_LOCK_AFI: {
|
||||
snprintf(
|
||||
nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s LOCK AFI", flags_string);
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_SELECT: {
|
||||
case NFCV_CMD_SELECT: {
|
||||
snprintf(
|
||||
nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s SELECT", flags_string);
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_RESET_TO_READY: {
|
||||
case NFCV_CMD_RESET_TO_READY: {
|
||||
snprintf(
|
||||
nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s RESET", flags_string);
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_READ_MULTI_BLOCK:
|
||||
case ISO15693_READBLOCK: {
|
||||
case NFCV_CMD_READ_MULTI_BLOCK:
|
||||
case NFCV_CMD_READ_BLOCK: {
|
||||
uint8_t block = nfcv_data->frame[ctx->payload_offset];
|
||||
uint8_t blocks = 1;
|
||||
|
||||
if(ctx->command == ISO15693_READ_MULTI_BLOCK) {
|
||||
if(ctx->command == NFCV_CMD_READ_MULTI_BLOCK) {
|
||||
blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1;
|
||||
}
|
||||
|
||||
@@ -973,20 +1026,20 @@ void nfcv_emu_sniff_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_WRITE_MULTI_BLOCK:
|
||||
case ISO15693_WRITEBLOCK: {
|
||||
case NFCV_CMD_WRITE_MULTI_BLOCK:
|
||||
case NFCV_CMD_WRITE_BLOCK: {
|
||||
uint8_t block = nfcv_data->frame[ctx->payload_offset];
|
||||
uint8_t blocks = 1;
|
||||
uint8_t data_pos = 1;
|
||||
|
||||
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
|
||||
if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) {
|
||||
blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1;
|
||||
data_pos++;
|
||||
}
|
||||
|
||||
uint8_t* data = &nfcv_data->frame[ctx->payload_offset + data_pos];
|
||||
|
||||
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
|
||||
if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) {
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
sizeof(nfcv_data->last_command),
|
||||
@@ -1009,7 +1062,7 @@ void nfcv_emu_sniff_packet(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_GET_SYSTEM_INFO: {
|
||||
case NFCV_CMD_GET_SYSTEM_INFO: {
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
sizeof(nfcv_data->last_command),
|
||||
@@ -1051,13 +1104,24 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
|
||||
/* everything is initialized */
|
||||
nfcv_data->ready = true;
|
||||
|
||||
/* ensure the GPIO is already in unmodulated state */
|
||||
furi_hal_gpio_init(&gpio_spi_r_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||
furi_hal_gpio_write(&gpio_spi_r_mosi, GPIO_LEVEL_UNMODULATED);
|
||||
|
||||
rfal_platform_spi_acquire();
|
||||
/* configure for transparent and passive mode */
|
||||
/* stop operation to configure for transparent and passive mode */
|
||||
st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
|
||||
/* set enable, rx_enable and field detector enable */
|
||||
st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0xC3);
|
||||
/* target mode: ISO14443 passive mode */
|
||||
st25r3916WriteRegister(ST25R3916_REG_MODE, 0x88);
|
||||
st25r3916WriteRegister(
|
||||
ST25R3916_REG_OP_CONTROL,
|
||||
ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en |
|
||||
ST25R3916_REG_OP_CONTROL_en_fd_auto_efd);
|
||||
/* explicitely set the modulation resistor in case system config changes for some reason */
|
||||
st25r3916WriteRegister(
|
||||
ST25R3916_REG_PT_MOD,
|
||||
(0 << ST25R3916_REG_PT_MOD_ptm_res_shift) | (15 << ST25R3916_REG_PT_MOD_pt_res_shift));
|
||||
/* target mode: target, other fields do not have any effect as we use transparent mode */
|
||||
st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ);
|
||||
/* let us modulate the field using MOSI, read ASK modulation using IRQ */
|
||||
st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE);
|
||||
|
||||
@@ -1112,11 +1176,12 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
|
||||
}
|
||||
|
||||
/* allocate a 512 edge buffer, more than enough */
|
||||
nfcv_data->emu_air.reader_signal = pulse_reader_alloc(&gpio_nfc_irq_rfid_pull, 512);
|
||||
nfcv_data->emu_air.reader_signal =
|
||||
pulse_reader_alloc(&gpio_nfc_irq_rfid_pull, NFCV_PULSE_BUFFER);
|
||||
/* timebase shall be 1 ns */
|
||||
pulse_reader_set_timebase(nfcv_data->emu_air.reader_signal, PulseReaderUnitNanosecond);
|
||||
/* and configure to already calculate the number of bits */
|
||||
pulse_reader_set_bittime(nfcv_data->emu_air.reader_signal, PULSE_DURATION_NS);
|
||||
pulse_reader_set_bittime(nfcv_data->emu_air.reader_signal, NFCV_PULSE_DURATION_NS);
|
||||
/* this IO is fed into the µC via a diode, so we need a pulldown */
|
||||
pulse_reader_set_pull(nfcv_data->emu_air.reader_signal, GpioPullDown);
|
||||
|
||||
@@ -1128,7 +1193,6 @@ void nfcv_emu_deinit(NfcVData* nfcv_data) {
|
||||
furi_assert(nfcv_data);
|
||||
|
||||
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
|
||||
rfal_platform_spi_release();
|
||||
nfcv_emu_free(nfcv_data);
|
||||
|
||||
if(nfcv_data->emu_protocol_ctx) {
|
||||
@@ -1139,6 +1203,7 @@ void nfcv_emu_deinit(NfcVData* nfcv_data) {
|
||||
/* set registers back to how we found them */
|
||||
st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0x00);
|
||||
st25r3916WriteRegister(ST25R3916_REG_MODE, 0x08);
|
||||
rfal_platform_spi_release();
|
||||
}
|
||||
|
||||
bool nfcv_emu_loop(
|
||||
@@ -1157,8 +1222,6 @@ bool nfcv_emu_loop(
|
||||
uint32_t byte_value = 0;
|
||||
uint32_t bits_received = 0;
|
||||
uint32_t timeout = timeout_ms * 1000;
|
||||
uint32_t sof_timestamp = 0;
|
||||
uint32_t eof_timestamp = 0;
|
||||
bool wait_for_pulse = false;
|
||||
|
||||
if(!nfcv_data->ready) {
|
||||
@@ -1200,7 +1263,6 @@ bool nfcv_emu_loop(
|
||||
frame_state = NFCV_FRAME_STATE_SOF2;
|
||||
} else {
|
||||
frame_state = NFCV_FRAME_STATE_SOF1;
|
||||
sof_timestamp = timestamp;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1234,7 +1296,6 @@ bool nfcv_emu_loop(
|
||||
break;
|
||||
} else if(periods == 2) {
|
||||
frame_state = NFCV_FRAME_STATE_EOF;
|
||||
eof_timestamp = timestamp;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1275,7 +1336,6 @@ bool nfcv_emu_loop(
|
||||
periods_previous = 0;
|
||||
} else if(periods == 2) {
|
||||
frame_state = NFCV_FRAME_STATE_EOF;
|
||||
eof_timestamp = timestamp;
|
||||
break;
|
||||
} else {
|
||||
frame_state = NFCV_FRAME_STATE_RESET;
|
||||
@@ -1310,27 +1370,13 @@ bool nfcv_emu_loop(
|
||||
}
|
||||
nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data);
|
||||
|
||||
/* determine readers fc by analyzing transmission duration */
|
||||
uint32_t duration = eof_timestamp - sof_timestamp;
|
||||
float fc_1024 = (4.0f * duration) / (4 * (frame_pos * 4 + 1) + 1);
|
||||
/* it should be 1024/fc in 64MHz ticks */
|
||||
float fact = fc_1024 / ((1000000.0f * 64.0f * 1024.0f) / NFCV_FC);
|
||||
FURI_LOG_D(TAG, "1024/fc: %f -> %f %%", (double)fc_1024, (double)(fact * 100));
|
||||
#if 0
|
||||
if(fact > 0.99f && fact < 1.01f) {
|
||||
static float avg_err = 0.0f;
|
||||
|
||||
avg_err = (avg_err * 15.0f + (fact - 1.0f)) / 16.0f;
|
||||
FURI_LOG_D(TAG, " ==> set %f %%", (double)((1.0f + avg_err) * 100));
|
||||
digital_sequence_timebase_correction(nfcv_data->emu_air.nfcv_signal, 1.0f + avg_err);
|
||||
}
|
||||
#endif
|
||||
|
||||
pulse_reader_start(nfcv_data->emu_air.reader_signal);
|
||||
ret = true;
|
||||
} else {
|
||||
if(frame_state != NFCV_FRAME_STATE_SOF1) {
|
||||
#ifdef NFCV_VERBOSE
|
||||
FURI_LOG_T(TAG, "leaving while in state: %lu", frame_state);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,13 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* true: modulating releases load, false: modulating adds load resistor to field coil */
|
||||
#define NFCV_LOAD_MODULATION_POLARITY (false)
|
||||
|
||||
#define NFCV_FC (13560000.0f / 0.9998f) /* MHz */
|
||||
#define NFCV_RESP_SUBC1_PULSE_32 (1.0f / (NFCV_FC / 32) / 2.0f) /* 1.1799 µs */
|
||||
#define NFCV_RESP_SUBC1_UNMOD_256 (256.0f / NFCV_FC) /* 18.8791 µs */
|
||||
|
||||
#define PULSE_DURATION_NS (128.0f * 1000000000.0f / NFCV_FC)
|
||||
|
||||
#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f)
|
||||
#define DIGITAL_SIGNAL_UNIT_US (100000.0f)
|
||||
#define NFCV_PULSE_DURATION_NS (128.0f * 1000000000.0f / NFCV_FC)
|
||||
|
||||
/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum number of blocks is defined as 256 */
|
||||
#define NFCV_BLOCKS_MAX 256
|
||||
@@ -30,15 +29,20 @@ extern "C" {
|
||||
/* ISO/IEC 15693-3:2019(E) 7.1b: standard allows up to 8192, the maxium frame length that we are expected to receive/send is less */
|
||||
#define NFCV_FRAMESIZE_MAX (1 + NFCV_MEMSIZE_MAX + NFCV_BLOCKS_MAX)
|
||||
|
||||
/* maximum string length for log messages */
|
||||
#define NFCV_LOG_STR_LEN 128
|
||||
/* maximum of pulses to be buffered by pulse reader */
|
||||
#define NFCV_PULSE_BUFFER 512
|
||||
|
||||
// #define NFCV_DIAGNOSTIC_DUMPS
|
||||
// #define NFCV_DIAGNOSTIC_DUMP_SIZE 128
|
||||
//#define NFCV_DIAGNOSTIC_DUMPS
|
||||
//#define NFCV_DIAGNOSTIC_DUMP_SIZE 256
|
||||
//#define NFCV_VERBOSE
|
||||
|
||||
/* helpers to calculate the send time based on DWT->CYCCNT */
|
||||
#define NFCV_FDT_USEC(usec) (usec * 64)
|
||||
#define NFCV_FDT_USEC(usec) ((usec)*64)
|
||||
#define NFCV_FDT_FC(ticks) ((ticks)*6400 / 1356)
|
||||
|
||||
/* state machine when receiving frame bits */
|
||||
#define NFCV_FRAME_STATE_SOF1 0
|
||||
#define NFCV_FRAME_STATE_SOF2 1
|
||||
#define NFCV_FRAME_STATE_CODING_4 2
|
||||
@@ -56,37 +60,83 @@ extern "C" {
|
||||
#define NFCV_SIG_LOW_BIT1 6
|
||||
#define NFCV_SIG_LOW_EOF 7
|
||||
|
||||
/* various constants */
|
||||
#define NFCV_COMMAND_RETRIES 5
|
||||
#define NFCV_UID_LENGTH 8
|
||||
|
||||
/* ISO15693 protocol flags */
|
||||
typedef enum {
|
||||
/* ISO15693 protocol flags when INVENTORY is NOT set */
|
||||
NFCV_REQ_FLAG_SUB_CARRIER = (1 << 0),
|
||||
NFCV_REQ_FLAG_DATA_RATE = (1 << 1),
|
||||
NFCV_REQ_FLAG_INVENTORY = (1 << 2),
|
||||
NFCV_REQ_FLAG_PROTOCOL_EXT = (1 << 3),
|
||||
NFCV_REQ_FLAG_SELECT = (1 << 4),
|
||||
NFCV_REQ_FLAG_ADDRESS = (1 << 5),
|
||||
NFCV_REQ_FLAG_OPTION = (1 << 6),
|
||||
/* ISO15693 protocol flags when INVENTORY flag is set */
|
||||
NFCV_REQ_FLAG_AFI = (1 << 4),
|
||||
NFCV_REQ_FLAG_NB_SLOTS = (1 << 5)
|
||||
} NfcVRequestFlags;
|
||||
|
||||
/* ISO15693 protocol flags */
|
||||
typedef enum {
|
||||
NFCV_RES_FLAG_ERROR = (1 << 0),
|
||||
NFCV_RES_FLAG_VALIDITY = (1 << 1),
|
||||
NFCV_RES_FLAG_FINAL = (1 << 2),
|
||||
NFCV_RES_FLAG_PROTOCOL_EXT = (1 << 3),
|
||||
NFCV_RES_FLAG_SEC_LEN1 = (1 << 4),
|
||||
NFCV_RES_FLAG_SEC_LEN2 = (1 << 5),
|
||||
NFCV_RES_FLAG_WAIT_EXT = (1 << 6),
|
||||
} NfcVRsponseFlags;
|
||||
|
||||
/* flags for SYSINFO response */
|
||||
typedef enum {
|
||||
NFCV_SYSINFO_FLAG_DSFID = (1 << 0),
|
||||
NFCV_SYSINFO_FLAG_AFI = (1 << 1),
|
||||
NFCV_SYSINFO_FLAG_MEMSIZE = (1 << 2),
|
||||
NFCV_SYSINFO_FLAG_ICREF = (1 << 3)
|
||||
} NfcVSysinfoFlags;
|
||||
|
||||
/* ISO15693 command codes */
|
||||
#define ISO15693_INVENTORY 0x01
|
||||
#define ISO15693_STAYQUIET 0x02
|
||||
#define ISO15693_READBLOCK 0x20
|
||||
#define ISO15693_WRITEBLOCK 0x21
|
||||
#define ISO15693_LOCKBLOCK 0x22
|
||||
#define ISO15693_READ_MULTI_BLOCK 0x23
|
||||
#define ISO15693_WRITE_MULTI_BLOCK 0x24
|
||||
#define ISO15693_SELECT 0x25
|
||||
#define ISO15693_RESET_TO_READY 0x26
|
||||
#define ISO15693_WRITE_AFI 0x27
|
||||
#define ISO15693_LOCK_AFI 0x28
|
||||
#define ISO15693_WRITE_DSFID 0x29
|
||||
#define ISO15693_LOCK_DSFID 0x2A
|
||||
#define ISO15693_GET_SYSTEM_INFO 0x2B
|
||||
#define ISO15693_READ_MULTI_SECSTATUS 0x2C
|
||||
typedef enum {
|
||||
/* mandatory command codes */
|
||||
NFCV_CMD_INVENTORY = 0x01,
|
||||
NFCV_CMD_STAY_QUIET = 0x02,
|
||||
/* optional command codes */
|
||||
NFCV_CMD_READ_BLOCK = 0x20,
|
||||
NFCV_CMD_WRITE_BLOCK = 0x21,
|
||||
NFCV_CMD_LOCK_BLOCK = 0x22,
|
||||
NFCV_CMD_READ_MULTI_BLOCK = 0x23,
|
||||
NFCV_CMD_WRITE_MULTI_BLOCK = 0x24,
|
||||
NFCV_CMD_SELECT = 0x25,
|
||||
NFCV_CMD_RESET_TO_READY = 0x26,
|
||||
NFCV_CMD_WRITE_AFI = 0x27,
|
||||
NFCV_CMD_LOCK_AFI = 0x28,
|
||||
NFCV_CMD_WRITE_DSFID = 0x29,
|
||||
NFCV_CMD_LOCK_DSFID = 0x2A,
|
||||
NFCV_CMD_GET_SYSTEM_INFO = 0x2B,
|
||||
NFCV_CMD_READ_MULTI_SECSTATUS = 0x2C,
|
||||
/* advanced command codes */
|
||||
NFCV_CMD_ADVANCED = 0xA0,
|
||||
/* flipper zero custom command codes */
|
||||
NFCV_CMD_CUST_ECHO_MODE = 0xDE,
|
||||
NFCV_CMD_CUST_ECHO_DATA = 0xDF
|
||||
} NfcVCommands;
|
||||
|
||||
#define ISO15693_CUST_ECHO_MODE 0xDE
|
||||
#define ISO15693_CUST_ECHO_DATA 0xDF
|
||||
|
||||
/* ISO15693 RESPONSE ERROR CODES */
|
||||
#define ISO15693_NOERROR 0x00
|
||||
#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported
|
||||
#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error)
|
||||
#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported
|
||||
#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error
|
||||
#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10
|
||||
#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again
|
||||
#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed
|
||||
#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful
|
||||
#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful
|
||||
/* ISO15693 Response error codes */
|
||||
typedef enum {
|
||||
NFCV_NOERROR = 0x00,
|
||||
NFCV_ERROR_CMD_NOT_SUP = 0x01, // Command not supported
|
||||
NFCV_ERROR_CMD_NOT_REC = 0x02, // Command not recognized (eg. parameter error)
|
||||
NFCV_ERROR_CMD_OPTION = 0x03, // Command option not supported
|
||||
NFCV_ERROR_GENERIC = 0x0F, // No additional Info about this error
|
||||
NFCV_ERROR_BLOCK_UNAVAILABLE = 0x10,
|
||||
NFCV_ERROR_BLOCK_LOCKED_ALREADY = 0x11, // cannot lock again
|
||||
NFCV_ERROR_BLOCK_LOCKED = 0x12, // cannot be changed
|
||||
NFCV_ERROR_BLOCK_WRITE = 0x13, // Writing was unsuccessful
|
||||
NFCV_ERROR_BLOCL_WRITELOCK = 0x14 // Locking was unsuccessful
|
||||
} NfcVErrorcodes;
|
||||
|
||||
typedef enum {
|
||||
NfcVLockBitDsfid = 1,
|
||||
|
||||
@@ -59,9 +59,9 @@ ReturnCode slix_get_random(NfcVData* data) {
|
||||
uint8_t rxBuf[32];
|
||||
|
||||
ReturnCode ret = rfalNfcvPollerTransceiveReq(
|
||||
ISO15693_CMD_NXP_GET_RANDOM_NUMBER,
|
||||
NFCV_CMD_NXP_GET_RANDOM_NUMBER,
|
||||
RFAL_NFCV_REQ_FLAG_DEFAULT,
|
||||
ISO15693_MANUFACTURER_NXP,
|
||||
NFCV_MANUFACTURER_NXP,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
@@ -124,9 +124,9 @@ ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) {
|
||||
}
|
||||
|
||||
ReturnCode ret = rfalNfcvPollerTransceiveReq(
|
||||
ISO15693_CMD_NXP_SET_PASSWORD,
|
||||
NFCV_CMD_NXP_SET_PASSWORD,
|
||||
RFAL_NFCV_REQ_FLAG_DATA_RATE,
|
||||
ISO15693_MANUFACTURER_NXP,
|
||||
NFCV_MANUFACTURER_NXP,
|
||||
NULL,
|
||||
cmd_set_pass,
|
||||
sizeof(cmd_set_pass),
|
||||
@@ -150,8 +150,8 @@ bool slix_generic_protocol_filter(
|
||||
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
|
||||
NfcVSlixData* slix = &nfcv_data->sub_data.slix;
|
||||
|
||||
if(slix->privacy && ctx->command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER &&
|
||||
ctx->command != ISO15693_CMD_NXP_SET_PASSWORD) {
|
||||
if(slix->privacy && ctx->command != NFCV_CMD_NXP_GET_RANDOM_NUMBER &&
|
||||
ctx->command != NFCV_CMD_NXP_SET_PASSWORD) {
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
sizeof(nfcv_data->last_command),
|
||||
@@ -164,11 +164,11 @@ bool slix_generic_protocol_filter(
|
||||
bool handled = false;
|
||||
|
||||
switch(ctx->command) {
|
||||
case ISO15693_CMD_NXP_GET_RANDOM_NUMBER: {
|
||||
case NFCV_CMD_NXP_GET_RANDOM_NUMBER: {
|
||||
slix->rand[0] = furi_hal_random_get();
|
||||
slix->rand[1] = furi_hal_random_get();
|
||||
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
ctx->response_buffer[1] = slix->rand[1];
|
||||
ctx->response_buffer[2] = slix->rand[0];
|
||||
|
||||
@@ -185,7 +185,7 @@ bool slix_generic_protocol_filter(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_CMD_NXP_SET_PASSWORD: {
|
||||
case NFCV_CMD_NXP_SET_PASSWORD: {
|
||||
uint8_t password_id = nfcv_data->frame[ctx->payload_offset];
|
||||
|
||||
if(!(password_id & password_supported)) {
|
||||
@@ -246,7 +246,7 @@ bool slix_generic_protocol_filter(
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
snprintf(
|
||||
@@ -268,15 +268,15 @@ bool slix_generic_protocol_filter(
|
||||
break;
|
||||
}
|
||||
|
||||
case ISO15693_CMD_NXP_ENABLE_PRIVACY: {
|
||||
ctx->response_buffer[0] = ISO15693_NOERROR;
|
||||
case NFCV_CMD_NXP_ENABLE_PRIVACY: {
|
||||
ctx->response_buffer[0] = NFCV_NOERROR;
|
||||
|
||||
nfcv_emu_send(
|
||||
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
|
||||
snprintf(
|
||||
nfcv_data->last_command,
|
||||
sizeof(nfcv_data->last_command),
|
||||
"ISO15693_CMD_NXP_ENABLE_PRIVACY");
|
||||
"NFCV_CMD_NXP_ENABLE_PRIVACY");
|
||||
|
||||
slix->privacy = true;
|
||||
handled = true;
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
#include "nfc_util.h"
|
||||
#include <furi_hal_nfc.h>
|
||||
|
||||
#define ISO15693_MANUFACTURER_NXP 0x04
|
||||
#define NFCV_MANUFACTURER_NXP 0x04
|
||||
|
||||
/* ISO15693-3 CUSTOM NXP COMMANDS */
|
||||
#define ISO15693_CMD_NXP_SET_EAS 0xA2
|
||||
#define ISO15693_CMD_NXP_RESET_EAS 0xA3
|
||||
#define ISO15693_CMD_NXP_LOCK_EAS 0xA4
|
||||
#define ISO15693_CMD_NXP_EAS_ALARM 0xA5
|
||||
#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6
|
||||
#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7
|
||||
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0
|
||||
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1
|
||||
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
|
||||
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
|
||||
#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4
|
||||
#define ISO15693_CMD_NXP_DESTROY 0xB9
|
||||
#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA
|
||||
#define NFCV_CMD_NXP_SET_EAS 0xA2
|
||||
#define NFCV_CMD_NXP_RESET_EAS 0xA3
|
||||
#define NFCV_CMD_NXP_LOCK_EAS 0xA4
|
||||
#define NFCV_CMD_NXP_EAS_ALARM 0xA5
|
||||
#define NFCV_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6
|
||||
#define NFCV_CMD_NXP_WRITE_EAS_ID 0xA7
|
||||
#define NFCV_CMD_NXP_INVENTORY_PAGE_READ 0xB0
|
||||
#define NFCV_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1
|
||||
#define NFCV_CMD_NXP_GET_RANDOM_NUMBER 0xB2
|
||||
#define NFCV_CMD_NXP_SET_PASSWORD 0xB3
|
||||
#define NFCV_CMD_NXP_WRITE_PASSWORD 0xB4
|
||||
#define NFCV_CMD_NXP_DESTROY 0xB9
|
||||
#define NFCV_CMD_NXP_ENABLE_PRIVACY 0xBA
|
||||
|
||||
/* available passwords */
|
||||
#define SLIX_PASS_READ 0x01
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "../blocks/generic.h"
|
||||
#include "../blocks/math.h"
|
||||
|
||||
#include "../blocks/custom_btn.h"
|
||||
|
||||
#define TAG "SubGhzProtocoCameAtomo"
|
||||
|
||||
static const SubGhzBlockConst subghz_protocol_came_atomo_const = {
|
||||
@@ -71,6 +73,13 @@ const SubGhzProtocol subghz_protocol_came_atomo = {
|
||||
|
||||
static void subghz_protocol_came_atomo_remote_controller(SubGhzBlockGeneric* instance);
|
||||
|
||||
/**
|
||||
* Defines the button value for the current btn_id
|
||||
* Basic set | 0x0 | 0x2 | 0x4 | 0x6 |
|
||||
* @return Button code
|
||||
*/
|
||||
static uint8_t subghz_protocol_came_atomo_get_btn_code();
|
||||
|
||||
void* subghz_protocol_encoder_came_atomo_alloc(SubGhzEnvironment* environment) {
|
||||
UNUSED(environment);
|
||||
SubGhzProtocolEncoderCameAtomo* instance = malloc(sizeof(SubGhzProtocolEncoderCameAtomo));
|
||||
@@ -120,12 +129,53 @@ static LevelDuration
|
||||
return level_duration_make(data.level, data.duration);
|
||||
}
|
||||
|
||||
bool subghz_protocol_came_atomo_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolEncoderCameAtomo* instance = context;
|
||||
instance->generic.btn = 0x1;
|
||||
instance->generic.serial = serial;
|
||||
instance->generic.cnt = cnt;
|
||||
instance->generic.cnt_2 = 0x7e;
|
||||
instance->generic.data_count_bit = 62;
|
||||
instance->generic.data_2 =
|
||||
((uint64_t)0x7e << 56 | (uint64_t)cnt << 40 | (uint64_t)serial << 8);
|
||||
|
||||
uint8_t pack[8] = {};
|
||||
|
||||
pack[0] = (instance->generic.cnt_2);
|
||||
pack[1] = (instance->generic.cnt >> 8);
|
||||
pack[2] = (instance->generic.cnt & 0xFF);
|
||||
pack[3] = ((instance->generic.data_2 >> 32) & 0xFF);
|
||||
pack[4] = ((instance->generic.data_2 >> 24) & 0xFF);
|
||||
pack[5] = ((instance->generic.data_2 >> 16) & 0xFF);
|
||||
pack[6] = ((instance->generic.data_2 >> 8) & 0xFF);
|
||||
pack[7] = (instance->generic.data_2 & 0xFF);
|
||||
|
||||
atomo_encrypt(pack);
|
||||
uint32_t hi = pack[0] << 24 | pack[1] << 16 | pack[2] << 8 | pack[3];
|
||||
uint32_t lo = pack[4] << 24 | pack[5] << 16 | pack[6] << 8 | pack[7];
|
||||
instance->generic.data = (uint64_t)hi << 32 | lo;
|
||||
|
||||
instance->generic.data ^= 0xFFFFFFFFFFFFFFFF;
|
||||
instance->generic.data >>= 4;
|
||||
instance->generic.data &= 0xFFFFFFFFFFFFFFF;
|
||||
|
||||
return SubGhzProtocolStatusOk ==
|
||||
subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generating an upload from data.
|
||||
* @param instance Pointer to a SubGhzProtocolEncoderCameAtomo instance
|
||||
*/
|
||||
static void
|
||||
subghz_protocol_encoder_came_atomo_get_upload(SubGhzProtocolEncoderCameAtomo* instance) {
|
||||
static void subghz_protocol_encoder_came_atomo_get_upload(
|
||||
SubGhzProtocolEncoderCameAtomo* instance,
|
||||
uint8_t btn) {
|
||||
furi_assert(instance);
|
||||
size_t index = 0;
|
||||
|
||||
@@ -145,6 +195,23 @@ static void
|
||||
instance->generic.cnt = 0;
|
||||
}
|
||||
|
||||
// Save original button for later use
|
||||
if(subghz_custom_btn_get_original() == 0) {
|
||||
subghz_custom_btn_set_original(btn);
|
||||
}
|
||||
|
||||
btn = subghz_protocol_came_atomo_get_btn_code();
|
||||
|
||||
if(btn == 0x1) {
|
||||
btn = 0x0;
|
||||
} else if(btn == 0x2) {
|
||||
btn = 0x2;
|
||||
} else if(btn == 0x3) {
|
||||
btn = 0x4;
|
||||
} else if(btn == 0x4) {
|
||||
btn = 0x6;
|
||||
}
|
||||
|
||||
//Send header
|
||||
instance->encoder.upload[index++] =
|
||||
level_duration_make(true, (uint32_t)subghz_protocol_came_atomo_const.te_long * 15);
|
||||
@@ -159,7 +226,7 @@ static void
|
||||
pack[4] = ((instance->generic.data_2 >> 24) & 0xFF);
|
||||
pack[5] = ((instance->generic.data_2 >> 16) & 0xFF);
|
||||
pack[6] = ((instance->generic.data_2 >> 8) & 0xFF);
|
||||
pack[7] = (instance->generic.data_2 & 0xFF);
|
||||
pack[7] = (btn << 4);
|
||||
|
||||
if(pack[0] == 0x7F) {
|
||||
pack[0] = 0;
|
||||
@@ -211,7 +278,7 @@ static void
|
||||
pack[4] = ((instance->generic.data_2 >> 24) & 0xFF);
|
||||
pack[5] = ((instance->generic.data_2 >> 16) & 0xFF);
|
||||
pack[6] = ((instance->generic.data_2 >> 8) & 0xFF);
|
||||
pack[7] = (instance->generic.data_2 & 0xFF);
|
||||
pack[7] = (btn << 4);
|
||||
|
||||
atomo_encrypt(pack);
|
||||
uint32_t hi = pack[0] << 24 | pack[1] << 16 | pack[2] << 8 | pack[3];
|
||||
@@ -240,7 +307,7 @@ SubGhzProtocolStatus
|
||||
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
|
||||
|
||||
subghz_protocol_came_atomo_remote_controller(&instance->generic);
|
||||
subghz_protocol_encoder_came_atomo_get_upload(instance);
|
||||
subghz_protocol_encoder_came_atomo_get_upload(instance, instance->generic.btn);
|
||||
|
||||
if(!flipper_format_rewind(flipper_format)) {
|
||||
FURI_LOG_E(TAG, "Rewind error");
|
||||
@@ -487,20 +554,23 @@ static void subghz_protocol_came_atomo_remote_controller(SubGhzBlockGeneric* ins
|
||||
uint8_t btn_decode = (pack[7] >> 4);
|
||||
if(btn_decode == 0x0) {
|
||||
instance->btn = 0x1;
|
||||
}
|
||||
if(btn_decode == 0x2) {
|
||||
} else if(btn_decode == 0x2) {
|
||||
instance->btn = 0x2;
|
||||
}
|
||||
if(btn_decode == 0x4) {
|
||||
} else if(btn_decode == 0x4) {
|
||||
instance->btn = 0x3;
|
||||
}
|
||||
if(btn_decode == 0x6) {
|
||||
} else if(btn_decode == 0x6) {
|
||||
instance->btn = 0x4;
|
||||
}
|
||||
|
||||
uint32_t hi = pack[0] << 24 | pack[1] << 16 | pack[2] << 8 | pack[3];
|
||||
uint32_t lo = pack[4] << 24 | pack[5] << 16 | pack[6] << 8 | pack[7];
|
||||
instance->data_2 = (uint64_t)hi << 32 | lo;
|
||||
|
||||
// Save original button for later use
|
||||
if(subghz_custom_btn_get_original() == 0) {
|
||||
subghz_custom_btn_set_original(instance->btn);
|
||||
}
|
||||
subghz_custom_btn_set_max(3);
|
||||
}
|
||||
|
||||
void atomo_encrypt(uint8_t* buff) {
|
||||
@@ -544,6 +614,74 @@ void atomo_decrypt(uint8_t* buff) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t subghz_protocol_came_atomo_get_btn_code() {
|
||||
uint8_t custom_btn_id = subghz_custom_btn_get();
|
||||
uint8_t original_btn_code = subghz_custom_btn_get_original();
|
||||
uint8_t btn = original_btn_code;
|
||||
|
||||
// Set custom button
|
||||
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
|
||||
// Restore original button code
|
||||
btn = original_btn_code;
|
||||
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
|
||||
switch(original_btn_code) {
|
||||
case 0x1:
|
||||
btn = 0x2;
|
||||
break;
|
||||
case 0x2:
|
||||
btn = 0x1;
|
||||
break;
|
||||
case 0x3:
|
||||
btn = 0x1;
|
||||
break;
|
||||
case 0x4:
|
||||
btn = 0x1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
|
||||
switch(original_btn_code) {
|
||||
case 0x1:
|
||||
btn = 0x3;
|
||||
break;
|
||||
case 0x2:
|
||||
btn = 0x3;
|
||||
break;
|
||||
case 0x3:
|
||||
btn = 0x2;
|
||||
break;
|
||||
case 0x4:
|
||||
btn = 0x2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
|
||||
switch(original_btn_code) {
|
||||
case 0x1:
|
||||
btn = 0x4;
|
||||
break;
|
||||
case 0x2:
|
||||
btn = 0x4;
|
||||
break;
|
||||
case 0x3:
|
||||
btn = 0x4;
|
||||
break;
|
||||
case 0x4:
|
||||
btn = 0x3;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderCameAtomo* instance = context;
|
||||
@@ -581,7 +719,7 @@ void subghz_protocol_decoder_came_atomo_get_string(void* context, FuriString* ou
|
||||
output,
|
||||
"%s %db\r\n"
|
||||
"Key:0x%08lX%08lX\r\n"
|
||||
"Sn:0x%08lX Btn:0x%01X\r\n"
|
||||
"Sn:0x%08lX Btn:%01X\r\n"
|
||||
"Pcl_Cnt:0x%04lX\r\n"
|
||||
"Btn_Cnt:0x%02X",
|
||||
|
||||
|
||||
@@ -14,6 +14,22 @@ void atomo_decrypt(uint8_t* buff);
|
||||
|
||||
void atomo_encrypt(uint8_t* buff);
|
||||
|
||||
/**
|
||||
* Key generation from simple data.
|
||||
* @param context Pointer to a SubGhzProtocolEncoderCameAtomo instance
|
||||
* @param flipper_format Pointer to a FlipperFormat instance
|
||||
* @param serial Serial number, 24 bit
|
||||
* @param cnt Counter value, 16 bit
|
||||
* @param preset Modulation, SubGhzRadioPreset
|
||||
* @return true On success
|
||||
*/
|
||||
bool subghz_protocol_came_atomo_create_data(
|
||||
void* context,
|
||||
FlipperFormat* flipper_format,
|
||||
uint32_t serial,
|
||||
uint16_t cnt,
|
||||
SubGhzRadioPreset* preset);
|
||||
|
||||
/**
|
||||
* Allocate SubGhzProtocolEncoderCameAtomo.
|
||||
* @param environment Pointer to a SubGhzEnvironment instance
|
||||
|
||||
@@ -308,7 +308,7 @@ void subghz_protocol_decoder_dooya_feed(void* context, bool level, uint32_t dura
|
||||
* Analysis of received data
|
||||
* @param instance Pointer to a SubGhzBlockGeneric* instance
|
||||
*/
|
||||
static void subghz_protocol_somfy_telis_check_remote_controller(SubGhzBlockGeneric* instance) {
|
||||
static void subghz_protocol_dooya_check_remote_controller(SubGhzBlockGeneric* instance) {
|
||||
/*
|
||||
* serial s/m ch key
|
||||
* long press down X * E1DC030533, 40b 111000011101110000000011 0000 0101 0011 0011
|
||||
@@ -416,7 +416,7 @@ void subghz_protocol_decoder_dooya_get_string(void* context, FuriString* output)
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderDooya* instance = context;
|
||||
|
||||
subghz_protocol_somfy_telis_check_remote_controller(&instance->generic);
|
||||
subghz_protocol_dooya_check_remote_controller(&instance->generic);
|
||||
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
|
||||
Reference in New Issue
Block a user