mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
Merge remote-tracking branch 'ul/dev' into mntm-dev
Only partially merged1ceb1eb256and09d6e4ee30Changes to login in cc1101_ext.c and adding setting are ignored
This commit is contained in:
@@ -29,7 +29,9 @@
|
|||||||
- Add older qFlipper install demos for windows and macos (by @DXVVAY & @grugnoymeme)
|
- Add older qFlipper install demos for windows and macos (by @DXVVAY & @grugnoymeme)
|
||||||
- OFW: New layout for es-LA (by @IRecabarren)
|
- OFW: New layout for es-LA (by @IRecabarren)
|
||||||
- OFW: Dolphin: Happy mode in Desktop settings (by @portasynthinca3)
|
- OFW: Dolphin: Happy mode in Desktop settings (by @portasynthinca3)
|
||||||
- OFW: GUI: Add up and down button drawing functions to GUI elements (by @DerSkythe)
|
- GUI:
|
||||||
|
- OFW: Add up and down button drawing functions to GUI elements (by @DerSkythe)
|
||||||
|
- OFW: Added one new function for drawing mirrored xbm bitmaps (by @RebornedBrain)
|
||||||
- OFW: RPC: Support 5V on GPIO control for ext. modules (by @gsurkov)
|
- OFW: RPC: Support 5V on GPIO control for ext. modules (by @gsurkov)
|
||||||
- OFW: Toolbox: Proper integer parsing library `strint` (by @portasynthinca3)
|
- OFW: Toolbox: Proper integer parsing library `strint` (by @portasynthinca3)
|
||||||
- OFW: Furi: Put errno into TCB (by @portasynthinca3)
|
- OFW: Furi: Put errno into TCB (by @portasynthinca3)
|
||||||
@@ -55,9 +57,10 @@
|
|||||||
- NFC:
|
- NFC:
|
||||||
- Added 6 new Mifare Classic keys from Bulgaria Hotel (#216 by @z3r0l1nk)
|
- Added 6 new Mifare Classic keys from Bulgaria Hotel (#216 by @z3r0l1nk)
|
||||||
- NDEF parser supports NTAG I2C Plus 1k and 2k chips too (by @RocketGod-git)
|
- NDEF parser supports NTAG I2C Plus 1k and 2k chips too (by @RocketGod-git)
|
||||||
- OFW: Rename 'Detect Reader' to 'Extract MF Keys' (by @bettse)
|
- OFW/UL: Rename 'Detect Reader' to 'Extract MFC Keys' (by @bettse & @xMasterX)
|
||||||
- OFW: Plantain parser improvements (by @assasinfil)
|
- OFW: Plantain parser improvements (by @assasinfil)
|
||||||
- OFW: Moscow social card parser (by @assasinfil)
|
- OFW: Moscow social card parser (by @assasinfil)
|
||||||
|
- OFW: Fixes and improvements to iso14443_4a listener and poller (by @RebornedBrain)
|
||||||
- Sub-GHz:
|
- Sub-GHz:
|
||||||
- UL: Frequency analyzer fixes and improvements (by @xMasterX):
|
- UL: Frequency analyzer fixes and improvements (by @xMasterX):
|
||||||
- Enforce int module (like in OFW) usage due to lack of required hardware on external boards (PathIsolate (+rf switch for multiple paths)) and incorrect usage and/or understanding the purpose of frequency analyzer app by users, it should be used only to get frequency of the remote placed around 1-10cm around flipper's left corner
|
- Enforce int module (like in OFW) usage due to lack of required hardware on external boards (PathIsolate (+rf switch for multiple paths)) and incorrect usage and/or understanding the purpose of frequency analyzer app by users, it should be used only to get frequency of the remote placed around 1-10cm around flipper's left corner
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <furi_hal_interrupt.h>
|
#include <furi_hal_interrupt.h>
|
||||||
#include <furi_hal_resources.h>
|
#include <furi_hal_resources.h>
|
||||||
#include <furi_hal_bus.h>
|
#include <furi_hal_bus.h>
|
||||||
#include <furi_hal_subghz.h>
|
|
||||||
|
|
||||||
#include <stm32wbxx_ll_dma.h>
|
#include <stm32wbxx_ll_dma.h>
|
||||||
#include <furi_hal_cortex.h>
|
#include <furi_hal_cortex.h>
|
||||||
@@ -16,12 +15,12 @@
|
|||||||
#include <cc1101.h>
|
#include <cc1101.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <momentum/momentum.h>
|
#include <momentum/settings.h>
|
||||||
|
|
||||||
#define TAG "SubGhzDeviceCc1101Ext"
|
#define TAG "SubGhzDeviceCc1101Ext"
|
||||||
|
|
||||||
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO (&gpio_ext_pb2)
|
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO (&gpio_ext_pb2)
|
||||||
#define SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO &gpio_ext_pc3
|
#define SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO &gpio_ext_pc3
|
||||||
|
|
||||||
#define SUBGHZ_DEVICE_CC1101_CONFIG_VER 1
|
#define SUBGHZ_DEVICE_CC1101_CONFIG_VER 1
|
||||||
|
|
||||||
@@ -94,9 +93,9 @@ typedef struct {
|
|||||||
const GpioPin* g0_pin;
|
const GpioPin* g0_pin;
|
||||||
SubGhzDeviceCC1101ExtAsyncTx async_tx;
|
SubGhzDeviceCC1101ExtAsyncTx async_tx;
|
||||||
SubGhzDeviceCC1101ExtAsyncRx async_rx;
|
SubGhzDeviceCC1101ExtAsyncRx async_rx;
|
||||||
|
bool amp_and_leds;
|
||||||
bool extended_range;
|
bool extended_range;
|
||||||
bool bypass_region;
|
bool bypass_region;
|
||||||
bool power_amp;
|
|
||||||
} SubGhzDeviceCC1101Ext;
|
} SubGhzDeviceCC1101Ext;
|
||||||
|
|
||||||
static SubGhzDeviceCC1101Ext* subghz_device_cc1101_ext = NULL;
|
static SubGhzDeviceCC1101Ext* subghz_device_cc1101_ext = NULL;
|
||||||
@@ -221,14 +220,14 @@ bool subghz_device_cc1101_ext_alloc(SubGhzDeviceConf* conf) {
|
|||||||
subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx;
|
subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx;
|
||||||
subghz_device_cc1101_ext->async_mirror_pin = NULL;
|
subghz_device_cc1101_ext->async_mirror_pin = NULL;
|
||||||
subghz_device_cc1101_ext->g0_pin = SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO;
|
subghz_device_cc1101_ext->g0_pin = SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO;
|
||||||
|
subghz_device_cc1101_ext->amp_and_leds = false;
|
||||||
subghz_device_cc1101_ext->extended_range = false;
|
subghz_device_cc1101_ext->extended_range = false;
|
||||||
subghz_device_cc1101_ext->bypass_region = false;
|
subghz_device_cc1101_ext->bypass_region = false;
|
||||||
subghz_device_cc1101_ext->power_amp = false;
|
|
||||||
if(conf) {
|
if(conf) {
|
||||||
if(conf->ver == SUBGHZ_DEVICE_CC1101_CONFIG_VER) {
|
if(conf->ver == SUBGHZ_DEVICE_CC1101_CONFIG_VER) {
|
||||||
|
subghz_device_cc1101_ext->amp_and_leds = conf->amp_and_leds;
|
||||||
subghz_device_cc1101_ext->extended_range = conf->extended_range;
|
subghz_device_cc1101_ext->extended_range = conf->extended_range;
|
||||||
subghz_device_cc1101_ext->bypass_region = conf->bypass_region;
|
subghz_device_cc1101_ext->bypass_region = conf->bypass_region;
|
||||||
subghz_device_cc1101_ext->power_amp = conf->power_amp;
|
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_E(TAG, "Config version mismatch");
|
FURI_LOG_E(TAG, "Config version mismatch");
|
||||||
}
|
}
|
||||||
@@ -248,10 +247,9 @@ bool subghz_device_cc1101_ext_alloc(SubGhzDeviceConf* conf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
furi_hal_spi_bus_handle_init(subghz_device_cc1101_ext->spi_bus_handle);
|
furi_hal_spi_bus_handle_init(subghz_device_cc1101_ext->spi_bus_handle);
|
||||||
if(subghz_device_cc1101_ext->power_amp) {
|
if(subghz_device_cc1101_ext->amp_and_leds) {
|
||||||
furi_hal_gpio_init_simple(
|
furi_hal_gpio_init_simple(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, GpioModeOutputPushPull);
|
||||||
SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO, GpioModeOutputPushPull);
|
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return subghz_device_cc1101_ext_check_init();
|
return subghz_device_cc1101_ext_check_init();
|
||||||
@@ -263,7 +261,8 @@ void subghz_device_cc1101_ext_free(void) {
|
|||||||
furi_hal_spi_bus_handle_deinit(subghz_device_cc1101_ext->spi_bus_handle);
|
furi_hal_spi_bus_handle_deinit(subghz_device_cc1101_ext->spi_bus_handle);
|
||||||
|
|
||||||
// resetting the CS pins to floating
|
// resetting the CS pins to floating
|
||||||
if(momentum_settings.spi_nrf24_handle == SpiDefault || subghz_device_cc1101_ext->power_amp) {
|
if(momentum_settings.spi_nrf24_handle == SpiDefault ||
|
||||||
|
subghz_device_cc1101_ext->amp_and_leds) {
|
||||||
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeAnalog);
|
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeAnalog);
|
||||||
} else if(momentum_settings.spi_nrf24_handle == SpiExtra) {
|
} else if(momentum_settings.spi_nrf24_handle == SpiExtra) {
|
||||||
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog);
|
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog);
|
||||||
@@ -442,6 +441,7 @@ void subghz_device_cc1101_ext_reset(void) {
|
|||||||
// Reset GDO2 (!TX/RX) to floating state
|
// Reset GDO2 (!TX/RX) to floating state
|
||||||
cc1101_write_reg(
|
cc1101_write_reg(
|
||||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
||||||
|
|
||||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,8 +455,8 @@ void subghz_device_cc1101_ext_idle(void) {
|
|||||||
cc1101_write_reg(
|
cc1101_write_reg(
|
||||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHighImpedance);
|
||||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||||
if(subghz_device_cc1101_ext->power_amp) {
|
if(subghz_device_cc1101_ext->amp_and_leds) {
|
||||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO, 0);
|
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,8 +471,8 @@ void subghz_device_cc1101_ext_rx(void) {
|
|||||||
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
|
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
|
||||||
|
|
||||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||||
if(subghz_device_cc1101_ext->power_amp) {
|
if(subghz_device_cc1101_ext->amp_and_leds) {
|
||||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO, 0);
|
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,8 +486,8 @@ bool subghz_device_cc1101_ext_tx(void) {
|
|||||||
// Go GDO2 (!TX/RX) to low (TX state)
|
// Go GDO2 (!TX/RX) to low (TX state)
|
||||||
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW);
|
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW);
|
||||||
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
|
||||||
if(subghz_device_cc1101_ext->power_amp) {
|
if(subghz_device_cc1101_ext->amp_and_leds) {
|
||||||
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07M20S_AMP_GPIO, 1);
|
furi_hal_gpio_write(SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO, 1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ static void nfc_scene_read_menu_on_enter_mf_classic(NfcApp* instance) {
|
|||||||
if(!mf_classic_is_card_read(data)) {
|
if(!mf_classic_is_card_read(data)) {
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Extract MF Keys",
|
"Extract MFC Keys",
|
||||||
SubmenuIndexDetectReader,
|
SubmenuIndexDetectReader,
|
||||||
nfc_protocol_support_common_submenu_callback,
|
nfc_protocol_support_common_submenu_callback,
|
||||||
instance);
|
instance);
|
||||||
@@ -155,7 +155,7 @@ static void nfc_scene_saved_menu_on_enter_mf_classic(NfcApp* instance) {
|
|||||||
if(!mf_classic_is_card_read(data)) {
|
if(!mf_classic_is_card_read(data)) {
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Extract MF Keys",
|
"Extract MFC Keys",
|
||||||
SubmenuIndexDetectReader,
|
SubmenuIndexDetectReader,
|
||||||
nfc_protocol_support_common_submenu_callback,
|
nfc_protocol_support_common_submenu_callback,
|
||||||
instance);
|
instance);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ void nfc_scene_start_on_enter(void* context) {
|
|||||||
submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Extract MF Keys",
|
"Extract MFC Keys",
|
||||||
SubmenuIndexDetectReader,
|
SubmenuIndexDetectReader,
|
||||||
nfc_scene_start_submenu_callback,
|
nfc_scene_start_submenu_callback,
|
||||||
nfc);
|
nfc);
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ const uint32_t radio_device_value[RADIO_DEVICE_COUNT] = {
|
|||||||
SubGhzRadioDeviceTypeExternalCC1101,
|
SubGhzRadioDeviceTypeExternalCC1101,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TIMESTAMP_NAMES_COUNT 2
|
#define ON_OFF_COUNT 2
|
||||||
const char* const timestamp_names_text[TIMESTAMP_NAMES_COUNT] = {
|
const char* const on_off_text[ON_OFF_COUNT] = {
|
||||||
"OFF",
|
"OFF",
|
||||||
"ON",
|
"ON",
|
||||||
};
|
};
|
||||||
@@ -139,7 +139,7 @@ static void subghz_scene_receiver_config_set_protocol_file_names(VariableItem* i
|
|||||||
SubGhz* subghz = variable_item_get_context(item);
|
SubGhz* subghz = variable_item_get_context(item);
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, timestamp_names_text[index]);
|
variable_item_set_current_value_text(item, on_off_text[index]);
|
||||||
|
|
||||||
subghz->last_settings->protocol_file_names = (index == 1);
|
subghz->last_settings->protocol_file_names = (index == 1);
|
||||||
subghz_last_settings_save(subghz->last_settings);
|
subghz_last_settings_save(subghz->last_settings);
|
||||||
@@ -183,12 +183,12 @@ void subghz_scene_radio_settings_on_enter(void* context) {
|
|||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
variable_item_list,
|
variable_item_list,
|
||||||
"Protocol Names",
|
"Protocol Names",
|
||||||
TIMESTAMP_NAMES_COUNT,
|
ON_OFF_COUNT,
|
||||||
subghz_scene_receiver_config_set_protocol_file_names,
|
subghz_scene_receiver_config_set_protocol_file_names,
|
||||||
subghz);
|
subghz);
|
||||||
value_index = subghz->last_settings->protocol_file_names;
|
value_index = subghz->last_settings->protocol_file_names;
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, timestamp_names_text[value_index]);
|
variable_item_set_current_value_text(item, on_off_text[value_index]);
|
||||||
|
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
variable_item_list,
|
variable_item_list,
|
||||||
|
|||||||
@@ -561,6 +561,19 @@ void canvas_draw_xbm(
|
|||||||
canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap, IconRotation0);
|
canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap, IconRotation0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void canvas_draw_xbm_mirrored(
|
||||||
|
Canvas* canvas,
|
||||||
|
int32_t x,
|
||||||
|
int32_t y,
|
||||||
|
size_t width,
|
||||||
|
size_t height,
|
||||||
|
const uint8_t* bitmap_data) {
|
||||||
|
furi_check(canvas);
|
||||||
|
x += canvas->offset_x;
|
||||||
|
y += canvas->offset_y;
|
||||||
|
canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap_data, IconRotation180);
|
||||||
|
}
|
||||||
|
|
||||||
void canvas_draw_glyph(Canvas* canvas, int32_t x, int32_t y, uint16_t ch) {
|
void canvas_draw_glyph(Canvas* canvas, int32_t x, int32_t y, uint16_t ch) {
|
||||||
furi_check(canvas);
|
furi_check(canvas);
|
||||||
x += canvas->offset_x;
|
x += canvas->offset_x;
|
||||||
|
|||||||
@@ -296,6 +296,23 @@ void canvas_draw_xbm(
|
|||||||
size_t height,
|
size_t height,
|
||||||
const uint8_t* bitmap);
|
const uint8_t* bitmap);
|
||||||
|
|
||||||
|
/** Draw mirrored XBM bitmap
|
||||||
|
*
|
||||||
|
* @param canvas Canvas instance
|
||||||
|
* @param x x coordinate
|
||||||
|
* @param y y coordinate
|
||||||
|
* @param[in] width bitmap width
|
||||||
|
* @param[in] height bitmap height
|
||||||
|
* @param bitmap pointer to XBM bitmap data
|
||||||
|
*/
|
||||||
|
void canvas_draw_xbm_mirrored(
|
||||||
|
Canvas* canvas,
|
||||||
|
int32_t x,
|
||||||
|
int32_t y,
|
||||||
|
size_t width,
|
||||||
|
size_t height,
|
||||||
|
const uint8_t* bitmap_data);
|
||||||
|
|
||||||
/** Draw dot at x,y
|
/** Draw dot at x,y
|
||||||
*
|
*
|
||||||
* @param canvas Canvas instance
|
* @param canvas Canvas instance
|
||||||
|
|||||||
@@ -2,22 +2,50 @@
|
|||||||
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
|
|
||||||
#define ISO14443_4_BLOCK_PCB (1U << 1)
|
// EMV Specific masks
|
||||||
#define ISO14443_4_BLOCK_PCB_I (0U)
|
|
||||||
#define ISO14443_4_BLOCK_PCB_R (5U << 5)
|
|
||||||
#define ISO14443_4_BLOCK_PCB_S (3U << 6)
|
|
||||||
|
|
||||||
#define ISO14443_4_BLOCK_PCB_I_ (0U << 6)
|
#define ISO14443_4_BLOCK_PCB_I_ (0U << 6)
|
||||||
#define ISO14443_4_BLOCK_PCB_R_ (2U << 6)
|
#define ISO14443_4_BLOCK_PCB_R_ (2U << 6)
|
||||||
#define ISO14443_4_BLOCK_PCB_TYPE_MASK (3U << 6)
|
#define ISO14443_4_BLOCK_PCB_TYPE_MASK (3U << 6)
|
||||||
|
|
||||||
#define ISO14443_4_BLOCK_PCB_S_DESELECT (0U << 4)
|
|
||||||
#define ISO14443_4_BLOCK_PCB_S_WTX (3U << 4)
|
#define ISO14443_4_BLOCK_PCB_S_WTX (3U << 4)
|
||||||
#define ISO14443_4_BLOCK_PCB_BLOCK_NUMBER (1U << 0)
|
#define ISO14443_4_BLOCK_PCB_S (3U << 6)
|
||||||
|
//
|
||||||
|
|
||||||
#define ISO14443_4_BLOCK_PCB_NAD (1U << 2)
|
#define ISO14443_4_BLOCK_PCB (1U << 1)
|
||||||
#define ISO14443_4_BLOCK_PCB_CID (1U << 3)
|
#define ISO14443_4_BLOCK_PCB_MASK (0x03)
|
||||||
#define ISO14443_4_BLOCK_PCB_CHAINING (1U << 4)
|
|
||||||
|
#define ISO14443_4_BLOCK_PCB_I (0U)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_I_NAD_OFFSET (2)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_I_CID_OFFSET (3)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_I_CHAIN_OFFSET (4)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_I_NAD_MASK (1U << ISO14443_4_BLOCK_PCB_I_NAD_OFFSET)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_I_CID_MASK (1U << ISO14443_4_BLOCK_PCB_I_CID_OFFSET)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_I_CHAIN_MASK (1U << ISO14443_4_BLOCK_PCB_I_CHAIN_OFFSET)
|
||||||
|
|
||||||
|
#define ISO14443_4_BLOCK_PCB_R_MASK (5U << 5)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_R_NACK_OFFSET (4)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_R_CID_OFFSET (3)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_R_CID_MASK (1U << ISO14443_4_BLOCK_PCB_R_CID_OFFSET)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_R_NACK_MASK (1U << ISO14443_4_BLOCK_PCB_R_NACK_OFFSET)
|
||||||
|
|
||||||
|
#define ISO14443_4_BLOCK_PCB_S_MASK (3U << 6)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_S_CID_OFFSET (3)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_OFFSET (4)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_S_CID_MASK (1U << ISO14443_4_BLOCK_PCB_R_CID_OFFSET)
|
||||||
|
#define ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_MASK (3U << ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_OFFSET)
|
||||||
|
|
||||||
|
#define ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, mask) (((pcb) & mask) == mask)
|
||||||
|
|
||||||
|
#define ISO14443_4_BLOCK_PCB_IS_R_BLOCK(pcb) \
|
||||||
|
ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, ISO14443_4_BLOCK_PCB_R_MASK)
|
||||||
|
|
||||||
|
#define ISO14443_4_BLOCK_PCB_IS_S_BLOCK(pcb) \
|
||||||
|
ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, ISO14443_4_BLOCK_PCB_S_MASK)
|
||||||
|
|
||||||
|
#define ISO14443_4_BLOCK_PCB_IS_CHAIN_ACTIVE(pcb) \
|
||||||
|
ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, ISO14443_4_BLOCK_PCB_I_CHAIN_MASK)
|
||||||
|
|
||||||
|
#define ISO14443_4_BLOCK_PCB_R_NACK_ACTIVE(pcb) \
|
||||||
|
ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, ISO14443_4_BLOCK_PCB_R_NACK_MASK)
|
||||||
|
|
||||||
struct Iso14443_4Layer {
|
struct Iso14443_4Layer {
|
||||||
uint8_t pcb;
|
uint8_t pcb;
|
||||||
@@ -43,9 +71,31 @@ void iso14443_4_layer_free(Iso14443_4Layer* instance) {
|
|||||||
|
|
||||||
void iso14443_4_layer_reset(Iso14443_4Layer* instance) {
|
void iso14443_4_layer_reset(Iso14443_4Layer* instance) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
instance->pcb_prev = 0;
|
||||||
instance->pcb = ISO14443_4_BLOCK_PCB_I | ISO14443_4_BLOCK_PCB;
|
instance->pcb = ISO14443_4_BLOCK_PCB_I | ISO14443_4_BLOCK_PCB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iso14443_4_layer_set_i_block(Iso14443_4Layer* instance, bool chaining, bool CID_present) {
|
||||||
|
uint8_t block_pcb = instance->pcb & ISO14443_4_BLOCK_PCB_MASK;
|
||||||
|
instance->pcb = ISO14443_4_BLOCK_PCB_I | (chaining << ISO14443_4_BLOCK_PCB_I_CHAIN_OFFSET) |
|
||||||
|
(CID_present << ISO14443_4_BLOCK_PCB_I_CID_OFFSET) | block_pcb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso14443_4_layer_set_r_block(Iso14443_4Layer* instance, bool acknowledged, bool CID_present) {
|
||||||
|
furi_assert(instance);
|
||||||
|
uint8_t block_pcb = instance->pcb & ISO14443_4_BLOCK_PCB_MASK;
|
||||||
|
instance->pcb = ISO14443_4_BLOCK_PCB_R_MASK |
|
||||||
|
(!acknowledged << ISO14443_4_BLOCK_PCB_R_NACK_OFFSET) |
|
||||||
|
(CID_present << ISO14443_4_BLOCK_PCB_R_CID_OFFSET) | block_pcb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso14443_4_layer_set_s_block(Iso14443_4Layer* instance, bool deselect, bool CID_present) {
|
||||||
|
furi_assert(instance);
|
||||||
|
uint8_t des_wtx = !deselect ? (ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_MASK) : 0;
|
||||||
|
instance->pcb = ISO14443_4_BLOCK_PCB_S_MASK | des_wtx |
|
||||||
|
(CID_present << ISO14443_4_BLOCK_PCB_S_CID_OFFSET) | ISO14443_4_BLOCK_PCB;
|
||||||
|
}
|
||||||
|
|
||||||
void iso14443_4_layer_encode_block(
|
void iso14443_4_layer_encode_block(
|
||||||
Iso14443_4Layer* instance,
|
Iso14443_4Layer* instance,
|
||||||
const BitBuffer* input_data,
|
const BitBuffer* input_data,
|
||||||
@@ -58,6 +108,11 @@ void iso14443_4_layer_encode_block(
|
|||||||
iso14443_4_layer_update_pcb(instance);
|
iso14443_4_layer_update_pcb(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t iso14443_4_layer_get_response_pcb(const BitBuffer* block_data) {
|
||||||
|
const uint8_t* data = bit_buffer_get_data(block_data);
|
||||||
|
return data[0];
|
||||||
|
}
|
||||||
|
|
||||||
bool iso14443_4_layer_decode_block(
|
bool iso14443_4_layer_decode_block(
|
||||||
Iso14443_4Layer* instance,
|
Iso14443_4Layer* instance,
|
||||||
BitBuffer* output_data,
|
BitBuffer* output_data,
|
||||||
@@ -74,9 +129,26 @@ bool iso14443_4_layer_decode_block(
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
if(ISO14443_4_BLOCK_PCB_IS_R_BLOCK(instance->pcb_prev)) {
|
||||||
|
const uint8_t response_pcb = iso14443_4_layer_get_response_pcb(block_data);
|
||||||
|
ret = (ISO14443_4_BLOCK_PCB_IS_R_BLOCK(response_pcb)) &&
|
||||||
|
(!ISO14443_4_BLOCK_PCB_R_NACK_ACTIVE(response_pcb));
|
||||||
|
instance->pcb &= ISO14443_4_BLOCK_PCB_MASK;
|
||||||
|
iso14443_4_layer_update_pcb(instance);
|
||||||
|
} else if(ISO14443_4_BLOCK_PCB_IS_CHAIN_ACTIVE(instance->pcb_prev)) {
|
||||||
|
const uint8_t response_pcb = iso14443_4_layer_get_response_pcb(block_data);
|
||||||
|
ret = (ISO14443_4_BLOCK_PCB_IS_R_BLOCK(response_pcb)) &&
|
||||||
|
(!ISO14443_4_BLOCK_PCB_R_NACK_ACTIVE(response_pcb));
|
||||||
|
instance->pcb &= ~(ISO14443_4_BLOCK_PCB_I_CHAIN_MASK);
|
||||||
|
} else if(ISO14443_4_BLOCK_PCB_IS_S_BLOCK(instance->pcb_prev)) {
|
||||||
|
ret = bit_buffer_starts_with_byte(block_data, instance->pcb_prev);
|
||||||
|
if(bit_buffer_get_size_bytes(block_data) > 1)
|
||||||
|
bit_buffer_copy_right(output_data, block_data, 1);
|
||||||
|
} else {
|
||||||
if(!bit_buffer_starts_with_byte(block_data, instance->pcb_prev)) break;
|
if(!bit_buffer_starts_with_byte(block_data, instance->pcb_prev)) break;
|
||||||
bit_buffer_copy_right(output_data, block_data, 1);
|
bit_buffer_copy_right(output_data, block_data, 1);
|
||||||
ret = true;
|
ret = true;
|
||||||
|
}
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ void iso14443_4_layer_free(Iso14443_4Layer* instance);
|
|||||||
|
|
||||||
void iso14443_4_layer_reset(Iso14443_4Layer* instance);
|
void iso14443_4_layer_reset(Iso14443_4Layer* instance);
|
||||||
|
|
||||||
|
void iso14443_4_layer_set_i_block(Iso14443_4Layer* instance, bool chaining, bool CID_present);
|
||||||
|
void iso14443_4_layer_set_r_block(Iso14443_4Layer* instance, bool acknowledged, bool CID_present);
|
||||||
|
void iso14443_4_layer_set_s_block(Iso14443_4Layer* instance, bool deselect, bool CID_present);
|
||||||
|
|
||||||
void iso14443_4_layer_encode_block(
|
void iso14443_4_layer_encode_block(
|
||||||
Iso14443_4Layer* instance,
|
Iso14443_4Layer* instance,
|
||||||
const BitBuffer* input_data,
|
const BitBuffer* input_data,
|
||||||
|
|||||||
@@ -84,6 +84,15 @@ static NfcCommand iso14443_4a_listener_run(NfcGenericEvent event, void* context)
|
|||||||
iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted ||
|
iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted ||
|
||||||
iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) {
|
iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) {
|
||||||
instance->state = Iso14443_4aListenerStateIdle;
|
instance->state = Iso14443_4aListenerStateIdle;
|
||||||
|
|
||||||
|
instance->iso14443_4a_event.type = iso14443_3a_event->type ==
|
||||||
|
Iso14443_3aListenerEventTypeHalted ?
|
||||||
|
Iso14443_4aListenerEventTypeHalted :
|
||||||
|
Iso14443_4aListenerEventTypeFieldOff;
|
||||||
|
|
||||||
|
if(instance->callback) {
|
||||||
|
command = instance->callback(instance->generic_event, instance->context);
|
||||||
|
}
|
||||||
command = NfcCommandContinue;
|
command = NfcCommandContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ typedef struct Iso14443_4aListener Iso14443_4aListener;
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Iso14443_4aListenerEventTypeHalted,
|
Iso14443_4aListenerEventTypeHalted,
|
||||||
|
Iso14443_4aListenerEventTypeFieldOff,
|
||||||
Iso14443_4aListenerEventTypeReceivedData,
|
Iso14443_4aListenerEventTypeReceivedData,
|
||||||
} Iso14443_4aListenerEventType;
|
} Iso14443_4aListenerEventType;
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,69 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext(
|
|||||||
const BitBuffer* tx_buffer,
|
const BitBuffer* tx_buffer,
|
||||||
BitBuffer* rx_buffer);
|
BitBuffer* rx_buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive Iso14443_4a chained block in poller mode. Also it
|
||||||
|
* automatically modifies PCB packet byte with appropriate bits then resets them back
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer. The fwt parameter is calculated during activation procedure.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @return Iso14443_4aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4aError iso14443_4a_poller_send_chain_block(
|
||||||
|
Iso14443_4aPoller* instance,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit Iso14443_4a R-block in poller mode. This block never contains
|
||||||
|
* data, but can contain CID and NAD, therefore in tx_buffer only two bytes can be added.
|
||||||
|
* The first one will represent CID, the second one will represent NAD.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with R-block repsonse
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] acknowledged Sets appropriate bit in PCB byte. True - ACK, false - NAK
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @return Iso14443_4aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4aError iso14443_4a_poller_send_receive_ready_block(
|
||||||
|
Iso14443_4aPoller* instance,
|
||||||
|
bool acknowledged,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit Iso14443_4a S-block in poller mode. S-block used to exchange control
|
||||||
|
* information between the card and the reader. Two different types of S-blocks
|
||||||
|
* are defined:
|
||||||
|
* - Waiting time extension containing a 1 byte long INF field and (deselect = false)
|
||||||
|
* - DESELECT containing no INF field (deselect = true)
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with R-block repsonse
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] deselect Sets appropriate bit in PCB byte.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @return Iso14443_4aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4aError iso14443_4a_poller_send_supervisory_block(
|
||||||
|
Iso14443_4aPoller* instance,
|
||||||
|
bool deselect,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send HALT command to the card.
|
* @brief Send HALT command to the card.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -164,3 +164,34 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext(
|
|||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Iso14443_4aError iso14443_4a_poller_send_chain_block(
|
||||||
|
Iso14443_4aPoller* instance,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer) {
|
||||||
|
iso14443_4_layer_set_i_block(instance->iso14443_4_layer, true, false);
|
||||||
|
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iso14443_4aError iso14443_4a_poller_send_receive_ready_block(
|
||||||
|
Iso14443_4aPoller* instance,
|
||||||
|
bool acknowledged,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer) {
|
||||||
|
bool CID_present = bit_buffer_get_size_bytes(tx_buffer) != 0;
|
||||||
|
iso14443_4_layer_set_r_block(instance->iso14443_4_layer, acknowledged, CID_present);
|
||||||
|
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iso14443_4aError iso14443_4a_poller_send_supervisory_block(
|
||||||
|
Iso14443_4aPoller* instance,
|
||||||
|
bool deselect,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer) {
|
||||||
|
bool CID_present = bit_buffer_get_size_bytes(tx_buffer) != 0;
|
||||||
|
iso14443_4_layer_set_s_block(instance->iso14443_4_layer, deselect, CID_present);
|
||||||
|
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ bool subghz_devices_begin(const SubGhzDevice* device) {
|
|||||||
.ver = 1,
|
.ver = 1,
|
||||||
.extended_range = furi_hal_subghz_get_extended_range(),
|
.extended_range = furi_hal_subghz_get_extended_range(),
|
||||||
.bypass_region = furi_hal_subghz_get_bypass_region(),
|
.bypass_region = furi_hal_subghz_get_bypass_region(),
|
||||||
.power_amp = true,
|
.amp_and_leds = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
ret = device->interconnect->begin(&conf);
|
ret = device->interconnect->begin(&conf);
|
||||||
|
|||||||
@@ -99,5 +99,5 @@ struct SubGhzDeviceConf {
|
|||||||
uint8_t ver;
|
uint8_t ver;
|
||||||
bool extended_range;
|
bool extended_range;
|
||||||
bool bypass_region;
|
bool bypass_region;
|
||||||
bool power_amp;
|
bool amp_and_leds;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -842,6 +842,7 @@ Function,+,canvas_draw_str,void,"Canvas*, int32_t, int32_t, const char*"
|
|||||||
Function,+,canvas_draw_str_aligned,void,"Canvas*, int32_t, int32_t, Align, Align, const char*"
|
Function,+,canvas_draw_str_aligned,void,"Canvas*, int32_t, int32_t, Align, Align, const char*"
|
||||||
Function,+,canvas_draw_triangle,void,"Canvas*, int32_t, int32_t, size_t, size_t, CanvasDirection"
|
Function,+,canvas_draw_triangle,void,"Canvas*, int32_t, int32_t, size_t, size_t, CanvasDirection"
|
||||||
Function,+,canvas_draw_xbm,void,"Canvas*, int32_t, int32_t, size_t, size_t, const uint8_t*"
|
Function,+,canvas_draw_xbm,void,"Canvas*, int32_t, int32_t, size_t, size_t, const uint8_t*"
|
||||||
|
Function,+,canvas_draw_xbm_mirrored,void,"Canvas*, int32_t, int32_t, size_t, size_t, const uint8_t*"
|
||||||
Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font"
|
Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font"
|
||||||
Function,+,canvas_glyph_width,size_t,"Canvas*, uint16_t"
|
Function,+,canvas_glyph_width,size_t,"Canvas*, uint16_t"
|
||||||
Function,+,canvas_height,size_t,const Canvas*
|
Function,+,canvas_height,size_t,const Canvas*
|
||||||
@@ -2200,6 +2201,9 @@ Function,+,iso14443_4a_poller_halt,Iso14443_4aError,Iso14443_4aPoller*
|
|||||||
Function,+,iso14443_4a_poller_read_ats,Iso14443_4aError,"Iso14443_4aPoller*, Iso14443_4aAtsData*"
|
Function,+,iso14443_4a_poller_read_ats,Iso14443_4aError,"Iso14443_4aPoller*, Iso14443_4aAtsData*"
|
||||||
Function,+,iso14443_4a_poller_send_block,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*"
|
Function,+,iso14443_4a_poller_send_block,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*"
|
||||||
Function,+,iso14443_4a_poller_send_block_pwt_ext,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*"
|
Function,+,iso14443_4a_poller_send_block_pwt_ext,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*"
|
||||||
|
Function,+,iso14443_4a_poller_send_chain_block,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*"
|
||||||
|
Function,+,iso14443_4a_poller_send_receive_ready_block,Iso14443_4aError,"Iso14443_4aPoller*, _Bool, const BitBuffer*, BitBuffer*"
|
||||||
|
Function,+,iso14443_4a_poller_send_supervisory_block,Iso14443_4aError,"Iso14443_4aPoller*, _Bool, const BitBuffer*, BitBuffer*"
|
||||||
Function,+,iso14443_4a_reset,void,Iso14443_4aData*
|
Function,+,iso14443_4a_reset,void,Iso14443_4aData*
|
||||||
Function,+,iso14443_4a_save,_Bool,"const Iso14443_4aData*, FlipperFormat*"
|
Function,+,iso14443_4a_save,_Bool,"const Iso14443_4aData*, FlipperFormat*"
|
||||||
Function,+,iso14443_4a_set_uid,_Bool,"Iso14443_4aData*, const uint8_t*, size_t"
|
Function,+,iso14443_4a_set_uid,_Bool,"Iso14443_4aData*, const uint8_t*, size_t"
|
||||||
|
|||||||
|
Reference in New Issue
Block a user