mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-13 13:48:35 -07:00
Added UHF RFID app
This commit is contained in:
17
applications/external/uhf_rfid/application.fam
vendored
Normal file
17
applications/external/uhf_rfid/application.fam
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
App(
|
||||||
|
appid="uhf_rfid",
|
||||||
|
name="[YRM100]UHF RFID",
|
||||||
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
|
targets=["f7"],
|
||||||
|
entry_point="uhf_app_main",
|
||||||
|
requires=[
|
||||||
|
"storage",
|
||||||
|
"gui",
|
||||||
|
],
|
||||||
|
stack_size=8 * 1024,
|
||||||
|
order=30,
|
||||||
|
fap_icon="icons/uhf_10px.png",
|
||||||
|
fap_category="GPIO",
|
||||||
|
fap_icon_assets="icons",
|
||||||
|
fap_icon_assets_symbol="uhf_rfid",
|
||||||
|
)
|
||||||
BIN
applications/external/uhf_rfid/icons/DolphinMafia_115x62.png
vendored
Normal file
BIN
applications/external/uhf_rfid/icons/DolphinMafia_115x62.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
applications/external/uhf_rfid/icons/DolphinNice_96x59.png
vendored
Normal file
BIN
applications/external/uhf_rfid/icons/DolphinNice_96x59.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
applications/external/uhf_rfid/icons/Nfc_10px.png
vendored
Normal file
BIN
applications/external/uhf_rfid/icons/Nfc_10px.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 304 B |
BIN
applications/external/uhf_rfid/icons/RFIDDolphinReceive_97x61.png
vendored
Normal file
BIN
applications/external/uhf_rfid/icons/RFIDDolphinReceive_97x61.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
applications/external/uhf_rfid/icons/RFIDDolphinSend_97x61.png
vendored
Normal file
BIN
applications/external/uhf_rfid/icons/RFIDDolphinSend_97x61.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
applications/external/uhf_rfid/icons/uhf_10px.png
vendored
Normal file
BIN
applications/external/uhf_rfid/icons/uhf_10px.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 148 B |
30
applications/external/uhf_rfid/scenes/uhf_scene.c
vendored
Normal file
30
applications/external/uhf_rfid/scenes/uhf_scene.c
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include "uhf_scene.h"
|
||||||
|
|
||||||
|
// Generate scene on_enter handlers array
|
||||||
|
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||||
|
void (*const uhf_on_enter_handlers[])(void*) = {
|
||||||
|
#include "uhf_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 uhf_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||||
|
#include "uhf_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 uhf_on_exit_handlers[])(void* context) = {
|
||||||
|
#include "uhf_scene_config.h"
|
||||||
|
};
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Initialize scene handlers configuration structure
|
||||||
|
const SceneManagerHandlers uhf_scene_handlers = {
|
||||||
|
.on_enter_handlers = uhf_on_enter_handlers,
|
||||||
|
.on_event_handlers = uhf_on_event_handlers,
|
||||||
|
.on_exit_handlers = uhf_on_exit_handlers,
|
||||||
|
.scene_num = UHFSceneNum,
|
||||||
|
};
|
||||||
29
applications/external/uhf_rfid/scenes/uhf_scene.h
vendored
Normal file
29
applications/external/uhf_rfid/scenes/uhf_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) UHFScene##id,
|
||||||
|
typedef enum {
|
||||||
|
#include "uhf_scene_config.h"
|
||||||
|
UHFSceneNum,
|
||||||
|
} UHFScene;
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
extern const SceneManagerHandlers uhf_scene_handlers;
|
||||||
|
|
||||||
|
// Generate scene on_enter handlers declaration
|
||||||
|
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||||
|
#include "uhf_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 "uhf_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 "uhf_scene_config.h"
|
||||||
|
#undef ADD_SCENE
|
||||||
18
applications/external/uhf_rfid/scenes/uhf_scene_config.h
vendored
Normal file
18
applications/external/uhf_rfid/scenes/uhf_scene_config.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
ADD_SCENE(uhf, verify, Verify)
|
||||||
|
ADD_SCENE(uhf, start, Start)
|
||||||
|
ADD_SCENE(uhf, read_tag, ReadTag)
|
||||||
|
ADD_SCENE(uhf, read_tag_success, ReadTagSuccess)
|
||||||
|
ADD_SCENE(uhf, tag_menu, TagMenu)
|
||||||
|
ADD_SCENE(uhf, save_name, SaveName)
|
||||||
|
ADD_SCENE(uhf, save_success, SaveSuccess)
|
||||||
|
ADD_SCENE(uhf, saved_menu, SavedMenu)
|
||||||
|
ADD_SCENE(uhf, file_select, FileSelect)
|
||||||
|
ADD_SCENE(uhf, device_info, DeviceInfo)
|
||||||
|
ADD_SCENE(uhf, delete, Delete)
|
||||||
|
ADD_SCENE(uhf, delete_success, DeleteSuccess)
|
||||||
|
ADD_SCENE(uhf, write_tag, WriteTag)
|
||||||
|
ADD_SCENE(uhf, write_tag_success, WriteTagSuccess)
|
||||||
|
ADD_SCENE(uhf, settings, Settings)
|
||||||
|
// ADD_SCENE(uhf, read_factory_success, ReadFactorySuccess)
|
||||||
|
// ADD_SCENE(uhf, write_key, WriteKey)
|
||||||
|
// ADD_SCENE(uhf, key_menu, KeyMenu)
|
||||||
50
applications/external/uhf_rfid/scenes/uhf_scene_delete.c
vendored
Normal file
50
applications/external/uhf_rfid/scenes/uhf_scene_delete.c
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
|
||||||
|
void uhf_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_delete_on_enter(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
// Setup Custom Widget view
|
||||||
|
char temp_str[64];
|
||||||
|
snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", uhf_app->uhf_device->dev_name);
|
||||||
|
widget_add_text_box_element(
|
||||||
|
uhf_app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false);
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget, GuiButtonTypeLeft, "Back", uhf_scene_delete_widget_callback, uhf_app);
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget, GuiButtonTypeRight, "Delete", uhf_scene_delete_widget_callback, uhf_app);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_delete_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
|
return scene_manager_previous_scene(uhf_app->scene_manager);
|
||||||
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
|
if(uhf_device_delete(uhf_app->uhf_device, true)) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneDeleteSuccess);
|
||||||
|
} else {
|
||||||
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_delete_on_exit(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
widget_reset(uhf_app->widget);
|
||||||
|
}
|
||||||
40
applications/external/uhf_rfid/scenes/uhf_scene_delete_success.c
vendored
Normal file
40
applications/external/uhf_rfid/scenes/uhf_scene_delete_success.c
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
|
||||||
|
void uhf_scene_delete_success_popup_callback(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_delete_success_on_enter(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
Popup* popup = uhf_app->popup;
|
||||||
|
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
|
||||||
|
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
popup_set_context(popup, uhf_app);
|
||||||
|
popup_set_callback(popup, uhf_scene_delete_success_popup_callback);
|
||||||
|
popup_enable_timeout(popup);
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == UHFCustomEventViewExit) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_delete_success_on_exit(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
popup_reset(uhf_app->popup);
|
||||||
|
}
|
||||||
133
applications/external/uhf_rfid/scenes/uhf_scene_device_info.c
vendored
Normal file
133
applications/external/uhf_rfid/scenes/uhf_scene_device_info.c
vendored
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
typedef enum { EPC_INFO, TID_INFO, USER_INFO } UHFTagInfo;
|
||||||
|
|
||||||
|
static UHFTagInfo current_info;
|
||||||
|
|
||||||
|
char* get_current_bank_info_str() {
|
||||||
|
switch(current_info) {
|
||||||
|
case EPC_INFO:
|
||||||
|
return "EPC Bank";
|
||||||
|
case TID_INFO:
|
||||||
|
return "TID Bank";
|
||||||
|
case USER_INFO:
|
||||||
|
return "User Bank";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_next_bank_info_str() {
|
||||||
|
switch(current_info) {
|
||||||
|
case EPC_INFO:
|
||||||
|
current_info = TID_INFO;
|
||||||
|
return "TID";
|
||||||
|
case TID_INFO:
|
||||||
|
current_info = USER_INFO;
|
||||||
|
return "USER";
|
||||||
|
case USER_INFO:
|
||||||
|
current_info = EPC_INFO;
|
||||||
|
return "EPC";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_view_on_event(UHFApp* uhf_app) {
|
||||||
|
UHFTag* uhf_tag = uhf_app->uhf_device->uhf_tag_wrapper->uhf_tag;
|
||||||
|
FuriString* furi_temp_str;
|
||||||
|
furi_temp_str = furi_string_alloc();
|
||||||
|
char* temp_str;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
widget_reset(uhf_app->widget);
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget, 64, 5, AlignCenter, AlignCenter, FontPrimary, get_current_bank_info_str());
|
||||||
|
|
||||||
|
switch(current_info) {
|
||||||
|
case EPC_INFO:
|
||||||
|
temp_str = convertToHexString(uhf_tag->epc->data, uhf_tag->epc->size);
|
||||||
|
length = uhf_tag->epc->size;
|
||||||
|
break;
|
||||||
|
case TID_INFO:
|
||||||
|
temp_str = convertToHexString(uhf_tag->tid->data, uhf_tag->tid->size);
|
||||||
|
length = uhf_tag->tid->size;
|
||||||
|
break;
|
||||||
|
case USER_INFO:
|
||||||
|
temp_str = convertToHexString(uhf_tag->user->data, uhf_tag->user->size);
|
||||||
|
length = uhf_tag->user->size;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
temp_str = NULL;
|
||||||
|
length = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_string_cat_printf(furi_temp_str, "Length: %d bytes", length);
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
3,
|
||||||
|
12,
|
||||||
|
AlignLeft,
|
||||||
|
AlignTop,
|
||||||
|
FontKeyboard,
|
||||||
|
furi_string_get_cstr(furi_temp_str));
|
||||||
|
|
||||||
|
widget_add_string_multiline_element(
|
||||||
|
uhf_app->widget, 3, 24, AlignLeft, AlignTop, FontKeyboard, temp_str);
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
GuiButtonTypeRight,
|
||||||
|
get_next_bank_info_str(),
|
||||||
|
uhf_scene_device_info_widget_callback,
|
||||||
|
uhf_app);
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget, GuiButtonTypeLeft, "Back", uhf_scene_device_info_widget_callback, uhf_app);
|
||||||
|
|
||||||
|
furi_string_free(furi_temp_str);
|
||||||
|
free(temp_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_device_info_on_enter(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
current_info = EPC_INFO;
|
||||||
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
change_view_on_event(uhf_app);
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_device_info_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.type == SceneManagerEventTypeTick) return false;
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
|
consumed = scene_manager_previous_scene(uhf_app->scene_manager);
|
||||||
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
|
change_view_on_event(uhf_app);
|
||||||
|
} else if(event.event == UHFCustomEventViewExit) {
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
scene_manager_previous_scene(uhf_app->scene_manager);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_device_info_on_exit(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
// Clear views
|
||||||
|
widget_reset(uhf_app->widget);
|
||||||
|
}
|
||||||
23
applications/external/uhf_rfid/scenes/uhf_scene_file_select.c
vendored
Normal file
23
applications/external/uhf_rfid/scenes/uhf_scene_file_select.c
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
|
||||||
|
void uhf_scene_file_select_on_enter(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
// Process file_select return
|
||||||
|
uhf_device_set_loading_callback(uhf_app->uhf_device, uhf_show_loading_popup, uhf_app);
|
||||||
|
if(uhf_file_select(uhf_app->uhf_device)) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSavedMenu);
|
||||||
|
} else {
|
||||||
|
scene_manager_search_and_switch_to_previous_scene(uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
}
|
||||||
|
uhf_device_set_loading_callback(uhf_app->uhf_device, NULL, uhf_app);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_file_select_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UNUSED(context);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_file_select_on_exit(void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
}
|
||||||
45
applications/external/uhf_rfid/scenes/uhf_scene_read_tag.c
vendored
Normal file
45
applications/external/uhf_rfid/scenes/uhf_scene_read_tag.c
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void uhf_read_tag_worker_callback(UHFWorkerEvent event, void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
if(event == UHFWorkerEventSuccess) {
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventWorkerExit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_read_tag_on_enter(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
dolphin_deed(DolphinDeedNfcRead);
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
Popup* popup = uhf_app->popup;
|
||||||
|
popup_set_header(popup, "Detecting\n[UHF] RFID\nTag", 68, 30, AlignLeft, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
||||||
|
|
||||||
|
// Start worker
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
|
||||||
|
uhf_worker_start(
|
||||||
|
uhf_app->worker, UHFWorkerStateDetectSingle, uhf_read_tag_worker_callback, uhf_app);
|
||||||
|
|
||||||
|
uhf_blink_start(uhf_app);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_read_tag_on_event(void* ctx, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.event == UHFCustomEventWorkerExit) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneReadTagSuccess);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_read_tag_on_exit(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
// Stop worker
|
||||||
|
uhf_worker_stop(uhf_app->worker);
|
||||||
|
// Clear view
|
||||||
|
popup_reset(uhf_app->popup);
|
||||||
|
uhf_blink_stop(uhf_app);
|
||||||
|
}
|
||||||
111
applications/external/uhf_rfid/scenes/uhf_scene_read_tag_success.c
vendored
Normal file
111
applications/external/uhf_rfid/scenes/uhf_scene_read_tag_success.c
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void uhf_read_tag_success_worker_callback(UHFWorkerEvent event, void* ctx) {
|
||||||
|
UNUSED(event);
|
||||||
|
UNUSED(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_read_card_success_widget_callback(GuiButtonType result, InputType type, void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_read_tag_success_on_enter(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
UHFTag* uhf_tag = uhf_app->worker->uhf_tag_wrapper->uhf_tag;
|
||||||
|
FuriString* temp_str = furi_string_alloc();
|
||||||
|
|
||||||
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
|
// Send notification
|
||||||
|
notification_message(uhf_app->notifications, &sequence_success);
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget, 32, 5, AlignLeft, AlignCenter, FontPrimary, "Read Success");
|
||||||
|
|
||||||
|
widget_add_string_element(uhf_app->widget, 3, 18, AlignLeft, AlignCenter, FontPrimary, "PC :");
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget, 66, 18, AlignLeft, AlignCenter, FontPrimary, "CRC :");
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget, 3, 32, AlignLeft, AlignCenter, FontPrimary, "EPC :");
|
||||||
|
|
||||||
|
furi_string_cat_printf(temp_str, "%04X", uhf_tag->epc->pc);
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
26,
|
||||||
|
19,
|
||||||
|
AlignLeft,
|
||||||
|
AlignCenter,
|
||||||
|
FontKeyboard,
|
||||||
|
furi_string_get_cstr(temp_str));
|
||||||
|
furi_string_reset(temp_str);
|
||||||
|
furi_string_cat_printf(temp_str, "%04X", uhf_tag->epc->crc);
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
96,
|
||||||
|
19,
|
||||||
|
AlignLeft,
|
||||||
|
AlignCenter,
|
||||||
|
FontKeyboard,
|
||||||
|
furi_string_get_cstr(temp_str));
|
||||||
|
char* epc = convertToHexString(uhf_tag->epc->data, uhf_tag->epc->size);
|
||||||
|
if(epc != NULL) {
|
||||||
|
widget_add_string_multiline_element(
|
||||||
|
uhf_app->widget, 34, 29, AlignLeft, AlignTop, FontKeyboard, epc);
|
||||||
|
}
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
GuiButtonTypeRight,
|
||||||
|
"More",
|
||||||
|
uhf_scene_read_card_success_widget_callback,
|
||||||
|
uhf_app);
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
GuiButtonTypeLeft,
|
||||||
|
"Exit",
|
||||||
|
uhf_scene_read_card_success_widget_callback,
|
||||||
|
uhf_app);
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
|
||||||
|
free(epc);
|
||||||
|
furi_string_free(temp_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_read_tag_success_on_event(void* ctx, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.event == SceneManagerEventTypeBack) {
|
||||||
|
uhf_app->worker->state = UHFWorkerStateStop;
|
||||||
|
}
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
// if 'exit' is pressed go back to home screen
|
||||||
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneTagMenu);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeCenter) {
|
||||||
|
// consumed = scene_manager_search_and_switch_to_another_scene(
|
||||||
|
// picopass->scene_manager, PicopassSceneStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_read_tag_success_on_exit(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
// // Stop worker
|
||||||
|
uhf_worker_stop(uhf_app->worker);
|
||||||
|
// Clear view
|
||||||
|
popup_reset(uhf_app->popup);
|
||||||
|
// clear widget
|
||||||
|
widget_reset(uhf_app->widget);
|
||||||
|
}
|
||||||
74
applications/external/uhf_rfid/scenes/uhf_scene_save_name.c
vendored
Normal file
74
applications/external/uhf_rfid/scenes/uhf_scene_save_name.c
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
#include <lib/toolbox/name_generator.h>
|
||||||
|
#include <gui/modules/validators.h>
|
||||||
|
#include <toolbox/path.h>
|
||||||
|
|
||||||
|
void uhf_scene_save_name_text_input_callback(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventTextInputDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_save_name_on_enter(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
TextInput* text_input = uhf_app->text_input;
|
||||||
|
name_generator_make_random(uhf_app->text_store, sizeof(uhf_app->text_store));
|
||||||
|
text_input_set_header_text(text_input, "Name the tag");
|
||||||
|
text_input_set_result_callback(
|
||||||
|
text_input,
|
||||||
|
uhf_scene_save_name_text_input_callback,
|
||||||
|
uhf_app,
|
||||||
|
uhf_app->text_store,
|
||||||
|
UHF_DEV_NAME_MAX_LEN,
|
||||||
|
true);
|
||||||
|
|
||||||
|
FuriString* folder_path;
|
||||||
|
folder_path = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
|
||||||
|
|
||||||
|
if(furi_string_end_with(uhf_app->uhf_device->load_path, UHF_APP_EXTENSION)) {
|
||||||
|
path_extract_dirname(furi_string_get_cstr(uhf_app->uhf_device->load_path), folder_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
|
||||||
|
furi_string_get_cstr(folder_path), UHF_APP_EXTENSION, uhf_app->uhf_device->dev_name);
|
||||||
|
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewTextInput);
|
||||||
|
|
||||||
|
furi_string_free(folder_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == UHFCustomEventTextInputDone) {
|
||||||
|
strlcpy(
|
||||||
|
uhf_app->uhf_device->dev_name,
|
||||||
|
uhf_app->text_store,
|
||||||
|
strlen(uhf_app->text_store) + 1);
|
||||||
|
if(uhf_device_save(uhf_app->uhf_device, uhf_app->text_store)) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSaveSuccess);
|
||||||
|
consumed = true;
|
||||||
|
} else {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_save_name_on_exit(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
void* validator_context = text_input_get_validator_callback_context(uhf_app->text_input);
|
||||||
|
text_input_set_validator(uhf_app->text_input, NULL, NULL);
|
||||||
|
validator_is_file_free(validator_context);
|
||||||
|
|
||||||
|
text_input_reset(uhf_app->text_input);
|
||||||
|
}
|
||||||
47
applications/external/uhf_rfid/scenes/uhf_scene_save_success.c
vendored
Normal file
47
applications/external/uhf_rfid/scenes/uhf_scene_save_success.c
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void uhf_scene_save_success_popup_callback(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_save_success_on_enter(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
dolphin_deed(DolphinDeedNfcSave);
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
Popup* popup = uhf_app->popup;
|
||||||
|
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||||
|
popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom);
|
||||||
|
popup_set_timeout(popup, 1500);
|
||||||
|
popup_set_context(popup, uhf_app);
|
||||||
|
popup_set_callback(popup, uhf_scene_save_success_popup_callback);
|
||||||
|
popup_enable_timeout(popup);
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == UHFCustomEventViewExit) {
|
||||||
|
if(scene_manager_has_previous_scene(uhf_app->scene_manager, UHFSceneTagMenu)) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
uhf_app->scene_manager, UHFSceneTagMenu);
|
||||||
|
} else {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_save_success_on_exit(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
popup_reset(uhf_app->popup);
|
||||||
|
}
|
||||||
59
applications/external/uhf_rfid/scenes/uhf_scene_saved_menu.c
vendored
Normal file
59
applications/external/uhf_rfid/scenes/uhf_scene_saved_menu.c
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexDelete,
|
||||||
|
SubmenuIndexInfo,
|
||||||
|
SubmenuIndexWrite,
|
||||||
|
};
|
||||||
|
|
||||||
|
void uhf_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_saved_menu_on_enter(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
Submenu* submenu = uhf_app->submenu;
|
||||||
|
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Delete", SubmenuIndexDelete, uhf_scene_saved_menu_submenu_callback, uhf_app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Info", SubmenuIndexInfo, uhf_scene_saved_menu_submenu_callback, uhf_app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Write", SubmenuIndexWrite, uhf_scene_saved_menu_submenu_callback, uhf_app);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
uhf_app->submenu,
|
||||||
|
scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneSavedMenu));
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
scene_manager_set_scene_state(uhf_app->scene_manager, UHFSceneSavedMenu, event.event);
|
||||||
|
|
||||||
|
if(event.event == SubmenuIndexDelete) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneDelete);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexInfo) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneDeviceInfo);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexWrite) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneWriteTag);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_saved_menu_on_exit(void* context) {
|
||||||
|
UHFApp* uhf_app = context;
|
||||||
|
|
||||||
|
submenu_reset(uhf_app->submenu);
|
||||||
|
}
|
||||||
122
applications/external/uhf_rfid/scenes/uhf_scene_settings.c
vendored
Normal file
122
applications/external/uhf_rfid/scenes/uhf_scene_settings.c
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
#include "../uhf_module.h"
|
||||||
|
|
||||||
|
void uhf_settings_set_module_baudrate(VariableItem* item) {
|
||||||
|
M100Module* uhf_module = variable_item_get_context(item);
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
if(index >= BAUD_RATES_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t baudrate = BAUD_RATES[index];
|
||||||
|
m100_set_baudrate(uhf_module, baudrate);
|
||||||
|
char text_buf[10];
|
||||||
|
snprintf(text_buf, sizeof(text_buf), "%lu", uhf_module->baudrate);
|
||||||
|
variable_item_set_current_value_text(item, text_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_settings_set_module_powerdb(VariableItem* item) {
|
||||||
|
M100Module* uhf_module = variable_item_get_context(item);
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
if(index >= POWER_DBM_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint16_t power = POWER_DBM[index];
|
||||||
|
m100_set_transmitting_power(uhf_module, power);
|
||||||
|
char text_buf[10];
|
||||||
|
snprintf(text_buf, sizeof(text_buf), "%ddBm", uhf_module->transmitting_power);
|
||||||
|
variable_item_set_current_value_text(item, text_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_settings_set_module_working_region(VariableItem* item) {
|
||||||
|
M100Module* uhf_module = variable_item_get_context(item);
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
if(index >= WORKING_REGIONS_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WorkingRegion region = WORKING_REGIONS[index];
|
||||||
|
m100_set_working_region(uhf_module, region);
|
||||||
|
variable_item_set_current_value_text(item, WORKING_REGIONS_STR[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t uhf_settings_get_module_baudrate_index(M100Module* module) {
|
||||||
|
for(uint8_t i = 0; i < BAUD_RATES_COUNT; i++) {
|
||||||
|
if(BAUD_RATES[i] == module->baudrate) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t uhf_settings_get_module_power_index(M100Module* module) {
|
||||||
|
for(uint8_t i = 0; i < BAUD_RATES_COUNT; i++) {
|
||||||
|
if(POWER_DBM[i] == module->transmitting_power) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t uhf_settings_get_module_working_region_index(M100Module* module) {
|
||||||
|
for(uint8_t i = 0; i < WORKING_REGIONS_COUNT; i++) {
|
||||||
|
if(WORKING_REGIONS[i] == module->region) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_settings_on_enter(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
M100Module* uhf_module = uhf_app->worker->module;
|
||||||
|
VariableItem* item;
|
||||||
|
VariableItemList* variable_item_list = uhf_app->variable_item_list;
|
||||||
|
|
||||||
|
uint8_t value_index = uhf_settings_get_module_baudrate_index(uhf_module);
|
||||||
|
char text_buf[10];
|
||||||
|
snprintf(text_buf, sizeof(text_buf), "%lu", uhf_module->baudrate);
|
||||||
|
item = variable_item_list_add(
|
||||||
|
variable_item_list,
|
||||||
|
"Baudrate:",
|
||||||
|
BAUD_RATES_COUNT,
|
||||||
|
uhf_settings_set_module_baudrate,
|
||||||
|
uhf_module);
|
||||||
|
|
||||||
|
variable_item_set_current_value_text(item, text_buf);
|
||||||
|
variable_item_set_current_value_index(item, value_index);
|
||||||
|
|
||||||
|
value_index = uhf_settings_get_module_power_index(uhf_module);
|
||||||
|
item = variable_item_list_add(
|
||||||
|
variable_item_list,
|
||||||
|
"Power(DBM):",
|
||||||
|
POWER_DBM_COUNT,
|
||||||
|
uhf_settings_set_module_powerdb,
|
||||||
|
uhf_module);
|
||||||
|
snprintf(text_buf, sizeof(text_buf), "%ddBm", uhf_module->transmitting_power);
|
||||||
|
variable_item_set_current_value_text(item, text_buf);
|
||||||
|
variable_item_set_current_value_index(item, value_index);
|
||||||
|
|
||||||
|
value_index = uhf_settings_get_module_working_region_index(uhf_module);
|
||||||
|
item = variable_item_list_add(
|
||||||
|
variable_item_list,
|
||||||
|
"Region:",
|
||||||
|
WORKING_REGIONS_COUNT,
|
||||||
|
uhf_settings_set_module_working_region,
|
||||||
|
uhf_module);
|
||||||
|
variable_item_set_current_value_text(item, WORKING_REGIONS_STR[value_index]);
|
||||||
|
variable_item_set_current_value_index(item, value_index);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewVariableItemList);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_settings_on_event(void* ctx, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
UNUSED(uhf_app);
|
||||||
|
UNUSED(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_settings_on_exit(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
variable_item_list_set_selected_item(uhf_app->variable_item_list, 0);
|
||||||
|
variable_item_list_reset(uhf_app->variable_item_list);
|
||||||
|
}
|
||||||
54
applications/external/uhf_rfid/scenes/uhf_scene_start.c
vendored
Normal file
54
applications/external/uhf_rfid/scenes/uhf_scene_start.c
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
|
||||||
|
enum SubmenuIndex { SubmenuIndexRead, SubmenuIndexSaved, SubmenuIndexSettings };
|
||||||
|
|
||||||
|
void uhf_scene_start_submenu_callback(void* ctx, uint32_t index) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_start_on_enter(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
Submenu* submenu = uhf_app->submenu;
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Read Tag", SubmenuIndexRead, uhf_scene_start_submenu_callback, uhf_app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Saved", SubmenuIndexSaved, uhf_scene_start_submenu_callback, uhf_app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Settings", SubmenuIndexSettings, uhf_scene_start_submenu_callback, uhf_app);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
submenu, scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneStart));
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_start_on_event(void* ctx, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexRead) {
|
||||||
|
scene_manager_set_scene_state(uhf_app->scene_manager, UHFSceneStart, SubmenuIndexRead);
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneReadTag);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexSaved) {
|
||||||
|
// Explicitly save state so that the correct item is
|
||||||
|
// reselected if the user cancels loading a file.
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart, SubmenuIndexSaved);
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneFileSelect);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexSettings) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart, SubmenuIndexSettings);
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSettings);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_start_on_exit(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
submenu_reset(uhf_app->submenu);
|
||||||
|
}
|
||||||
58
applications/external/uhf_rfid/scenes/uhf_scene_tag_menu.c
vendored
Normal file
58
applications/external/uhf_rfid/scenes/uhf_scene_tag_menu.c
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexSave,
|
||||||
|
SubmenuIndexChangeKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
void uhf_scene_tag_menu_submenu_callback(void* ctx, uint32_t index) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_tag_menu_on_enter(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
Submenu* submenu = uhf_app->submenu;
|
||||||
|
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Save", SubmenuIndexSave, uhf_scene_tag_menu_submenu_callback, uhf_app);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Change Key", SubmenuIndexChangeKey, uhf_scene_tag_menu_submenu_callback, uhf_app);
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
submenu, scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneTagMenu));
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_tag_menu_on_event(void* ctx, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexSave) {
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
uhf_app->scene_manager, UHFSceneTagMenu, SubmenuIndexSave);
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSaveName);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
// else if(event.event == SubmenuIndexChangeKey) {
|
||||||
|
// scene_manager_set_scene_state(
|
||||||
|
// picopass->scene_manager, UHFSceneTagMenu, SubmenuIndexChangeKey);
|
||||||
|
// scene_manager_next_scene(picopass->scene_manager, PicopassSceneKeyMenu);
|
||||||
|
// consumed = true;
|
||||||
|
// }
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_tag_menu_on_exit(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
submenu_reset(uhf_app->submenu);
|
||||||
|
}
|
||||||
147
applications/external/uhf_rfid/scenes/uhf_scene_verify.c
vendored
Normal file
147
applications/external/uhf_rfid/scenes/uhf_scene_verify.c
vendored
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
|
||||||
|
bool verify_success = false;
|
||||||
|
FuriString* temp_str;
|
||||||
|
|
||||||
|
void uhf_scene_verify_callback_event(UHFWorkerEvent event, void* ctx) {
|
||||||
|
UNUSED(ctx);
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
if(event == UHFWorkerEventSuccess) verify_success = true;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventVerifyDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_verify_widget_callback(GuiButtonType result, InputType type, void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_verify_on_enter(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
uhf_worker_start(
|
||||||
|
uhf_app->worker, UHFWorkerStateVerify, uhf_scene_verify_callback_event, uhf_app);
|
||||||
|
temp_str = furi_string_alloc();
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.event == SceneManagerEventTypeBack) {
|
||||||
|
uhf_app->worker->state = UHFWorkerStateStop;
|
||||||
|
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == GuiButtonTypeRight) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeLeft) {
|
||||||
|
if(!verify_success) {
|
||||||
|
widget_reset(uhf_app->widget);
|
||||||
|
furi_string_reset(temp_str);
|
||||||
|
uhf_worker_stop(uhf_app->worker);
|
||||||
|
// furi_hal_gpio_write(&gpio_ext, false);
|
||||||
|
// furi_delay_ms(50);
|
||||||
|
// furi_hal_gpio_write(&gpio_ext_pa7, true);
|
||||||
|
// furi_delay_ms(50);
|
||||||
|
uhf_worker_start(
|
||||||
|
uhf_app->worker,
|
||||||
|
UHFWorkerStateVerify,
|
||||||
|
uhf_scene_verify_callback_event,
|
||||||
|
uhf_app);
|
||||||
|
}
|
||||||
|
} else if(event.event == UHFCustomEventVerifyDone) {
|
||||||
|
if(verify_success) {
|
||||||
|
widget_reset(uhf_app->widget);
|
||||||
|
furi_string_reset(temp_str);
|
||||||
|
M100Module* module = uhf_app->worker->module;
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget, 64, 5, AlignCenter, AlignCenter, FontPrimary, "Module Info");
|
||||||
|
// hardware info
|
||||||
|
furi_string_cat_str(temp_str, "HW Version: ");
|
||||||
|
furi_string_cat_str(temp_str, module->info->hw_version);
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
1,
|
||||||
|
15,
|
||||||
|
AlignLeft,
|
||||||
|
AlignTop,
|
||||||
|
FontSecondary,
|
||||||
|
furi_string_get_cstr(temp_str));
|
||||||
|
furi_string_reset(temp_str);
|
||||||
|
// software info
|
||||||
|
furi_string_cat_str(temp_str, "SW Version: ");
|
||||||
|
furi_string_cat_str(temp_str, module->info->sw_version);
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
1,
|
||||||
|
27,
|
||||||
|
AlignLeft,
|
||||||
|
AlignTop,
|
||||||
|
FontSecondary,
|
||||||
|
furi_string_get_cstr(temp_str));
|
||||||
|
furi_string_reset(temp_str);
|
||||||
|
// manufacturer info
|
||||||
|
furi_string_cat_str(temp_str, "Manufacturer: ");
|
||||||
|
furi_string_cat_str(temp_str, module->info->manufacturer);
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
1,
|
||||||
|
39,
|
||||||
|
AlignLeft,
|
||||||
|
AlignTop,
|
||||||
|
FontSecondary,
|
||||||
|
furi_string_get_cstr(temp_str));
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
GuiButtonTypeRight,
|
||||||
|
"Continue",
|
||||||
|
uhf_scene_verify_widget_callback,
|
||||||
|
uhf_app);
|
||||||
|
} else {
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
64,
|
||||||
|
5,
|
||||||
|
AlignCenter,
|
||||||
|
AlignCenter,
|
||||||
|
FontPrimary,
|
||||||
|
"No UHF Module found");
|
||||||
|
widget_add_string_multiline_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
64,
|
||||||
|
30,
|
||||||
|
AlignCenter,
|
||||||
|
AlignCenter,
|
||||||
|
FontSecondary,
|
||||||
|
"Please refer to the git@frux-c/uhf_rfid for help.");
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
GuiButtonTypeLeft,
|
||||||
|
"Retry",
|
||||||
|
uhf_scene_verify_widget_callback,
|
||||||
|
uhf_app);
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
GuiButtonTypeRight,
|
||||||
|
"Skip",
|
||||||
|
uhf_scene_verify_widget_callback,
|
||||||
|
uhf_app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_verify_on_exit(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
// Clear string
|
||||||
|
furi_string_free(temp_str);
|
||||||
|
// Stop worker
|
||||||
|
uhf_worker_stop(uhf_app->worker);
|
||||||
|
// clear widget
|
||||||
|
widget_reset(uhf_app->widget);
|
||||||
|
}
|
||||||
49
applications/external/uhf_rfid/scenes/uhf_scene_write_tag.c
vendored
Normal file
49
applications/external/uhf_rfid/scenes/uhf_scene_write_tag.c
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void uhf_write_tag_worker_callback(UHFWorkerEvent event, void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
if(event == UHFWorkerEventSuccess) {
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventWorkerExit);
|
||||||
|
}
|
||||||
|
// } else if(event == UHFWorkerEventAborted) {
|
||||||
|
// scene_manager_search_and_switch_to_previous_scene(uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_write_tag_on_enter(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
dolphin_deed(DolphinDeedNfcRead);
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
Popup* popup = uhf_app->popup;
|
||||||
|
popup_set_header(popup, "Writing\n[UHF] RFID\nTag", 68, 30, AlignLeft, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||||
|
|
||||||
|
// Start worker
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
|
||||||
|
uhf_worker_start(
|
||||||
|
uhf_app->worker, UHFWorkerStateWriteSingle, uhf_write_tag_worker_callback, uhf_app);
|
||||||
|
|
||||||
|
uhf_blink_start(uhf_app);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_write_tag_on_event(void* ctx, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.event == UHFCustomEventWorkerExit) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneWriteTagSuccess);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_write_tag_on_exit(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
// Stop worker
|
||||||
|
uhf_worker_stop(uhf_app->worker);
|
||||||
|
// Clear view
|
||||||
|
popup_reset(uhf_app->popup);
|
||||||
|
|
||||||
|
uhf_blink_stop(uhf_app);
|
||||||
|
}
|
||||||
94
applications/external/uhf_rfid/scenes/uhf_scene_write_tag_success.c
vendored
Normal file
94
applications/external/uhf_rfid/scenes/uhf_scene_write_tag_success.c
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#include "../uhf_app_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void uhf_write_tag_success_worker_callback(UHFWorkerEvent event, void* ctx) {
|
||||||
|
UNUSED(event);
|
||||||
|
UNUSED(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_write_tag_success_widget_callback(GuiButtonType result, InputType type, void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_write_tag_success_on_enter(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
|
// Send notification
|
||||||
|
notification_message(uhf_app->notifications, &sequence_success);
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
uhf_app->widget, 32, 5, AlignLeft, AlignCenter, FontPrimary, "Write Success");
|
||||||
|
|
||||||
|
// widget_add_string_element(uhf_app->widget, 3, 18, AlignLeft, AlignCenter, FontPrimary, "PC :");
|
||||||
|
|
||||||
|
// widget_add_string_element(
|
||||||
|
// uhf_app->widget, 66, 18, AlignLeft, AlignCenter, FontPrimary, "CRC :");
|
||||||
|
|
||||||
|
// widget_add_string_element(
|
||||||
|
// uhf_app->widget, 3, 32, AlignLeft, AlignCenter, FontPrimary, "EPC :");
|
||||||
|
|
||||||
|
// char* pc = convertToHexString(uhf_tag->pc, 2);
|
||||||
|
// widget_add_string_element(uhf_app->widget, 26, 19, AlignLeft, AlignCenter, FontKeyboard, pc);
|
||||||
|
// char* crc = convertToHexString(uhf_tag->crc, 2);
|
||||||
|
// widget_add_string_element(uhf_app->widget, 96, 19, AlignLeft, AlignCenter, FontKeyboard, crc);
|
||||||
|
// char* epc = convertToHexString(uhf_tag->epc + 2, uhf_tag->epc_length - 2);
|
||||||
|
// widget_add_string_multiline_element(
|
||||||
|
// uhf_app->widget, 34, 29, AlignLeft, AlignTop, FontKeyboard, epc);
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
GuiButtonTypeRight,
|
||||||
|
"More",
|
||||||
|
uhf_scene_write_tag_success_widget_callback,
|
||||||
|
uhf_app);
|
||||||
|
widget_add_button_element(
|
||||||
|
uhf_app->widget,
|
||||||
|
GuiButtonTypeLeft,
|
||||||
|
"Exit",
|
||||||
|
uhf_scene_write_tag_success_widget_callback,
|
||||||
|
uhf_app);
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
|
||||||
|
// free(pc);
|
||||||
|
// free(crc);
|
||||||
|
// free(epc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_scene_write_tag_success_on_event(void* ctx, SceneManagerEvent event) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
bool consumed = false;
|
||||||
|
if(event.event == SceneManagerEventTypeBack) {
|
||||||
|
uhf_app->worker->state = UHFWorkerStateStop;
|
||||||
|
}
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
// if 'exit' is pressed go back to home screen
|
||||||
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
uhf_app->scene_manager, UHFSceneStart);
|
||||||
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneTagMenu);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeCenter) {
|
||||||
|
// consumed = scene_manager_search_and_switch_to_another_scene(
|
||||||
|
// picopass->scene_manager, PicopassSceneStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_scene_write_tag_success_on_exit(void* ctx) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
// // Stop worker
|
||||||
|
uhf_worker_stop(uhf_app->worker);
|
||||||
|
// Clear view
|
||||||
|
popup_reset(uhf_app->popup);
|
||||||
|
// clear widget
|
||||||
|
widget_reset(uhf_app->widget);
|
||||||
|
}
|
||||||
214
applications/external/uhf_rfid/uhf_app.c
vendored
Normal file
214
applications/external/uhf_rfid/uhf_app.c
vendored
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
#include "uhf_app_i.h"
|
||||||
|
|
||||||
|
char* convertToHexString(uint8_t* array, size_t length) {
|
||||||
|
if(array == NULL || length == 0) {
|
||||||
|
return " ";
|
||||||
|
}
|
||||||
|
FuriString* temp_str = furi_string_alloc();
|
||||||
|
|
||||||
|
for(size_t i = 0; i < length; i++) {
|
||||||
|
furi_string_cat_printf(temp_str, "%02X ", array[i]);
|
||||||
|
}
|
||||||
|
const char* furi_str = furi_string_get_cstr(temp_str);
|
||||||
|
|
||||||
|
size_t str_len = strlen(furi_str);
|
||||||
|
char* str = (char*)malloc(sizeof(char) * str_len);
|
||||||
|
|
||||||
|
memcpy(str, furi_str, str_len);
|
||||||
|
furi_string_free(temp_str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_custom_event_callback(void* ctx, uint32_t event) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
return scene_manager_handle_custom_event(uhf_app->scene_manager, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_back_event_callback(void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
return scene_manager_handle_back_event(uhf_app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tick_event_callback(void* ctx) {
|
||||||
|
furi_assert(ctx);
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
scene_manager_handle_tick_event(uhf_app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
UHFApp* uhf_alloc() {
|
||||||
|
UHFApp* uhf_app = (UHFApp*)malloc(sizeof(UHFApp));
|
||||||
|
uhf_app->view_dispatcher = view_dispatcher_alloc();
|
||||||
|
uhf_app->scene_manager = scene_manager_alloc(&uhf_scene_handlers, uhf_app);
|
||||||
|
view_dispatcher_enable_queue(uhf_app->view_dispatcher);
|
||||||
|
view_dispatcher_set_event_callback_context(uhf_app->view_dispatcher, uhf_app);
|
||||||
|
view_dispatcher_set_custom_event_callback(uhf_app->view_dispatcher, uhf_custom_event_callback);
|
||||||
|
view_dispatcher_set_navigation_event_callback(
|
||||||
|
uhf_app->view_dispatcher, uhf_back_event_callback);
|
||||||
|
view_dispatcher_set_tick_event_callback(
|
||||||
|
uhf_app->view_dispatcher, uhf_tick_event_callback, 100);
|
||||||
|
|
||||||
|
// Open GUI record
|
||||||
|
uhf_app->gui = furi_record_open(RECORD_GUI);
|
||||||
|
view_dispatcher_attach_to_gui(
|
||||||
|
uhf_app->view_dispatcher, uhf_app->gui, ViewDispatcherTypeFullscreen);
|
||||||
|
|
||||||
|
// Variable Item List
|
||||||
|
uhf_app->variable_item_list = variable_item_list_alloc();
|
||||||
|
|
||||||
|
//worker
|
||||||
|
uhf_app->worker = uhf_worker_alloc();
|
||||||
|
|
||||||
|
// device
|
||||||
|
uhf_app->uhf_device = uhf_device_alloc();
|
||||||
|
|
||||||
|
UHFTagWrapper* uhf_tag_wrapper = uhf_tag_wrapper_alloc();
|
||||||
|
|
||||||
|
// // point tag object to worker
|
||||||
|
uhf_app->worker->uhf_tag_wrapper = uhf_tag_wrapper;
|
||||||
|
uhf_app->uhf_device->uhf_tag_wrapper = uhf_tag_wrapper;
|
||||||
|
|
||||||
|
// Open Notification record
|
||||||
|
uhf_app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
|
// Variable Item List
|
||||||
|
uhf_app->variable_item_list = variable_item_list_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
uhf_app->view_dispatcher,
|
||||||
|
UHFViewVariableItemList,
|
||||||
|
variable_item_list_get_view(uhf_app->variable_item_list));
|
||||||
|
|
||||||
|
// Submenu
|
||||||
|
uhf_app->submenu = submenu_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
uhf_app->view_dispatcher, UHFViewMenu, submenu_get_view(uhf_app->submenu));
|
||||||
|
|
||||||
|
// Popup
|
||||||
|
uhf_app->popup = popup_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
uhf_app->view_dispatcher, UHFViewPopup, popup_get_view(uhf_app->popup));
|
||||||
|
|
||||||
|
// Loading
|
||||||
|
uhf_app->loading = loading_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
uhf_app->view_dispatcher, UHFViewLoading, loading_get_view(uhf_app->loading));
|
||||||
|
|
||||||
|
// Text Input
|
||||||
|
uhf_app->text_input = text_input_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
uhf_app->view_dispatcher, UHFViewTextInput, text_input_get_view(uhf_app->text_input));
|
||||||
|
|
||||||
|
// Custom Widget
|
||||||
|
uhf_app->widget = widget_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
uhf_app->view_dispatcher, UHFViewWidget, widget_get_view(uhf_app->widget));
|
||||||
|
|
||||||
|
return uhf_app;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_free(UHFApp* uhf_app) {
|
||||||
|
furi_assert(uhf_app);
|
||||||
|
|
||||||
|
// Submenu
|
||||||
|
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewMenu);
|
||||||
|
submenu_free(uhf_app->submenu);
|
||||||
|
|
||||||
|
// Popup
|
||||||
|
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewPopup);
|
||||||
|
popup_free(uhf_app->popup);
|
||||||
|
|
||||||
|
// Loading
|
||||||
|
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewLoading);
|
||||||
|
loading_free(uhf_app->loading);
|
||||||
|
|
||||||
|
// TextInput
|
||||||
|
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewTextInput);
|
||||||
|
text_input_free(uhf_app->text_input);
|
||||||
|
|
||||||
|
// Custom Widget
|
||||||
|
view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewWidget);
|
||||||
|
widget_free(uhf_app->widget);
|
||||||
|
|
||||||
|
// Tag
|
||||||
|
uhf_tag_wrapper_free(uhf_app->worker->uhf_tag_wrapper);
|
||||||
|
|
||||||
|
// Worker
|
||||||
|
uhf_worker_stop(uhf_app->worker);
|
||||||
|
uhf_worker_free(uhf_app->worker);
|
||||||
|
|
||||||
|
// Device
|
||||||
|
uhf_device_free(uhf_app->uhf_device);
|
||||||
|
|
||||||
|
// View Dispatcher
|
||||||
|
view_dispatcher_free(uhf_app->view_dispatcher);
|
||||||
|
|
||||||
|
// Scene Manager
|
||||||
|
scene_manager_free(uhf_app->scene_manager);
|
||||||
|
|
||||||
|
// GUI
|
||||||
|
furi_record_close(RECORD_GUI);
|
||||||
|
uhf_app->gui = NULL;
|
||||||
|
|
||||||
|
// Variable Item List
|
||||||
|
variable_item_list_free(uhf_app->variable_item_list);
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
uhf_app->notifications = NULL;
|
||||||
|
|
||||||
|
free(uhf_app);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const NotificationSequence uhf_sequence_blink_start_cyan = {
|
||||||
|
&message_blink_start_10,
|
||||||
|
&message_blink_set_color_cyan,
|
||||||
|
&message_do_not_reset,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NotificationSequence uhf_sequence_blink_stop = {
|
||||||
|
&message_blink_stop,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void uhf_blink_start(UHFApp* uhf_app) {
|
||||||
|
notification_message(uhf_app->notifications, &uhf_sequence_blink_start_cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_blink_stop(UHFApp* uhf_app) {
|
||||||
|
notification_message(uhf_app->notifications, &uhf_sequence_blink_stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_show_loading_popup(void* ctx, bool show) {
|
||||||
|
UHFApp* uhf_app = ctx;
|
||||||
|
|
||||||
|
if(show) {
|
||||||
|
// Raise timer priority so that animations can play
|
||||||
|
furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
|
||||||
|
view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewLoading);
|
||||||
|
} else {
|
||||||
|
// Restore default timer priority
|
||||||
|
furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t uhf_app_main(void* ctx) {
|
||||||
|
UNUSED(ctx);
|
||||||
|
UHFApp* uhf_app = uhf_alloc();
|
||||||
|
|
||||||
|
// enable 5v pin
|
||||||
|
furi_hal_power_enable_otg();
|
||||||
|
// init pin a2
|
||||||
|
// furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull);
|
||||||
|
furi_hal_uart_set_br(FuriHalUartIdUSART1, DEFAULT_BAUDRATE);
|
||||||
|
scene_manager_next_scene(uhf_app->scene_manager, UHFSceneVerify);
|
||||||
|
view_dispatcher_run(uhf_app->view_dispatcher);
|
||||||
|
|
||||||
|
// disable 5v pin
|
||||||
|
furi_hal_power_disable_otg();
|
||||||
|
// furi_hal_gpio_disable_int_callback()
|
||||||
|
// exit app
|
||||||
|
uhf_free(uhf_app);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
3
applications/external/uhf_rfid/uhf_app.h
vendored
Normal file
3
applications/external/uhf_rfid/uhf_app.h
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct UHFApp UHFApp;
|
||||||
108
applications/external/uhf_rfid/uhf_app_i.h
vendored
Normal file
108
applications/external/uhf_rfid/uhf_app_i.h
vendored
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/view_dispatcher.h>
|
||||||
|
#include <gui/scene_manager.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
|
||||||
|
#include <gui/modules/submenu.h>
|
||||||
|
#include <gui/modules/popup.h>
|
||||||
|
#include <gui/modules/loading.h>
|
||||||
|
#include <gui/modules/text_input.h>
|
||||||
|
#include <gui/modules/widget.h>
|
||||||
|
#include <gui/modules/variable_item_list.h>
|
||||||
|
|
||||||
|
#include <input/input.h>
|
||||||
|
|
||||||
|
#include "uhf_app.h"
|
||||||
|
#include "uhf_worker.h"
|
||||||
|
#include "uhf_device.h"
|
||||||
|
#include "scenes/uhf_scene.h"
|
||||||
|
|
||||||
|
#include <storage/storage.h>
|
||||||
|
#include <lib/toolbox/path.h>
|
||||||
|
#include <toolbox/path.h>
|
||||||
|
#include <flipper_format/flipper_format.h>
|
||||||
|
|
||||||
|
#include <uhf_rfid_icons.h>
|
||||||
|
|
||||||
|
#define UHF_TEXT_STORE_SIZE 128
|
||||||
|
// #define UHF_APPS_DATA_FOLDER EXT_PATH("apps_data")
|
||||||
|
// #define UHF_APPS_STORAGE_FOLDER
|
||||||
|
// UHF_APPS_DATA_FOLDER "/"
|
||||||
|
// "uhf_rfid"
|
||||||
|
// #define UHF_FILE_EXTENSION ".uhf"
|
||||||
|
|
||||||
|
enum UHFCustomEvent {
|
||||||
|
// Reserve first 100 events for button types and indexes, starting from 0
|
||||||
|
UHFCustomEventReserved = 100,
|
||||||
|
|
||||||
|
UHFCustomEventVerifyDone,
|
||||||
|
UHFCustomEventViewExit,
|
||||||
|
UHFCustomEventWorkerExit,
|
||||||
|
UHFCustomEventByteInputDone,
|
||||||
|
UHFCustomEventTextInputDone,
|
||||||
|
UHFCustomEventSceneSettingLock,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EventTypeTick,
|
||||||
|
EventTypeKey,
|
||||||
|
} EventType;
|
||||||
|
|
||||||
|
struct UHFApp {
|
||||||
|
UHFWorker* worker;
|
||||||
|
ViewDispatcher* view_dispatcher;
|
||||||
|
Gui* gui;
|
||||||
|
NotificationApp* notifications;
|
||||||
|
SceneManager* scene_manager;
|
||||||
|
VariableItemList* variable_item_list;
|
||||||
|
// Storage* storage;
|
||||||
|
UHFDevice* uhf_device;
|
||||||
|
char text_store[UHF_TEXT_STORE_SIZE + 1];
|
||||||
|
FuriString* text_box_store;
|
||||||
|
// Common Views
|
||||||
|
Submenu* submenu;
|
||||||
|
Popup* popup;
|
||||||
|
Loading* loading;
|
||||||
|
TextInput* text_input;
|
||||||
|
Widget* widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UHFViewMenu,
|
||||||
|
UHFViewPopup,
|
||||||
|
UHFViewLoading,
|
||||||
|
UHFViewTextInput,
|
||||||
|
UHFViewWidget,
|
||||||
|
UHFViewVariableItemList,
|
||||||
|
} UHFView;
|
||||||
|
|
||||||
|
UHFApp* uhf_app_alloc();
|
||||||
|
|
||||||
|
void uhf_text_store_set(UHFApp* uhf, const char* text, ...);
|
||||||
|
|
||||||
|
void uhf_text_store_clear(UHFApp* uhf);
|
||||||
|
|
||||||
|
void uhf_blink_start(UHFApp* uhf);
|
||||||
|
|
||||||
|
void uhf_blink_stop(UHFApp* uhf);
|
||||||
|
|
||||||
|
void uhf_show_loading_popup(void* context, bool show);
|
||||||
|
|
||||||
|
/** Check if memory is set to pattern
|
||||||
|
*
|
||||||
|
* @warning zero size will return false
|
||||||
|
*
|
||||||
|
* @param[in] data Pointer to the byte array
|
||||||
|
* @param[in] pattern The pattern
|
||||||
|
* @param[in] size The byte array size
|
||||||
|
*
|
||||||
|
* @return True if memory is set to pattern, false otherwise
|
||||||
|
*/
|
||||||
|
bool uhf_is_memset(const uint8_t* data, const uint8_t pattern, size_t size);
|
||||||
|
|
||||||
|
char* convertToHexString(uint8_t* array, size_t length);
|
||||||
|
|
||||||
|
// bool uhf_save_read_data(UHFResponseData* uhf_response_data, Storage* storage, const char* filename);
|
||||||
69
applications/external/uhf_rfid/uhf_buffer.c
vendored
Normal file
69
applications/external/uhf_rfid/uhf_buffer.c
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include "uhf_buffer.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
Buffer* buffer_alloc(size_t initial_capacity) {
|
||||||
|
Buffer* buf = (Buffer*)malloc(sizeof(Buffer));
|
||||||
|
buf->data = (uint8_t*)malloc(sizeof(uint8_t) * initial_capacity);
|
||||||
|
if(!buf->data) {
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buf->size = 0;
|
||||||
|
buf->capacity = initial_capacity;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool buffer_append_single(Buffer* buf, uint8_t data) {
|
||||||
|
if(buf->closed) return false;
|
||||||
|
if(buf->size + 1 > buf->capacity) {
|
||||||
|
size_t new_capacity = buf->capacity * 2;
|
||||||
|
uint8_t* new_data = (uint8_t*)realloc(buf->data, sizeof(uint8_t) * new_capacity);
|
||||||
|
if(!new_data) return false;
|
||||||
|
buf->data = new_data;
|
||||||
|
buf->capacity = new_capacity;
|
||||||
|
}
|
||||||
|
buf->data[buf->size++] = data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool buffer_append(Buffer* buf, uint8_t* data, size_t data_size) {
|
||||||
|
if(buf->closed) return false;
|
||||||
|
if(buf->size + data_size > buf->capacity) {
|
||||||
|
size_t new_capacity = buf->capacity * 2;
|
||||||
|
uint8_t* new_data = (uint8_t*)realloc(buf->data, new_capacity);
|
||||||
|
if(!new_data) return false;
|
||||||
|
|
||||||
|
buf->data = new_data;
|
||||||
|
buf->capacity = new_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy((void*)&buf->data[buf->size], data, data_size);
|
||||||
|
buf->size += data_size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* buffer_get_data(Buffer* buf) {
|
||||||
|
return buf->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t buffer_get_size(Buffer* buf) {
|
||||||
|
return buf->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_close(Buffer* buf) {
|
||||||
|
buf->closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_reset(Buffer* buf) {
|
||||||
|
for(size_t i = 0; i < MAX_BUFFER_SIZE; i++) {
|
||||||
|
buf->data[i] = 0;
|
||||||
|
}
|
||||||
|
buf->size = 0;
|
||||||
|
buf->closed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_free(Buffer* buf) {
|
||||||
|
free(buf->data);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
22
applications/external/uhf_rfid/uhf_buffer.h
vendored
Normal file
22
applications/external/uhf_rfid/uhf_buffer.h
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define MAX_BUFFER_SIZE 200
|
||||||
|
|
||||||
|
typedef struct Buffer {
|
||||||
|
uint8_t* data;
|
||||||
|
size_t size;
|
||||||
|
size_t capacity;
|
||||||
|
bool closed;
|
||||||
|
} Buffer;
|
||||||
|
|
||||||
|
Buffer* buffer_alloc(size_t inital_capacity);
|
||||||
|
bool buffer_append_single(Buffer* buf, uint8_t value);
|
||||||
|
bool buffer_append(Buffer* buf, uint8_t* data, size_t size);
|
||||||
|
uint8_t* buffer_get_data(Buffer* buf);
|
||||||
|
size_t buffer_get_size(Buffer* buf);
|
||||||
|
void buffer_close(Buffer* buf);
|
||||||
|
void buffer_reset(Buffer* buf);
|
||||||
|
void buffer_free(Buffer* buf);
|
||||||
348
applications/external/uhf_rfid/uhf_device.c
vendored
Normal file
348
applications/external/uhf_rfid/uhf_device.c
vendored
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
#include "uhf_device.h"
|
||||||
|
#include <toolbox/path.h>
|
||||||
|
#include <flipper_format/flipper_format.h>
|
||||||
|
#include <uhf_rfid_icons.h>
|
||||||
|
|
||||||
|
#define TAG "UHFDevice"
|
||||||
|
|
||||||
|
static const char* uhf_file_header = "Flipper UHF RFID device";
|
||||||
|
static const uint32_t uhf_file_version = 1;
|
||||||
|
// static const uint8_t bank_data_start = 20;
|
||||||
|
// static const uint8_t bank_data_length = 16;
|
||||||
|
|
||||||
|
UHFDevice* uhf_device_alloc() {
|
||||||
|
UHFDevice* uhf_device = malloc(sizeof(UHFDevice));
|
||||||
|
uhf_device->storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
uhf_device->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
|
uhf_device->load_path = furi_string_alloc();
|
||||||
|
return uhf_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_device_set_name(UHFDevice* dev, const char* name) {
|
||||||
|
furi_assert(dev);
|
||||||
|
strlcpy(dev->dev_name, name, UHF_DEV_NAME_MAX_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool uhf_device_save_file(
|
||||||
|
UHFDevice* dev,
|
||||||
|
const char* dev_name,
|
||||||
|
const char* folder,
|
||||||
|
const char* extension,
|
||||||
|
bool use_load_path) {
|
||||||
|
furi_assert(dev);
|
||||||
|
|
||||||
|
UHFTag* uhf_tag = dev->uhf_tag_wrapper->uhf_tag;
|
||||||
|
bool saved = false;
|
||||||
|
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
|
||||||
|
FuriString* temp_str;
|
||||||
|
temp_str = furi_string_alloc();
|
||||||
|
do {
|
||||||
|
if(use_load_path && !furi_string_empty(dev->load_path)) {
|
||||||
|
// Get directory name
|
||||||
|
path_extract_dirname(furi_string_get_cstr(dev->load_path), temp_str);
|
||||||
|
// Make path to file to save
|
||||||
|
furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension);
|
||||||
|
} else {
|
||||||
|
// First remove uhf device file if it was saved
|
||||||
|
furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
|
||||||
|
}
|
||||||
|
// Open file
|
||||||
|
if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
|
||||||
|
|
||||||
|
// Write header
|
||||||
|
if(!flipper_format_write_header_cstr(file, uhf_file_header, uhf_file_version)) break;
|
||||||
|
|
||||||
|
// Reserved bank might be added
|
||||||
|
// todo : maybe
|
||||||
|
uint32_t temp_arr[1];
|
||||||
|
uint8_t temp_arr2[2];
|
||||||
|
// write pc
|
||||||
|
temp_arr2[0] = (uint8_t)(uhf_tag_get_epc_pc(uhf_tag) >> 8) & 0xFF;
|
||||||
|
temp_arr2[1] = (uint8_t)(uhf_tag_get_epc_pc(uhf_tag) & 0xFF);
|
||||||
|
if(!flipper_format_write_hex(file, UHF_EPC_PC_LABEL, temp_arr2, 2)) break;
|
||||||
|
// write crc
|
||||||
|
temp_arr2[0] = (uint8_t)(uhf_tag_get_epc_crc(uhf_tag) >> 8) & 0xFF;
|
||||||
|
temp_arr2[1] = (uint8_t)(uhf_tag_get_epc_crc(uhf_tag) & 0xFF);
|
||||||
|
if(!flipper_format_write_hex(file, UHF_EPC_CRC_LABEL, temp_arr2, 2)) break;
|
||||||
|
// write epc
|
||||||
|
temp_arr[0] = uhf_tag_get_epc_size(uhf_tag);
|
||||||
|
if(!flipper_format_write_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
|
||||||
|
break;
|
||||||
|
// write tid
|
||||||
|
temp_arr[0] = uhf_tag_get_tid_size(uhf_tag);
|
||||||
|
if(!flipper_format_write_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
|
||||||
|
break;
|
||||||
|
// write user
|
||||||
|
temp_arr[0] = uhf_tag_get_user_size(uhf_tag);
|
||||||
|
if(!flipper_format_write_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
file,
|
||||||
|
UHF_USER_BANK_LABEL,
|
||||||
|
uhf_tag_get_user(uhf_tag),
|
||||||
|
uhf_tag_get_user_size(uhf_tag)))
|
||||||
|
break;
|
||||||
|
saved = true;
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
if(!saved) {
|
||||||
|
dialog_message_show_storage_error(dev->dialogs, "Can not save\nfile");
|
||||||
|
}
|
||||||
|
furi_string_free(temp_str);
|
||||||
|
flipper_format_free(file);
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_device_save(UHFDevice* dev, const char* dev_name) {
|
||||||
|
return uhf_device_save_file(
|
||||||
|
dev, dev_name, STORAGE_APP_DATA_PATH_PREFIX, UHF_APP_EXTENSION, true);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// uncomment
|
||||||
|
|
||||||
|
static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dialog) {
|
||||||
|
bool parsed = false;
|
||||||
|
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
|
||||||
|
// UHFResponseData* uhf_response_data = dev->dev_data;
|
||||||
|
FuriString* temp_str;
|
||||||
|
temp_str = furi_string_alloc();
|
||||||
|
bool deprecated_version = false;
|
||||||
|
UHFTag* uhf_tag = uhf_tag_alloc();
|
||||||
|
uhf_tag_reset(uhf_tag);
|
||||||
|
uint32_t temp_arr[1];
|
||||||
|
if(dev->loading_cb) {
|
||||||
|
dev->loading_cb(dev->loading_cb_ctx, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;
|
||||||
|
|
||||||
|
// Read and verify file header
|
||||||
|
uint32_t version = 0;
|
||||||
|
if(!flipper_format_read_header(file, temp_str, &version)) break;
|
||||||
|
if(furi_string_cmp_str(temp_str, uhf_file_header) || (version != uhf_file_version)) {
|
||||||
|
deprecated_version = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// read pc
|
||||||
|
uint8_t temp_arr2[2];
|
||||||
|
if(!flipper_format_read_hex(file, UHF_EPC_PC_LABEL, temp_arr2, 2)) break;
|
||||||
|
uhf_tag_set_epc_pc(uhf_tag, (temp_arr2[0] << 8) + temp_arr2[1]);
|
||||||
|
// read crc
|
||||||
|
if(!flipper_format_read_hex(file, UHF_EPC_CRC_LABEL, temp_arr2, 2)) break;
|
||||||
|
uhf_tag_set_epc_crc(uhf_tag, (temp_arr2[0] << 8) + temp_arr2[1]);
|
||||||
|
// read epc
|
||||||
|
if(!flipper_format_read_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
|
||||||
|
uhf_tag_set_epc_size(uhf_tag, temp_arr[0]);
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// read tid
|
||||||
|
if(!flipper_format_read_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
|
||||||
|
uhf_tag_set_tid_size(uhf_tag, temp_arr[0]);
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
|
||||||
|
break;
|
||||||
|
// read user
|
||||||
|
if(!flipper_format_read_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
|
||||||
|
uhf_tag_set_user_size(uhf_tag, temp_arr[0]);
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
file,
|
||||||
|
UHF_USER_BANK_LABEL,
|
||||||
|
uhf_tag_get_user(uhf_tag),
|
||||||
|
uhf_tag_get_user_size(uhf_tag)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
if(dev->loading_cb) {
|
||||||
|
dev->loading_cb(dev->loading_cb_ctx, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((!parsed) && (show_dialog)) {
|
||||||
|
if(deprecated_version) {
|
||||||
|
dialog_message_show_storage_error(dev->dialogs, "File format deprecated");
|
||||||
|
} else {
|
||||||
|
dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uhf_tag_wrapper_set_tag(dev->uhf_tag_wrapper, uhf_tag);
|
||||||
|
furi_string_free(temp_str);
|
||||||
|
flipper_format_free(file);
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void picopass_device_clear(UHFDevice* dev) {
|
||||||
|
// furi_assert(dev);
|
||||||
|
|
||||||
|
// picopass_device_data_clear(&dev->dev_data);
|
||||||
|
// memset(&dev->dev_data, 0, sizeof(dev->dev_data));
|
||||||
|
// dev->format = PicopassDeviceSaveFormatHF;
|
||||||
|
// furi_string_reset(dev->load_path);
|
||||||
|
// }
|
||||||
|
|
||||||
|
void uhf_device_free(UHFDevice* uhf_dev) {
|
||||||
|
furi_assert(uhf_dev);
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
furi_record_close(RECORD_DIALOGS);
|
||||||
|
furi_string_free(uhf_dev->load_path);
|
||||||
|
free(uhf_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uhf_file_select(UHFDevice* dev) {
|
||||||
|
furi_assert(dev);
|
||||||
|
|
||||||
|
FuriString* uhf_app_folder;
|
||||||
|
uhf_app_folder = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
|
||||||
|
|
||||||
|
DialogsFileBrowserOptions browser_options;
|
||||||
|
dialog_file_browser_set_basic_options(&browser_options, UHF_APP_EXTENSION, &I_Nfc_10px);
|
||||||
|
browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
|
||||||
|
|
||||||
|
bool res =
|
||||||
|
dialog_file_browser_show(dev->dialogs, dev->load_path, uhf_app_folder, &browser_options);
|
||||||
|
|
||||||
|
furi_string_free(uhf_app_folder);
|
||||||
|
if(res) {
|
||||||
|
FuriString* filename;
|
||||||
|
filename = furi_string_alloc();
|
||||||
|
path_extract_filename(dev->load_path, filename, true);
|
||||||
|
strncpy(dev->dev_name, furi_string_get_cstr(filename), UHF_DEV_NAME_MAX_LEN);
|
||||||
|
res = uhf_device_load_data(dev, dev->load_path, true);
|
||||||
|
if(res) {
|
||||||
|
uhf_device_set_name(dev, dev->dev_name);
|
||||||
|
}
|
||||||
|
furi_string_free(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void uhf_device_data_clear(UHFDevice* dev_data) {
|
||||||
|
// for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
|
||||||
|
// memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data));
|
||||||
|
// }
|
||||||
|
// dev_data->pacs.legacy = false;
|
||||||
|
// dev_data->pacs.se_enabled = false;
|
||||||
|
// dev_data->pacs.elite_kdf = false;
|
||||||
|
// dev_data->pacs.pin_length = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
bool uhf_device_delete(UHFDevice* dev, bool use_load_path) {
|
||||||
|
furi_assert(dev);
|
||||||
|
|
||||||
|
bool deleted = false;
|
||||||
|
FuriString* file_path;
|
||||||
|
file_path = furi_string_alloc();
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Delete original file
|
||||||
|
if(use_load_path && !furi_string_empty(dev->load_path)) {
|
||||||
|
furi_string_set(file_path, dev->load_path);
|
||||||
|
} else {
|
||||||
|
furi_string_printf(file_path, APP_DATA_PATH("%s%s"), dev->dev_name, UHF_APP_EXTENSION);
|
||||||
|
}
|
||||||
|
if(!storage_simply_remove(dev->storage, furi_string_get_cstr(file_path))) break;
|
||||||
|
deleted = true;
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
if(!deleted) {
|
||||||
|
dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_string_free(file_path);
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_device_set_loading_callback(UHFDevice* dev, UHFLoadingCallback callback, void* context) {
|
||||||
|
furi_assert(dev);
|
||||||
|
|
||||||
|
dev->loading_cb = callback;
|
||||||
|
dev->loading_cb_ctx = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReturnCode picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) {
|
||||||
|
// uint8_t key[32] = {0};
|
||||||
|
// memcpy(key, picopass_iclass_decryptionkey, sizeof(picopass_iclass_decryptionkey));
|
||||||
|
// mbedtls_des3_context ctx;
|
||||||
|
// mbedtls_des3_init(&ctx);
|
||||||
|
// mbedtls_des3_set2key_dec(&ctx, key);
|
||||||
|
// mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
|
||||||
|
// mbedtls_des3_free(&ctx);
|
||||||
|
// return ERR_NONE;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) {
|
||||||
|
// ReturnCode err;
|
||||||
|
|
||||||
|
// pacs->biometrics = AA1[6].data[4];
|
||||||
|
// pacs->pin_length = AA1[6].data[6] & 0x0F;
|
||||||
|
// pacs->encryption = AA1[6].data[7];
|
||||||
|
|
||||||
|
// if(pacs->encryption == PicopassDeviceEncryption3DES) {
|
||||||
|
// FURI_LOG_D(TAG, "3DES Encrypted");
|
||||||
|
// err = picopass_device_decrypt(AA1[7].data, pacs->credential);
|
||||||
|
// if(err != ERR_NONE) {
|
||||||
|
// FURI_LOG_E(TAG, "decrypt error %d", err);
|
||||||
|
// return err;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// err = picopass_device_decrypt(AA1[8].data, pacs->pin0);
|
||||||
|
// if(err != ERR_NONE) {
|
||||||
|
// FURI_LOG_E(TAG, "decrypt error %d", err);
|
||||||
|
// return err;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// err = picopass_device_decrypt(AA1[9].data, pacs->pin1);
|
||||||
|
// if(err != ERR_NONE) {
|
||||||
|
// FURI_LOG_E(TAG, "decrypt error %d", err);
|
||||||
|
// return err;
|
||||||
|
// }
|
||||||
|
// } else if(pacs->encryption == PicopassDeviceEncryptionNone) {
|
||||||
|
// FURI_LOG_D(TAG, "No Encryption");
|
||||||
|
// memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN);
|
||||||
|
// memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN);
|
||||||
|
// memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN);
|
||||||
|
// } else if(pacs->encryption == PicopassDeviceEncryptionDES) {
|
||||||
|
// FURI_LOG_D(TAG, "DES Encrypted");
|
||||||
|
// } else {
|
||||||
|
// FURI_LOG_D(TAG, "Unknown encryption");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pacs->sio = (AA1[10].data[0] == 0x30); // rough check
|
||||||
|
|
||||||
|
// return ERR_NONE;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record) {
|
||||||
|
// uint32_t* halves = (uint32_t*)data;
|
||||||
|
// if(halves[0] == 0) {
|
||||||
|
// uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1]));
|
||||||
|
// record->bitLength = 31 - leading0s;
|
||||||
|
// } else {
|
||||||
|
// uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0]));
|
||||||
|
// record->bitLength = 63 - leading0s;
|
||||||
|
// }
|
||||||
|
// FURI_LOG_D(TAG, "bitLength: %d", record->bitLength);
|
||||||
|
|
||||||
|
// if(record->bitLength == 26) {
|
||||||
|
// uint8_t* v4 = data + 4;
|
||||||
|
// uint32_t bot = v4[3] | (v4[2] << 8) | (v4[1] << 16) | (v4[0] << 24);
|
||||||
|
|
||||||
|
// record->CardNumber = (bot >> 1) & 0xFFFF;
|
||||||
|
// record->FacilityCode = (bot >> 17) & 0xFF;
|
||||||
|
// FURI_LOG_D(TAG, "FC: %u CN: %u", record->FacilityCode, record->CardNumber);
|
||||||
|
// record->valid = true;
|
||||||
|
// } else {
|
||||||
|
// record->CardNumber = 0;
|
||||||
|
// record->FacilityCode = 0;
|
||||||
|
// record->valid = false;
|
||||||
|
// }
|
||||||
|
// return ERR_NONE;
|
||||||
|
// }
|
||||||
54
applications/external/uhf_rfid/uhf_device.h
vendored
Normal file
54
applications/external/uhf_rfid/uhf_device.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <storage/storage.h>
|
||||||
|
#include <dialogs/dialogs.h>
|
||||||
|
#include <mbedtls/des.h>
|
||||||
|
#include "uhf_tag.h"
|
||||||
|
|
||||||
|
#define UHF_DEV_NAME_MAX_LEN 22
|
||||||
|
#define UHF_EPC_BANK_LENGTH_LABEL "EPC_LENGTH"
|
||||||
|
#define UHF_TID_BANK_LENGTH_LABEL "TID_LENGTH"
|
||||||
|
#define UHF_USER_BANK_LENGTH_LABEL "USER_LENGTH"
|
||||||
|
#define UHF_EPC_PC_LABEL "PC"
|
||||||
|
#define UHF_EPC_CRC_LABEL "CRC"
|
||||||
|
#define UHF_RFU_BANK_LABEL "RFU"
|
||||||
|
#define UHF_EPC_BANK_LABEL "EPC"
|
||||||
|
#define UHF_TID_BANK_LABEL "TID"
|
||||||
|
#define UHF_USER_BANK_LABEL "USER"
|
||||||
|
|
||||||
|
#define UHF_APP_EXTENSION ".uhf"
|
||||||
|
|
||||||
|
typedef void (*UHFLoadingCallback)(void* context, bool state);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Storage* storage;
|
||||||
|
DialogsApp* dialogs;
|
||||||
|
UHFTagWrapper* uhf_tag_wrapper;
|
||||||
|
char dev_name[UHF_DEV_NAME_MAX_LEN + 1];
|
||||||
|
FuriString* load_path;
|
||||||
|
UHFLoadingCallback loading_cb;
|
||||||
|
void* loading_cb_ctx;
|
||||||
|
} UHFDevice;
|
||||||
|
|
||||||
|
UHFDevice* uhf_device_alloc();
|
||||||
|
|
||||||
|
void uhf_device_free(UHFDevice* uhf_dev);
|
||||||
|
|
||||||
|
void uhf_device_set_name(UHFDevice* dev, const char* name);
|
||||||
|
|
||||||
|
bool uhf_device_save(UHFDevice* dev, const char* dev_name);
|
||||||
|
|
||||||
|
bool uhf_file_select(UHFDevice* dev);
|
||||||
|
|
||||||
|
// void uhf_device_data_clear(PicopassDeviceData* dev_data);
|
||||||
|
|
||||||
|
void uhf_device_clear(UHFDevice* dev);
|
||||||
|
|
||||||
|
bool uhf_device_delete(UHFDevice* dev, bool use_load_path);
|
||||||
|
|
||||||
|
void uhf_device_set_loading_callback(UHFDevice* dev, UHFLoadingCallback callback, void* context);
|
||||||
|
|
||||||
|
// ReturnCode uhf_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs);
|
||||||
|
// ReturnCode uhf_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record);
|
||||||
388
applications/external/uhf_rfid/uhf_module.c
vendored
Normal file
388
applications/external/uhf_rfid/uhf_module.c
vendored
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
#include "uhf_module.h"
|
||||||
|
#include "uhf_module_cmd.h"
|
||||||
|
|
||||||
|
#define DELAY_MS 100
|
||||||
|
#define WAIT_TICK 8000 // max wait time in between each byte
|
||||||
|
|
||||||
|
volatile uint16_t tick = 0;
|
||||||
|
|
||||||
|
void rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
|
||||||
|
UNUSED(event);
|
||||||
|
Buffer* buffer = ctx;
|
||||||
|
if(buffer->closed) return; // buffer closed
|
||||||
|
buffer_append_single(buffer, data); // append data
|
||||||
|
if(data == FRAME_END) buffer_close(buffer); // end of frame
|
||||||
|
tick = WAIT_TICK; // reset tick
|
||||||
|
}
|
||||||
|
|
||||||
|
static M100ResponseType setup_and_send_rx(M100Module* module, uint8_t* cmd, size_t cmd_length) {
|
||||||
|
buffer_reset(module->buf);
|
||||||
|
tick = WAIT_TICK;
|
||||||
|
furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, cmd_length);
|
||||||
|
while(--tick) {
|
||||||
|
furi_delay_us(5);
|
||||||
|
}
|
||||||
|
buffer_close(module->buf);
|
||||||
|
// Validation Checks
|
||||||
|
uint8_t* data = buffer_get_data(module->buf);
|
||||||
|
size_t length = buffer_get_size(module->buf);
|
||||||
|
// check if size > 0
|
||||||
|
if(!length) return M100EmptyResponse;
|
||||||
|
// check if data is valid
|
||||||
|
if(data[0] != FRAME_START || data[length - 1] != FRAME_END) return M100ValidationFail;
|
||||||
|
// check if checksum is correct
|
||||||
|
if(checksum(data + 1, length - 3) != data[length - 2]) return M100ChecksumFail;
|
||||||
|
return M100SuccessResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
M100ModuleInfo* m100_module_info_alloc() {
|
||||||
|
M100ModuleInfo* module_info = (M100ModuleInfo*)malloc(sizeof(M100ModuleInfo));
|
||||||
|
return module_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m100_module_info_free(M100ModuleInfo* module_info) {
|
||||||
|
free(module_info->hw_version);
|
||||||
|
free(module_info->sw_version);
|
||||||
|
free(module_info->manufacturer);
|
||||||
|
free(module_info);
|
||||||
|
}
|
||||||
|
M100Module* m100_module_alloc() {
|
||||||
|
M100Module* module = (M100Module*)malloc(sizeof(M100Module));
|
||||||
|
module->info = m100_module_info_alloc();
|
||||||
|
module->buf = buffer_alloc(MAX_BUFFER_SIZE);
|
||||||
|
module->baudrate = DEFAULT_BAUDRATE;
|
||||||
|
module->transmitting_power = DEFAULT_TRANSMITTING_POWER;
|
||||||
|
module->region = DEFAULT_WORKING_REGION;
|
||||||
|
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m100_module_free(M100Module* module) {
|
||||||
|
m100_module_info_free(module->info);
|
||||||
|
buffer_free(module->buf);
|
||||||
|
free(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t checksum(const uint8_t* data, size_t length) {
|
||||||
|
// CheckSum8 Modulo 256
|
||||||
|
// Sum of Bytes % 256
|
||||||
|
uint64_t sum_val = 0x00;
|
||||||
|
for(size_t i = 0; i < length; i++) {
|
||||||
|
sum_val += data[i];
|
||||||
|
}
|
||||||
|
return (uint8_t)(sum_val % 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t crc16_genibus(const uint8_t* data, size_t length) {
|
||||||
|
uint16_t crc = 0xFFFF; // Initial value
|
||||||
|
uint16_t polynomial = 0x1021; // CRC-16/GENIBUS polynomial
|
||||||
|
|
||||||
|
for(size_t i = 0; i < length; i++) {
|
||||||
|
crc ^= (data[i] << 8); // Move byte into MSB of 16bit CRC
|
||||||
|
for(int j = 0; j < 8; j++) {
|
||||||
|
if(crc & 0x8000) {
|
||||||
|
crc = (crc << 1) ^ polynomial;
|
||||||
|
} else {
|
||||||
|
crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc ^ 0xFFFF; // Post-inversion
|
||||||
|
}
|
||||||
|
|
||||||
|
char* _m100_info_helper(M100Module* module, char** info) {
|
||||||
|
if(!buffer_get_size(module->buf)) return NULL;
|
||||||
|
uint8_t* data = buffer_get_data(module->buf);
|
||||||
|
uint16_t payload_len = data[3];
|
||||||
|
payload_len = (payload_len << 8) + data[4];
|
||||||
|
FuriString* temp_str = furi_string_alloc();
|
||||||
|
for(int i = 0; i < payload_len; i++) {
|
||||||
|
furi_string_cat_printf(temp_str, "%c", data[6 + i]);
|
||||||
|
}
|
||||||
|
if(*info == NULL) {
|
||||||
|
*info = (char*)malloc(sizeof(char) * payload_len);
|
||||||
|
} else {
|
||||||
|
for(size_t i = 0; i < strlen(*info); i++) {
|
||||||
|
(*info)[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(*info, furi_string_get_cstr(temp_str), payload_len);
|
||||||
|
furi_string_free(temp_str);
|
||||||
|
return *info;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* m100_get_hardware_version(M100Module* module) {
|
||||||
|
setup_and_send_rx(module, (uint8_t*)&CMD_HW_VERSION.cmd[0], CMD_HW_VERSION.length);
|
||||||
|
return _m100_info_helper(module, &module->info->hw_version);
|
||||||
|
}
|
||||||
|
char* m100_get_software_version(M100Module* module) {
|
||||||
|
setup_and_send_rx(module, (uint8_t*)&CMD_SW_VERSION.cmd[0], CMD_SW_VERSION.length);
|
||||||
|
return _m100_info_helper(module, &module->info->sw_version);
|
||||||
|
}
|
||||||
|
char* m100_get_manufacturers(M100Module* module) {
|
||||||
|
setup_and_send_rx(module, (uint8_t*)&CMD_MANUFACTURERS.cmd[0], CMD_MANUFACTURERS.length);
|
||||||
|
return _m100_info_helper(module, &module->info->manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
M100ResponseType m100_single_poll(M100Module* module, UHFTag* uhf_tag) {
|
||||||
|
M100ResponseType rp_type =
|
||||||
|
setup_and_send_rx(module, (uint8_t*)&CMD_SINGLE_POLLING.cmd[0], CMD_SINGLE_POLLING.length);
|
||||||
|
if(rp_type != M100SuccessResponse) return rp_type;
|
||||||
|
uint8_t* data = buffer_get_data(module->buf);
|
||||||
|
size_t length = buffer_get_size(module->buf);
|
||||||
|
uint16_t pc = data[6];
|
||||||
|
uint16_t crc = 0;
|
||||||
|
// mask out epc length from protocol control
|
||||||
|
size_t epc_len = pc;
|
||||||
|
epc_len >>= 3;
|
||||||
|
epc_len *= 2;
|
||||||
|
// get protocol control
|
||||||
|
pc <<= 8;
|
||||||
|
pc += data[7];
|
||||||
|
// get cyclic redundency check
|
||||||
|
crc = data[8 + epc_len];
|
||||||
|
crc <<= 8;
|
||||||
|
crc += data[8 + epc_len + 1];
|
||||||
|
// validate checksum
|
||||||
|
if(checksum(data + 1, length - 3) != data[length - 2]) return M100ValidationFail;
|
||||||
|
// validate crc
|
||||||
|
if(crc16_genibus(data + 6, epc_len + 2) != crc) return M100ValidationFail;
|
||||||
|
uhf_tag_set_epc_pc(uhf_tag, pc);
|
||||||
|
uhf_tag_set_epc_crc(uhf_tag, crc);
|
||||||
|
uhf_tag_set_epc(uhf_tag, data + 8, epc_len);
|
||||||
|
return M100SuccessResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
M100ResponseType m100_set_select(M100Module* module, UHFTag* uhf_tag) {
|
||||||
|
// Set select
|
||||||
|
uint8_t cmd[MAX_BUFFER_SIZE];
|
||||||
|
size_t cmd_length = CMD_SET_SELECT_PARAMETER.length;
|
||||||
|
size_t mask_length_bytes = uhf_tag->epc->size;
|
||||||
|
size_t mask_length_bits = mask_length_bytes * 8;
|
||||||
|
// payload len == sel param len + ptr len + mask len + epc len
|
||||||
|
size_t payload_len = 7 + mask_length_bytes;
|
||||||
|
memcpy(cmd, CMD_SET_SELECT_PARAMETER.cmd, cmd_length);
|
||||||
|
// set new length
|
||||||
|
cmd_length = 12 + mask_length_bytes + 2;
|
||||||
|
// set payload length
|
||||||
|
cmd[3] = (payload_len >> 8) & 0xFF;
|
||||||
|
cmd[4] = payload_len & 0xFF;
|
||||||
|
// set select param
|
||||||
|
cmd[5] = 0x01; // 0x00=rfu, 0x01=epc, 0x10=tid, 0x11=user
|
||||||
|
// set ptr
|
||||||
|
cmd[9] = 0x20; // epc data begins after 0x20
|
||||||
|
// set mask length
|
||||||
|
cmd[10] = mask_length_bits;
|
||||||
|
// truncate
|
||||||
|
cmd[11] = false;
|
||||||
|
// set mask
|
||||||
|
memcpy((void*)&cmd[12], uhf_tag->epc->data, mask_length_bytes);
|
||||||
|
|
||||||
|
// set checksum
|
||||||
|
cmd[cmd_length - 2] = checksum(cmd + 1, 11 + mask_length_bytes);
|
||||||
|
// end frame
|
||||||
|
cmd[cmd_length - 1] = FRAME_END;
|
||||||
|
|
||||||
|
setup_and_send_rx(module, cmd, 12 + mask_length_bytes + 3);
|
||||||
|
|
||||||
|
uint8_t* data = buffer_get_data(module->buf);
|
||||||
|
if(checksum(data + 1, 5) != data[6]) return M100ValidationFail; // error in rx
|
||||||
|
if(data[5] != 0x00) return M100ValidationFail; // error if not 0
|
||||||
|
|
||||||
|
return M100SuccessResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
UHFTag* m100_get_select_param(M100Module* module) {
|
||||||
|
buffer_reset(module->buf);
|
||||||
|
furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, rx_callback, module->buf);
|
||||||
|
furi_hal_uart_tx(
|
||||||
|
FuriHalUartIdUSART1,
|
||||||
|
(uint8_t*)&CMD_GET_SELECT_PARAMETER.cmd,
|
||||||
|
CMD_GET_SELECT_PARAMETER.length);
|
||||||
|
furi_delay_ms(DELAY_MS);
|
||||||
|
// UHFTag* uhf_tag = uhf_tag_alloc();
|
||||||
|
// uint8_t* data = buffer_get_data(module->buf);
|
||||||
|
// size_t mask_length =
|
||||||
|
// uhf_tag_set_epc(uhf_tag, data + 12, )
|
||||||
|
// TODO : implement
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
M100ResponseType m100_read_label_data_storage(
|
||||||
|
M100Module* module,
|
||||||
|
UHFTag* uhf_tag,
|
||||||
|
BankType bank,
|
||||||
|
uint32_t access_pwd,
|
||||||
|
uint16_t word_count) {
|
||||||
|
/*
|
||||||
|
Will probably remove UHFTag as param and get it from get selected tag
|
||||||
|
*/
|
||||||
|
if(bank == EPCBank) return M100SuccessResponse;
|
||||||
|
uint8_t cmd[MAX_BUFFER_SIZE];
|
||||||
|
size_t cmd_length = CMD_READ_LABEL_DATA_STORAGE_AREA.length;
|
||||||
|
memcpy(cmd, CMD_READ_LABEL_DATA_STORAGE_AREA.cmd, cmd_length);
|
||||||
|
// set access password
|
||||||
|
cmd[5] = (access_pwd >> 24) & 0xFF;
|
||||||
|
cmd[6] = (access_pwd >> 16) & 0xFF;
|
||||||
|
cmd[7] = (access_pwd >> 8) & 0xFF;
|
||||||
|
cmd[8] = access_pwd & 0xFF;
|
||||||
|
// set mem bank
|
||||||
|
cmd[9] = (uint8_t)bank;
|
||||||
|
// set word counter
|
||||||
|
cmd[12] = (word_count >> 8) & 0xFF;
|
||||||
|
cmd[13] = word_count & 0xFF;
|
||||||
|
// calc checksum
|
||||||
|
cmd[cmd_length - 2] = checksum(cmd + 1, cmd_length - 3);
|
||||||
|
|
||||||
|
M100ResponseType rp_type = setup_and_send_rx(module, cmd, cmd_length);
|
||||||
|
if(rp_type != M100SuccessResponse) return rp_type;
|
||||||
|
|
||||||
|
uint8_t* data = buffer_get_data(module->buf);
|
||||||
|
|
||||||
|
uint8_t rtn_command = data[2];
|
||||||
|
uint16_t payload_len = data[3];
|
||||||
|
payload_len = (payload_len << 8) + data[4];
|
||||||
|
|
||||||
|
if(rtn_command == 0xFF) {
|
||||||
|
if(payload_len == 0x01) return M100NoTagResponse;
|
||||||
|
return M100MemoryOverrun;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ptr_offset = 5 /*<-ptr offset*/ + uhf_tag_get_epc_size(uhf_tag) + 3 /*<-pc + ul*/;
|
||||||
|
size_t bank_data_length = payload_len - (ptr_offset - 5 /*dont include the offset*/);
|
||||||
|
|
||||||
|
if(bank == TIDBank) {
|
||||||
|
uhf_tag_set_tid(uhf_tag, data + ptr_offset, bank_data_length);
|
||||||
|
} else if(bank == UserBank) {
|
||||||
|
uhf_tag_set_user(uhf_tag, data + ptr_offset, bank_data_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return M100SuccessResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
M100ResponseType m100_write_label_data_storage(
|
||||||
|
M100Module* module,
|
||||||
|
UHFTag* saved_tag,
|
||||||
|
UHFTag* selected_tag,
|
||||||
|
BankType bank,
|
||||||
|
uint16_t source_address,
|
||||||
|
uint32_t access_pwd) {
|
||||||
|
uint8_t cmd[MAX_BUFFER_SIZE];
|
||||||
|
size_t cmd_length = CMD_WRITE_LABEL_DATA_STORE.length;
|
||||||
|
memcpy(cmd, CMD_WRITE_LABEL_DATA_STORE.cmd, cmd_length);
|
||||||
|
uint16_t payload_len = 9;
|
||||||
|
uint16_t data_length = 0;
|
||||||
|
if(bank == ReservedBank) {
|
||||||
|
// access pwd len + kill pwd len
|
||||||
|
payload_len += 4;
|
||||||
|
data_length = 4;
|
||||||
|
} else if(bank == EPCBank) {
|
||||||
|
// epc len + pc len
|
||||||
|
payload_len += 4 + uhf_tag_get_epc_size(saved_tag);
|
||||||
|
data_length = 4 + uhf_tag_get_epc_size(saved_tag);
|
||||||
|
// set data
|
||||||
|
uint8_t tmp_arr[4];
|
||||||
|
tmp_arr[0] = (uint8_t)((uhf_tag_get_epc_crc(selected_tag) >> 8) & 0xFF);
|
||||||
|
tmp_arr[1] = (uint8_t)(uhf_tag_get_epc_crc(selected_tag) & 0xFF);
|
||||||
|
tmp_arr[2] = (uint8_t)((uhf_tag_get_epc_pc(saved_tag) >> 8) & 0xFF);
|
||||||
|
tmp_arr[3] = (uint8_t)(uhf_tag_get_epc_pc(saved_tag) & 0xFF);
|
||||||
|
memcpy(cmd + 14, tmp_arr, 4);
|
||||||
|
memcpy(cmd + 18, uhf_tag_get_epc(saved_tag), uhf_tag_get_epc_size(saved_tag));
|
||||||
|
} else if(bank == UserBank) {
|
||||||
|
payload_len += uhf_tag_get_user_size(saved_tag);
|
||||||
|
data_length = uhf_tag_get_user_size(saved_tag);
|
||||||
|
// set data
|
||||||
|
memcpy(cmd + 14, uhf_tag_get_user(saved_tag), uhf_tag_get_user_size(saved_tag));
|
||||||
|
}
|
||||||
|
// set payload length
|
||||||
|
cmd[3] = (payload_len >> 8) & 0xFF;
|
||||||
|
cmd[4] = payload_len & 0xFF;
|
||||||
|
// set access password
|
||||||
|
cmd[5] = (access_pwd >> 24) & 0xFF;
|
||||||
|
cmd[6] = (access_pwd >> 16) & 0xFF;
|
||||||
|
cmd[7] = (access_pwd >> 8) & 0xFF;
|
||||||
|
cmd[8] = access_pwd & 0xFF;
|
||||||
|
// set membank
|
||||||
|
cmd[9] = (uint8_t)bank;
|
||||||
|
// set source address
|
||||||
|
cmd[10] = (source_address >> 8) & 0xFF;
|
||||||
|
cmd[11] = source_address & 0xFF;
|
||||||
|
// set data length
|
||||||
|
size_t data_length_words = data_length / 2;
|
||||||
|
cmd[12] = (data_length_words >> 8) & 0xFF;
|
||||||
|
cmd[13] = data_length_words & 0xFF;
|
||||||
|
// update cmd len
|
||||||
|
cmd_length = 7 + payload_len;
|
||||||
|
// calculate checksum
|
||||||
|
cmd[cmd_length - 2] = checksum(cmd + 1, cmd_length - 3);
|
||||||
|
cmd[cmd_length - 1] = FRAME_END;
|
||||||
|
// send cmd
|
||||||
|
// furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
|
||||||
|
// furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, cmd_length);
|
||||||
|
// unsigned int delay = DELAY_MS / 2;
|
||||||
|
// unsigned int timeout = 15;
|
||||||
|
// while(!buffer_get_size(module->buf)) {
|
||||||
|
// furi_delay_ms(delay);
|
||||||
|
// if(!timeout--) break;
|
||||||
|
// }
|
||||||
|
setup_and_send_rx(module, cmd, cmd_length);
|
||||||
|
uint8_t* buff_data = buffer_get_data(module->buf);
|
||||||
|
size_t buff_length = buffer_get_size(module->buf);
|
||||||
|
if(buff_data[2] == 0xFF && buff_length == 8)
|
||||||
|
return M100NoTagResponse;
|
||||||
|
else if(buff_data[2] == 0xFF)
|
||||||
|
return M100ValidationFail;
|
||||||
|
return M100SuccessResponse;
|
||||||
|
}
|
||||||
|
void m100_set_baudrate(M100Module* module, uint32_t baudrate) {
|
||||||
|
size_t length = CMD_SET_COMMUNICATION_BAUD_RATE.length;
|
||||||
|
uint8_t cmd[length];
|
||||||
|
memcpy(cmd, CMD_SET_COMMUNICATION_BAUD_RATE.cmd, length);
|
||||||
|
uint16_t br_mod = baudrate / 100; // module format
|
||||||
|
cmd[6] = 0xFF & br_mod; // pow LSB
|
||||||
|
cmd[5] = 0xFF & (br_mod >> 8); // pow MSB
|
||||||
|
cmd[length - 2] = checksum(cmd + 1, length - 3);
|
||||||
|
furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, length);
|
||||||
|
furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate);
|
||||||
|
module->baudrate = baudrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool m100_set_working_region(M100Module* module, WorkingRegion region) {
|
||||||
|
size_t length = CMD_SET_WORK_AREA.length;
|
||||||
|
uint8_t cmd[length];
|
||||||
|
memcpy(cmd, CMD_SET_WORK_AREA.cmd, length);
|
||||||
|
cmd[5] = (uint8_t)region;
|
||||||
|
cmd[length - 2] = checksum(cmd + 1, length - 3);
|
||||||
|
setup_and_send_rx(module, cmd, length);
|
||||||
|
module->region = region;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool m100_set_transmitting_power(M100Module* module, uint16_t power) {
|
||||||
|
size_t length = CMD_SET_TRANSMITTING_POWER.length;
|
||||||
|
uint8_t cmd[length];
|
||||||
|
memcpy(cmd, CMD_SET_TRANSMITTING_POWER.cmd, length);
|
||||||
|
cmd[5] = (power >> 8) & 0xFF;
|
||||||
|
cmd[6] = power & 0xFF;
|
||||||
|
cmd[length - 2] = checksum(cmd + 1, length - 3);
|
||||||
|
setup_and_send_rx(module, cmd, length);
|
||||||
|
module->transmitting_power = power;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool m100_set_freq_hopping(M100Module* module, bool hopping) {
|
||||||
|
UNUSED(module);
|
||||||
|
UNUSED(hopping);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool m100_set_power(M100Module* module, uint8_t* power) {
|
||||||
|
UNUSED(module);
|
||||||
|
UNUSED(power);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t m100_get_baudrate(M100Module* module) {
|
||||||
|
return module->baudrate;
|
||||||
|
}
|
||||||
82
applications/external/uhf_rfid/uhf_module.h
vendored
Normal file
82
applications/external/uhf_rfid/uhf_module.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
#include "uhf_tag.h"
|
||||||
|
#include "uhf_buffer.h"
|
||||||
|
#include "uhf_tag.h"
|
||||||
|
#include <furi_hal.h>
|
||||||
|
#include "uhf_module_settings.h"
|
||||||
|
|
||||||
|
#define FRAME_START 0xBB
|
||||||
|
#define FRAME_END 0x7E
|
||||||
|
#define DEFAULT_BAUDRATE BAUD_RATES[BAUD_RATES_COUNT - 1]
|
||||||
|
#define DEFAULT_TRANSMITTING_POWER POWER_DBM[POWER_DBM_COUNT - 1]
|
||||||
|
#define DEFAULT_WORKING_REGION WR_US
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* hw_version;
|
||||||
|
char* sw_version;
|
||||||
|
char* manufacturer;
|
||||||
|
} M100ModuleInfo;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
M100SuccessResponse,
|
||||||
|
M100ValidationFail,
|
||||||
|
M100NoTagResponse,
|
||||||
|
M100MemoryOverrun,
|
||||||
|
M100EmptyResponse,
|
||||||
|
M100ChecksumFail
|
||||||
|
} M100ResponseType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
M100ModuleInfo* info;
|
||||||
|
uint32_t baudrate;
|
||||||
|
WorkingRegion region;
|
||||||
|
uint16_t region_frequency;
|
||||||
|
uint16_t transmitting_power;
|
||||||
|
bool freq_hopping;
|
||||||
|
Buffer* buf;
|
||||||
|
} M100Module;
|
||||||
|
|
||||||
|
M100ModuleInfo* m100_module_info_alloc();
|
||||||
|
void m100_module_info_free(M100ModuleInfo* module_info);
|
||||||
|
|
||||||
|
M100Module* m100_module_alloc();
|
||||||
|
void m100_module_free(M100Module* module);
|
||||||
|
uint16_t crc16_genibus(const uint8_t* data, size_t length);
|
||||||
|
uint8_t checksum(const uint8_t* data, size_t length);
|
||||||
|
uint8_t get_baudrate_count();
|
||||||
|
|
||||||
|
// Function prototypes
|
||||||
|
char* m100_get_hardware_version(M100Module* module);
|
||||||
|
char* m100_get_software_version(M100Module* module);
|
||||||
|
char* m100_get_manufacturers(M100Module* module);
|
||||||
|
|
||||||
|
void m100_set_baudrate(M100Module* module, uint32_t baudrate);
|
||||||
|
bool m100_set_working_region(M100Module* module, WorkingRegion region);
|
||||||
|
bool m100_set_transmitting_power(M100Module* module, uint16_t power);
|
||||||
|
bool m100_set_freq_hopping(M100Module* module, bool hopping);
|
||||||
|
bool m100_set_power(M100Module* module, uint8_t* power);
|
||||||
|
|
||||||
|
// gen2 cmds
|
||||||
|
M100ResponseType m100_single_poll(M100Module* module, UHFTag* uhf_tag);
|
||||||
|
M100ResponseType m100_set_select(M100Module* module, UHFTag* uhf_tag);
|
||||||
|
M100ResponseType m100_read_label_data_storage(
|
||||||
|
M100Module* module,
|
||||||
|
UHFTag* uhf_tag,
|
||||||
|
BankType bank,
|
||||||
|
uint32_t access_pwd,
|
||||||
|
uint16_t word_count);
|
||||||
|
|
||||||
|
M100ResponseType m100_write_label_data_storage(
|
||||||
|
M100Module* module,
|
||||||
|
UHFTag* saved_tag,
|
||||||
|
UHFTag* selected_tag,
|
||||||
|
BankType bank,
|
||||||
|
uint16_t source_address,
|
||||||
|
uint32_t access_pwd);
|
||||||
|
|
||||||
|
uint32_t m100_get_baudrate(M100Module* module);
|
||||||
50
applications/external/uhf_rfid/uhf_module_cmd.h
vendored
Normal file
50
applications/external/uhf_rfid/uhf_module_cmd.h
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const uint8_t* cmd;
|
||||||
|
size_t length;
|
||||||
|
} Command;
|
||||||
|
|
||||||
|
// Define the command data arrays
|
||||||
|
static const uint8_t CMD_HW_VERSION_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x7E};
|
||||||
|
static const uint8_t CMD_SW_VERSION_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x01, 0x05, 0x7E};
|
||||||
|
static const uint8_t CMD_MANUFACTURERS_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x02, 0x06, 0x7E};
|
||||||
|
static const uint8_t CMD_SINGLE_POLLING_DATA[] = {0xBB, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7E};
|
||||||
|
static const uint8_t CMD_MULTIPLE_POLLING_DATA[] = {0xBB, 0x00, 0x27, 0x00, 0x03, 0x22, 0x27, 0x10, 0x83, 0x7E};
|
||||||
|
static const uint8_t CMD_STOP_MULTIPLE_POLLING_DATA[] = {0xBB, 0x00, 0x28, 0x00, 0x00, 0x28, 0x7E};
|
||||||
|
static const uint8_t CMD_SET_SELECT_PARAMETER_DATA[] = {0xBB, 0x00, 0x0C, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x20, 0x60, 0x00, 0x30, 0x75, 0x1F, 0xEB, 0x70, 0x5C, 0x59, 0x04, 0xE3, 0xD5, 0x0D, 0x70, 0xAD, 0x7E};
|
||||||
|
static const uint8_t CMD_GET_SELECT_PARAMETER_DATA[] = {0xBB, 0x00, 0x0B, 0x00, 0x00, 0x0B, 0x7E};
|
||||||
|
static const uint8_t CMD_SET_SELECT_MODE_DATA[] = {0xBB, 0x00, 0x12, 0x00, 0x01, 0x01, 0x14, 0x7E};
|
||||||
|
static const uint8_t CMD_READ_LABEL_DATA_STORAGE_AREA_DATA[] = {0xBB, 0x00, 0x39, 0x00, 0x09, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x45, 0x7E};
|
||||||
|
static const uint8_t CMD_WRITE_LABEL_DATA_STORE_DATA[] = {0xBB, 0x00, 0x49, 0x00, 0x0D, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x12, 0x34, 0x56, 0x78, 0x6D, 0x7E};
|
||||||
|
static const uint8_t CMD_LOCK_LABEL_DATA_STORE_DATA[] = {0xBB, 0x00, 0x82, 0x00, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x80, 0x09, 0x7E};
|
||||||
|
static const uint8_t CMD_INACTIVATE_KILL_TAG_DATA[] = {0xBB, 0x00, 0x65, 0x00, 0x04, 0x00, 0x00, 0xFF, 0xFF, 0x67, 0x7E};
|
||||||
|
static const uint8_t CMD_SET_COMMUNICATION_BAUD_RATE_DATA[] = {0xBB, 0x00, 0x11, 0x00, 0x02, 0x00, 0xC0, 0xD3, 0x7E};
|
||||||
|
static const uint8_t CMD_GET_QUERY_PARAMETERS_DATA[] = {0xBB, 0x00, 0x0D, 0x00, 0x00, 0x0D, 0x7E};
|
||||||
|
static const uint8_t CMD_SET_QUERY_PARAMETER_DATA[] = {0xBB, 0x00, 0x0E, 0x00, 0x02, 0x10, 0x20, 0x40, 0x7E};
|
||||||
|
static const uint8_t CMD_SET_WORK_AREA_DATA[] = {0xBB, 0x00, 0x07, 0x00, 0x01, 0x01, 0x09, 0x7E};
|
||||||
|
static const uint8_t CMD_SET_TRANSMITTING_POWER_DATA[] = {0xBB, 0x00, 0xB6, 0x00, 0x02, 0x07, 0xD0, 0x8F, 0x7E};
|
||||||
|
|
||||||
|
|
||||||
|
// Define the Command structs
|
||||||
|
static const Command CMD_HW_VERSION = {CMD_HW_VERSION_DATA, sizeof(CMD_HW_VERSION_DATA)};
|
||||||
|
static const Command CMD_SW_VERSION = {CMD_SW_VERSION_DATA, sizeof(CMD_SW_VERSION_DATA)};
|
||||||
|
static const Command CMD_MANUFACTURERS = {CMD_MANUFACTURERS_DATA, sizeof(CMD_MANUFACTURERS_DATA)};
|
||||||
|
static const Command CMD_SINGLE_POLLING = {CMD_SINGLE_POLLING_DATA, sizeof(CMD_SINGLE_POLLING_DATA)};
|
||||||
|
static const Command CMD_MULTIPLE_POLLING = {CMD_MULTIPLE_POLLING_DATA, sizeof(CMD_MULTIPLE_POLLING_DATA)};
|
||||||
|
static const Command CMD_STOP_MULTIPLE_POLLING = {CMD_STOP_MULTIPLE_POLLING_DATA, sizeof(CMD_STOP_MULTIPLE_POLLING_DATA)};
|
||||||
|
static const Command CMD_SET_SELECT_PARAMETER = {CMD_SET_SELECT_PARAMETER_DATA, sizeof(CMD_SET_SELECT_PARAMETER_DATA)};
|
||||||
|
static const Command CMD_GET_SELECT_PARAMETER = {CMD_GET_SELECT_PARAMETER_DATA, sizeof(CMD_GET_SELECT_PARAMETER_DATA)};
|
||||||
|
static const Command CMD_SET_SELECT_MODE = {CMD_SET_SELECT_MODE_DATA, sizeof(CMD_SET_SELECT_MODE_DATA)};
|
||||||
|
static const Command CMD_READ_LABEL_DATA_STORAGE_AREA = {CMD_READ_LABEL_DATA_STORAGE_AREA_DATA, sizeof(CMD_READ_LABEL_DATA_STORAGE_AREA_DATA)};
|
||||||
|
static const Command CMD_WRITE_LABEL_DATA_STORE = {CMD_WRITE_LABEL_DATA_STORE_DATA, sizeof(CMD_WRITE_LABEL_DATA_STORE_DATA)};
|
||||||
|
static const Command CMD_LOCK_LABEL_DATA_STORE = {CMD_LOCK_LABEL_DATA_STORE_DATA, sizeof(CMD_LOCK_LABEL_DATA_STORE_DATA)};
|
||||||
|
static const Command CMD_INACTIVATE_KILL_TAG = {CMD_INACTIVATE_KILL_TAG_DATA, sizeof(CMD_INACTIVATE_KILL_TAG_DATA)};
|
||||||
|
static const Command CMD_SET_COMMUNICATION_BAUD_RATE = {CMD_SET_COMMUNICATION_BAUD_RATE_DATA, sizeof(CMD_SET_COMMUNICATION_BAUD_RATE_DATA)};
|
||||||
|
static const Command CMD_GET_QUERY_PARAMETERS = {CMD_GET_QUERY_PARAMETERS_DATA, sizeof(CMD_GET_QUERY_PARAMETERS_DATA)};
|
||||||
|
static const Command CMD_SET_QUERY_PARAMETER = {CMD_SET_QUERY_PARAMETER_DATA, sizeof(CMD_SET_QUERY_PARAMETER_DATA)};
|
||||||
|
static const Command CMD_SET_WORK_AREA = {CMD_SET_WORK_AREA_DATA, sizeof(CMD_SET_WORK_AREA_DATA)};
|
||||||
|
static const Command CMD_SET_TRANSMITTING_POWER = {CMD_SET_TRANSMITTING_POWER_DATA, sizeof(CMD_SET_TRANSMITTING_POWER_DATA)};
|
||||||
29
applications/external/uhf_rfid/uhf_module_settings.h
vendored
Normal file
29
applications/external/uhf_rfid/uhf_module_settings.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// UHF module regions
|
||||||
|
typedef enum {
|
||||||
|
WR_CHINA_900 = 1, // Freq_CH-920.125M
|
||||||
|
WR_US, // Freq_CH-902.25M
|
||||||
|
WR_EU, // Freq_CH-865.1M
|
||||||
|
WR_CHINA_800, // Freq_CH-840.125M
|
||||||
|
WR_KOREA = 6 // Freq_CH-917.1M
|
||||||
|
} WorkingRegion;
|
||||||
|
|
||||||
|
// UHF module baudrates
|
||||||
|
static const uint32_t BAUD_RATES[] = {9600, 19200, 115200};
|
||||||
|
static const uint8_t BAUD_RATES_COUNT = sizeof(BAUD_RATES) / sizeof(BAUD_RATES[0]);
|
||||||
|
// RF Power Setting
|
||||||
|
static const uint8_t POWER_DBM[] = {12, 14, 17, 20}; // To be determined ...
|
||||||
|
static const uint8_t POWER_DBM_COUNT = sizeof(POWER_DBM) / sizeof(POWER_DBM[0]);
|
||||||
|
// UHF WorkingArea
|
||||||
|
static const char* WORKING_REGIONS_STR[] = {"CN1", "US", "EU", "CN2", "KR"};
|
||||||
|
static const uint8_t __working_region_str =
|
||||||
|
sizeof(WORKING_REGIONS_STR) / sizeof(WORKING_REGIONS_STR[0]);
|
||||||
|
static const WorkingRegion WORKING_REGIONS[] = {WR_CHINA_900, WR_US, WR_EU, WR_CHINA_800, WR_KOREA};
|
||||||
|
static const uint8_t WORKING_REGIONS_COUNT = sizeof(WORKING_REGIONS) / sizeof(WORKING_REGIONS[0]);
|
||||||
|
// UHF WorkingChannel
|
||||||
|
// static const string WORKING_CHANNELS_STR[] = {"China 900MHz", "US", "EU", "China 800MHz", "Korea"};
|
||||||
|
// static const WorkingChannel WORKING_CHANNELS[] = {WC_CHINA_900, WC_US, WC_EU, WC_CHINA_800, WC_KOREA};
|
||||||
|
// static const uint8_t WORKING_CHANNELS_COUNT = sizeof(WORKING_CHANNELS) / sizeof(WORKING_CHANNELS[0]);
|
||||||
116
applications/external/uhf_rfid/uhf_tag.c
vendored
Normal file
116
applications/external/uhf_rfid/uhf_tag.c
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#include "uhf_tag.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
UHFTagWrapper* uhf_tag_wrapper_alloc() {
|
||||||
|
UHFTagWrapper* uhf_tag_wrapper = (UHFTagWrapper*)malloc(sizeof(UHFTagWrapper));
|
||||||
|
uhf_tag_wrapper->uhf_tag = NULL;
|
||||||
|
return uhf_tag_wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_wrapper_set_tag(UHFTagWrapper* uhf_tag_wrapper, UHFTag* uhf_tag) {
|
||||||
|
if(uhf_tag_wrapper->uhf_tag != NULL) {
|
||||||
|
uhf_tag_free(uhf_tag_wrapper->uhf_tag);
|
||||||
|
}
|
||||||
|
uhf_tag_wrapper->uhf_tag = uhf_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_wrapper_free(UHFTagWrapper* uhf_tag_wrapper) {
|
||||||
|
uhf_tag_free(uhf_tag_wrapper->uhf_tag);
|
||||||
|
free(uhf_tag_wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
UHFTag* uhf_tag_alloc() {
|
||||||
|
UHFTag* uhf_tag = (UHFTag*)malloc(sizeof(UHFTag));
|
||||||
|
uhf_tag->reserved = (ReservedMemoryBank*)malloc(sizeof(ReservedMemoryBank));
|
||||||
|
uhf_tag->epc = (EPCMemoryBank*)malloc(sizeof(EPCMemoryBank));
|
||||||
|
uhf_tag->tid = (TIDMemoryBank*)malloc(sizeof(TIDMemoryBank));
|
||||||
|
uhf_tag->user = (UserMemoryBank*)malloc(sizeof(UserMemoryBank));
|
||||||
|
return uhf_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_reset(UHFTag* uhf_tag) {
|
||||||
|
uhf_tag->epc->crc = 0;
|
||||||
|
uhf_tag->epc->pc = 0;
|
||||||
|
uhf_tag->epc->size = 0;
|
||||||
|
uhf_tag->tid->size = 0;
|
||||||
|
uhf_tag->user->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_free(UHFTag* uhf_tag) {
|
||||||
|
if(uhf_tag == NULL) return;
|
||||||
|
free(uhf_tag->reserved);
|
||||||
|
free(uhf_tag->epc);
|
||||||
|
free(uhf_tag->tid);
|
||||||
|
free(uhf_tag->user);
|
||||||
|
free(uhf_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_set_epc_pc(UHFTag* uhf_tag, uint16_t pc) {
|
||||||
|
uhf_tag->epc->pc = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_set_epc_crc(UHFTag* uhf_tag, uint16_t crc) {
|
||||||
|
uhf_tag->epc->crc = crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_set_epc(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
|
||||||
|
memcpy(uhf_tag->epc->data, data_in, size);
|
||||||
|
uhf_tag->epc->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_set_epc_size(UHFTag* uhf_tag, size_t size) {
|
||||||
|
uhf_tag->epc->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_set_tid(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
|
||||||
|
memcpy(uhf_tag->tid->data, data_in, size);
|
||||||
|
uhf_tag->tid->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_set_tid_size(UHFTag* uhf_tag, size_t size) {
|
||||||
|
uhf_tag->tid->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_set_user(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
|
||||||
|
memcpy(uhf_tag->user->data, data_in, size);
|
||||||
|
uhf_tag->user->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_tag_set_user_size(UHFTag* uhf_tag, size_t size) {
|
||||||
|
uhf_tag->user->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getters
|
||||||
|
|
||||||
|
uint8_t* uhf_tag_get_epc(UHFTag* uhf_tag) {
|
||||||
|
return uhf_tag->epc->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t uhf_tag_get_epc_size(UHFTag* uhf_tag) {
|
||||||
|
return uhf_tag->epc->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t uhf_tag_get_epc_pc(UHFTag* uhf_tag) {
|
||||||
|
return uhf_tag->epc->pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t uhf_tag_get_epc_crc(UHFTag* uhf_tag) {
|
||||||
|
return uhf_tag->epc->crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* uhf_tag_get_tid(UHFTag* uhf_tag) {
|
||||||
|
return uhf_tag->tid->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t uhf_tag_get_tid_size(UHFTag* uhf_tag) {
|
||||||
|
return uhf_tag->tid->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* uhf_tag_get_user(UHFTag* uhf_tag) {
|
||||||
|
return uhf_tag->user->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t uhf_tag_get_user_size(UHFTag* uhf_tag) {
|
||||||
|
return uhf_tag->user->size;
|
||||||
|
}
|
||||||
80
applications/external/uhf_rfid/uhf_tag.h
vendored
Normal file
80
applications/external/uhf_rfid/uhf_tag.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define MAX_BANK_SIZE 256
|
||||||
|
// storage enum
|
||||||
|
typedef enum { ReservedBank, EPCBank, TIDBank, UserBank } BankType;
|
||||||
|
|
||||||
|
// Reserved Memory Bank
|
||||||
|
typedef struct {
|
||||||
|
uint8_t kill_password[2]; // 2 bytes (16 bits) for kill password
|
||||||
|
uint8_t access_password[2]; // 2 bytes (16 bits) for access password
|
||||||
|
} ReservedMemoryBank;
|
||||||
|
|
||||||
|
// EPC Memory Bank
|
||||||
|
typedef struct {
|
||||||
|
size_t size; // Size of EPC memory data
|
||||||
|
uint8_t data[MAX_BANK_SIZE]; // 2 bytes for CRC16, 2 bytes for PC, and max 14 bytes for EPC
|
||||||
|
uint16_t pc;
|
||||||
|
uint16_t crc;
|
||||||
|
} EPCMemoryBank;
|
||||||
|
|
||||||
|
// TID Memory Bank
|
||||||
|
typedef struct {
|
||||||
|
size_t size; // Size of TID memory data
|
||||||
|
uint8_t data[MAX_BANK_SIZE]; // 4 bytes for Class ID
|
||||||
|
} TIDMemoryBank;
|
||||||
|
|
||||||
|
// User Memory Bank
|
||||||
|
typedef struct {
|
||||||
|
size_t size; // Size of user memory data
|
||||||
|
uint8_t data[MAX_BANK_SIZE]; // Assuming max 512 bits (64 bytes) for User Memory
|
||||||
|
} UserMemoryBank;
|
||||||
|
|
||||||
|
// EPC Gen 2 Tag containing all memory banks
|
||||||
|
typedef struct {
|
||||||
|
ReservedMemoryBank* reserved;
|
||||||
|
EPCMemoryBank* epc;
|
||||||
|
TIDMemoryBank* tid;
|
||||||
|
UserMemoryBank* user;
|
||||||
|
} UHFTag;
|
||||||
|
|
||||||
|
typedef struct UHFTagWrapper {
|
||||||
|
UHFTag* uhf_tag;
|
||||||
|
} UHFTagWrapper;
|
||||||
|
|
||||||
|
UHFTagWrapper* uhf_tag_wrapper_alloc();
|
||||||
|
void uhf_tag_wrapper_set_tag(UHFTagWrapper* uhf_tag_wrapper, UHFTag* uhf_tag);
|
||||||
|
void uhf_tag_wrapper_free(UHFTagWrapper* uhf_tag_wrapper);
|
||||||
|
|
||||||
|
UHFTag* uhf_tag_alloc();
|
||||||
|
void uhf_tag_reset(UHFTag* uhf_tag);
|
||||||
|
void uhf_tag_free(UHFTag* uhf_tag);
|
||||||
|
|
||||||
|
void uhf_tag_set_kill_pwd(UHFTag* uhf_tag, uint8_t* data_in);
|
||||||
|
void uhf_tag_set_access_pwd(UHFTag* uhf_tag, uint8_t* data_in);
|
||||||
|
void uhf_tag_set_epc_pc(UHFTag* uhf_tag, uint16_t pc);
|
||||||
|
void uhf_tag_set_epc_crc(UHFTag* uhf_tag, uint16_t crc);
|
||||||
|
void uhf_tag_set_epc(UHFTag* uhf_tag, uint8_t* data_in, size_t size);
|
||||||
|
void uhf_tag_set_epc_size(UHFTag* uhf_tag, size_t size);
|
||||||
|
void uhf_tag_set_tid(UHFTag* uhf_tag, uint8_t* data_in, size_t size);
|
||||||
|
void uhf_tag_set_tid_size(UHFTag* uhf_tag, size_t size);
|
||||||
|
void uhf_tag_set_user(UHFTag* uhf_tag, uint8_t* data_in, size_t size);
|
||||||
|
void uhf_tag_set_user_size(UHFTag* uhf_tag, size_t size);
|
||||||
|
|
||||||
|
uint8_t* uhf_tag_get_kill_pwd(UHFTag* uhf_tag);
|
||||||
|
uint8_t* uhf_tag_get_access_pwd(UHFTag* uhf_tag);
|
||||||
|
uint8_t* uhf_tag_get_epc(UHFTag* uhf_tag);
|
||||||
|
uint16_t uhf_tag_get_epc_pc(UHFTag* uhf_tag);
|
||||||
|
uint16_t uhf_tag_get_epc_crc(UHFTag* uhf_tag);
|
||||||
|
size_t uhf_tag_get_epc_size(UHFTag* uhf_tag);
|
||||||
|
uint8_t* uhf_tag_get_tid(UHFTag* uhf_tag);
|
||||||
|
size_t uhf_tag_get_tid_size(UHFTag* uhf_tag);
|
||||||
|
uint8_t* uhf_tag_get_user(UHFTag* uhf_tag);
|
||||||
|
size_t uhf_tag_get_user_size(UHFTag* uhf_tag);
|
||||||
|
|
||||||
|
// debug
|
||||||
|
char* uhf_tag_get_cstr(UHFTag* uhf_tag);
|
||||||
138
applications/external/uhf_rfid/uhf_worker.c
vendored
Normal file
138
applications/external/uhf_rfid/uhf_worker.c
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
#include "uhf_worker.h"
|
||||||
|
#include "uhf_tag.h"
|
||||||
|
|
||||||
|
// yrm100 module commands
|
||||||
|
UHFWorkerEvent verify_module_connected(UHFWorker* uhf_worker) {
|
||||||
|
char* hw_version = m100_get_hardware_version(uhf_worker->module);
|
||||||
|
char* sw_version = m100_get_software_version(uhf_worker->module);
|
||||||
|
char* manufacturer = m100_get_manufacturers(uhf_worker->module);
|
||||||
|
// verify all data exists
|
||||||
|
if(hw_version == NULL || sw_version == NULL || manufacturer == NULL) return UHFWorkerEventFail;
|
||||||
|
return UHFWorkerEventSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
UHFTag* send_polling_command(UHFWorker* uhf_worker) {
|
||||||
|
// read epc bank
|
||||||
|
UHFTag* uhf_tag = uhf_tag_alloc();
|
||||||
|
while(true) {
|
||||||
|
M100ResponseType status = m100_single_poll(uhf_worker->module, uhf_tag);
|
||||||
|
if(uhf_worker->state == UHFWorkerStateStop) {
|
||||||
|
uhf_tag_free(uhf_tag);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(status == M100SuccessResponse) break;
|
||||||
|
}
|
||||||
|
return uhf_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
UHFWorkerEvent read_bank_till_max_length(UHFWorker* uhf_worker, UHFTag* uhf_tag, BankType bank) {
|
||||||
|
unsigned int word_low = 0, word_high = 64;
|
||||||
|
unsigned int word_size;
|
||||||
|
M100ResponseType status;
|
||||||
|
do {
|
||||||
|
if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted;
|
||||||
|
if(word_low >= word_high) return UHFWorkerEventSuccess;
|
||||||
|
word_size = (word_low + word_high) / 2;
|
||||||
|
status = m100_read_label_data_storage(uhf_worker->module, uhf_tag, bank, 0, word_size);
|
||||||
|
if(status == M100SuccessResponse) {
|
||||||
|
word_low = word_size + 1;
|
||||||
|
} else if(status == M100MemoryOverrun) {
|
||||||
|
word_high = word_size - 1;
|
||||||
|
}
|
||||||
|
} while(true);
|
||||||
|
return UHFWorkerEventSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
|
||||||
|
UHFTag* uhf_tag = send_polling_command(uhf_worker);
|
||||||
|
if(uhf_tag == NULL) return UHFWorkerEventAborted;
|
||||||
|
uhf_tag_wrapper_set_tag(uhf_worker->uhf_tag_wrapper, uhf_tag);
|
||||||
|
// set select
|
||||||
|
if(m100_set_select(uhf_worker->module, uhf_tag) != M100SuccessResponse)
|
||||||
|
return UHFWorkerEventFail;
|
||||||
|
// read tid
|
||||||
|
UHFWorkerEvent event;
|
||||||
|
event = read_bank_till_max_length(uhf_worker, uhf_tag, TIDBank);
|
||||||
|
if(event != UHFWorkerEventSuccess) return event;
|
||||||
|
// read user
|
||||||
|
event = read_bank_till_max_length(uhf_worker, uhf_tag, UserBank);
|
||||||
|
if(event != UHFWorkerEventSuccess) return event;
|
||||||
|
return UHFWorkerEventSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
UHFWorkerEvent write_single_card(UHFWorker* uhf_worker) {
|
||||||
|
UHFTag* uhf_tag_des = send_polling_command(uhf_worker);
|
||||||
|
if(uhf_tag_des == NULL) return UHFWorkerEventAborted;
|
||||||
|
UHFTag* uhf_tag_from = uhf_worker->uhf_tag_wrapper->uhf_tag;
|
||||||
|
if(m100_set_select(uhf_worker->module, uhf_tag_des) != M100SuccessResponse)
|
||||||
|
return UHFWorkerEventFail;
|
||||||
|
do {
|
||||||
|
M100ResponseType rp_type = m100_write_label_data_storage(
|
||||||
|
uhf_worker->module, uhf_tag_from, uhf_tag_des, UserBank, 0, 0);
|
||||||
|
if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted;
|
||||||
|
if(rp_type == M100SuccessResponse) break;
|
||||||
|
} while(true);
|
||||||
|
do {
|
||||||
|
M100ResponseType rp_type = m100_write_label_data_storage(
|
||||||
|
uhf_worker->module, uhf_tag_from, uhf_tag_des, EPCBank, 0, 0);
|
||||||
|
if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted;
|
||||||
|
if(rp_type == M100SuccessResponse) break;
|
||||||
|
} while(true);
|
||||||
|
return UHFWorkerEventSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t uhf_worker_task(void* ctx) {
|
||||||
|
UHFWorker* uhf_worker = ctx;
|
||||||
|
if(uhf_worker->state == UHFWorkerStateVerify) {
|
||||||
|
UHFWorkerEvent event = verify_module_connected(uhf_worker);
|
||||||
|
uhf_worker->callback(event, uhf_worker->ctx);
|
||||||
|
} else if(uhf_worker->state == UHFWorkerStateDetectSingle) {
|
||||||
|
UHFWorkerEvent event = read_single_card(uhf_worker);
|
||||||
|
uhf_worker->callback(event, uhf_worker->ctx);
|
||||||
|
} else if(uhf_worker->state == UHFWorkerStateWriteSingle) {
|
||||||
|
UHFWorkerEvent event = write_single_card(uhf_worker);
|
||||||
|
uhf_worker->callback(event, uhf_worker->ctx);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UHFWorker* uhf_worker_alloc() {
|
||||||
|
UHFWorker* uhf_worker = (UHFWorker*)malloc(sizeof(UHFWorker));
|
||||||
|
uhf_worker->thread = furi_thread_alloc_ex("UHFWorker", 8 * 1024, uhf_worker_task, uhf_worker);
|
||||||
|
uhf_worker->module = m100_module_alloc();
|
||||||
|
uhf_worker->callback = NULL;
|
||||||
|
uhf_worker->ctx = NULL;
|
||||||
|
return uhf_worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_worker_change_state(UHFWorker* worker, UHFWorkerState state) {
|
||||||
|
worker->state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_worker_start(
|
||||||
|
UHFWorker* uhf_worker,
|
||||||
|
UHFWorkerState state,
|
||||||
|
UHFWorkerCallback callback,
|
||||||
|
void* ctx) {
|
||||||
|
uhf_worker->state = state;
|
||||||
|
uhf_worker->callback = callback;
|
||||||
|
uhf_worker->ctx = ctx;
|
||||||
|
furi_thread_start(uhf_worker->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_worker_stop(UHFWorker* uhf_worker) {
|
||||||
|
furi_assert(uhf_worker);
|
||||||
|
furi_assert(uhf_worker->thread);
|
||||||
|
|
||||||
|
if(furi_thread_get_state(uhf_worker->thread) != FuriThreadStateStopped) {
|
||||||
|
uhf_worker_change_state(uhf_worker, UHFWorkerStateStop);
|
||||||
|
furi_thread_join(uhf_worker->thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uhf_worker_free(UHFWorker* uhf_worker) {
|
||||||
|
furi_assert(uhf_worker);
|
||||||
|
furi_thread_free(uhf_worker->thread);
|
||||||
|
m100_module_free(uhf_worker->module);
|
||||||
|
free(uhf_worker);
|
||||||
|
}
|
||||||
49
applications/external/uhf_rfid/uhf_worker.h
vendored
Normal file
49
applications/external/uhf_rfid/uhf_worker.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
#include "uhf_module.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
// Init states
|
||||||
|
UHFWorkerStateNone,
|
||||||
|
UHFWorkerStateBroken,
|
||||||
|
UHFWorkerStateReady,
|
||||||
|
UHFWorkerStateVerify,
|
||||||
|
// Main worker states
|
||||||
|
UHFWorkerStateDetectSingle,
|
||||||
|
UHFWorkerStateWriteSingle,
|
||||||
|
UHFWorkerStateWriteKey,
|
||||||
|
// Transition
|
||||||
|
UHFWorkerStateStop,
|
||||||
|
} UHFWorkerState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UHFWorkerEventSuccess,
|
||||||
|
UHFWorkerEventFail,
|
||||||
|
UHFWorkerEventNoTagDetected,
|
||||||
|
UHFWorkerEventAborted,
|
||||||
|
UHFWorkerEventCardDetected,
|
||||||
|
} UHFWorkerEvent;
|
||||||
|
|
||||||
|
typedef void (*UHFWorkerCallback)(UHFWorkerEvent event, void* ctx);
|
||||||
|
|
||||||
|
typedef struct UHFWorker {
|
||||||
|
FuriThread* thread;
|
||||||
|
M100Module* module;
|
||||||
|
UHFWorkerCallback callback;
|
||||||
|
UHFWorkerState state;
|
||||||
|
UHFTagWrapper* uhf_tag_wrapper;
|
||||||
|
void* ctx;
|
||||||
|
} UHFWorker;
|
||||||
|
|
||||||
|
int32_t uhf_worker_task(void* ctx);
|
||||||
|
UHFWorker* uhf_worker_alloc();
|
||||||
|
void uhf_worker_change_state(UHFWorker* worker, UHFWorkerState state);
|
||||||
|
void uhf_worker_start(
|
||||||
|
UHFWorker* uhf_worker,
|
||||||
|
UHFWorkerState state,
|
||||||
|
UHFWorkerCallback callback,
|
||||||
|
void* ctx);
|
||||||
|
void uhf_worker_stop(UHFWorker* uhf_worker);
|
||||||
|
void uhf_worker_free(UHFWorker* uhf_worker);
|
||||||
Reference in New Issue
Block a user