This commit is contained in:
Willy-JL
2024-01-13 02:36:39 +00:00
25 changed files with 577 additions and 217 deletions

View File

@@ -369,7 +369,7 @@ vscode_dist = distenv.Install(
)
distenv.Precious(vscode_dist)
distenv.NoClean(vscode_dist)
distenv.Alias("vscode_dist", vscode_dist)
distenv.Alias("vscode_dist", (vscode_dist, firmware_env["FW_CDB"]))
# Configure shell with build tools
distenv.PhonyTarget(

View File

@@ -229,17 +229,17 @@ typedef struct {
size_t pos;
} SubGhzHalAsyncTxTest;
#define SUBGHZ_HAL_TEST_DURATION 1
#define SUBGHZ_HAL_TEST_DURATION 3
static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
SubGhzHalAsyncTxTest* test = context;
bool is_odd = test->pos % 2;
if(test->type == SubGhzHalAsyncTxTestTypeNormal) {
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
@@ -249,36 +249,36 @@ static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
if(test->pos == 0) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidMid) {
if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidEnd) {
if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
@@ -292,20 +292,20 @@ static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeResetMid) {
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeResetEnd) {
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) {
test->pos++;
return level_duration_reset();
} else {
@@ -332,6 +332,8 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
while(!furi_hal_subghz_is_async_tx_complete()) {
if(furi_hal_cortex_timer_is_expired(timer)) {
furi_hal_subghz_stop_async_tx();
furi_hal_subghz_sleep();
return false;
}
furi_delay_ms(10);

View File

@@ -18,18 +18,18 @@
#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_FORCE_EXTENDED_RANGE false
#define SUBGHZ_DEVICE_CC1101_CONFIG_VER 1
/* DMA Channels definition */
#define SUBGHZ_DEVICE_CC1101_EXT_DMA DMA2
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL LL_DMA_CHANNEL_3
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL LL_DMA_CHANNEL_4
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL LL_DMA_CHANNEL_5
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ FuriHalInterruptIdDma2Ch3
#define SUBGHZ_DEVICE_CC1101_EXT_DMA (DMA2)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL (LL_DMA_CHANNEL_3)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL (LL_DMA_CHANNEL_4)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL (LL_DMA_CHANNEL_5)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ (FuriHalInterruptIdDma2Ch3)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \
@@ -38,10 +38,10 @@
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL
/** Low level buffer dimensions and guard times */
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256)
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256u)
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \
(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2)
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME 999 << 1
#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME (999u >> 1)
/** SubGhz state */
typedef enum {
@@ -59,13 +59,25 @@ typedef enum {
SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/
} SubGhzDeviceCC1101ExtRegulation;
typedef enum {
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle,
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset,
SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun,
} SubGhzDeviceCC1101ExtAsyncTxMiddlewareState;
typedef struct {
SubGhzDeviceCC1101ExtAsyncTxMiddlewareState state;
bool is_odd_level;
uint32_t adder_duration;
} SubGhzDeviceCC1101ExtAsyncTxMiddleware;
typedef struct {
uint32_t* buffer;
LevelDuration carry_ld;
SubGhzDeviceCC1101ExtCallback callback;
void* callback_context;
uint32_t gpio_tx_buff[2];
uint32_t debug_gpio_buff[2];
SubGhzDeviceCC1101ExtAsyncTxMiddleware middleware;
} SubGhzDeviceCC1101ExtAsyncTx;
typedef struct {
@@ -303,8 +315,8 @@ void subghz_device_cc1101_ext_dump_state() {
void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) {
//load config
subghz_device_cc1101_ext_reset();
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
uint32_t i = 0;
uint8_t pa[8] = {0};
while(preset_data[i]) {
@@ -333,8 +345,8 @@ void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) {
}
void subghz_device_cc1101_ext_load_registers(const uint8_t* data) {
subghz_device_cc1101_ext_reset();
furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
uint32_t i = 0;
while(data[i]) {
cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]);
@@ -416,6 +428,7 @@ void subghz_device_cc1101_ext_reset() {
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle);
cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle);
// Warning: push pull cc1101 clock output on GD0
cc1101_write_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
@@ -636,50 +649,91 @@ void subghz_device_cc1101_ext_stop_async_rx() {
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
}
static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
while(samples > 0) {
bool is_odd = samples % 2;
LevelDuration ld;
if(level_duration_is_reset(subghz_device_cc1101_ext->async_tx.carry_ld)) {
ld = subghz_device_cc1101_ext->async_tx.callback(
subghz_device_cc1101_ext->async_tx.callback_context);
} else {
ld = subghz_device_cc1101_ext->async_tx.carry_ld;
subghz_device_cc1101_ext->async_tx.carry_ld = level_duration_reset();
void subghz_device_cc1101_ext_async_tx_middleware_idle(
SubGhzDeviceCC1101ExtAsyncTxMiddleware* middleware) {
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle;
middleware->is_odd_level = false;
middleware->adder_duration = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
}
static inline uint32_t subghz_device_cc1101_ext_async_tx_middleware_get_duration(
SubGhzDeviceCC1101ExtAsyncTxMiddleware* middleware,
SubGhzDeviceCC1101ExtCallback callback) {
uint32_t ret = 0;
bool is_level = false;
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset) return 0;
while(1) {
LevelDuration ld = callback(subghz_device_cc1101_ext->async_tx.callback_context);
if(level_duration_is_reset(ld)) {
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateReset;
if(!middleware->is_odd_level) {
return 0;
} else {
return middleware->adder_duration;
}
} else if(level_duration_is_wait(ld)) {
middleware->is_odd_level = !middleware->is_odd_level;
ret = middleware->adder_duration + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
middleware->adder_duration = 0;
return ret;
}
if(level_duration_is_wait(ld)) {
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
buffer++;
samples--;
} else if(level_duration_is_reset(ld)) {
is_level = level_duration_get_level(ld);
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateIdle) {
if(is_level != middleware->is_odd_level) {
middleware->state = SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun;
middleware->is_odd_level = is_level;
middleware->adder_duration = level_duration_get_duration(ld);
return SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
} else {
continue;
}
}
if(middleware->state == SubGhzDeviceCC1101ExtAsyncTxMiddlewareStateRun) {
if(is_level == middleware->is_odd_level) {
middleware->adder_duration += level_duration_get_duration(ld);
continue;
} else {
middleware->is_odd_level = is_level;
ret = middleware->adder_duration;
middleware->adder_duration = level_duration_get_duration(ld);
return ret;
}
}
}
}
static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) {
furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx);
while(samples > 0) {
volatile uint32_t duration = subghz_device_cc1101_ext_async_tx_middleware_get_duration(
&subghz_device_cc1101_ext->async_tx.middleware,
subghz_device_cc1101_ext->async_tx.callback);
if(duration == 0) {
*buffer = 0;
buffer++;
samples--;
LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
if(LL_DMA_IsActiveFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
LL_DMA_ClearFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
}
if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) {
LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA);
}
LL_TIM_EnableIT_UPDATE(TIM17);
break;
} else {
bool level = level_duration_get_level(ld);
// Inject guard time if level is incorrect
if(is_odd != level) {
*buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME;
buffer++;
samples--;
// Special case: prevent buffer overflow if sample is last
if(samples == 0) {
subghz_device_cc1101_ext->async_tx.carry_ld = ld;
break;
}
}
uint32_t duration = level_duration_get_duration(ld);
furi_assert(duration > 0);
*buffer = duration >> 1;
// Lowest possible value is 4us
if(duration < 4) duration = 4;
// Divide by 2 since timer resolution is 2us
// Subtract 1 since we counting from 0
*buffer = (duration >> 1) - 1;
buffer++;
samples--;
}
@@ -711,12 +765,14 @@ static void subghz_device_cc1101_ext_async_tx_dma_isr() {
static void subghz_device_cc1101_ext_async_tx_timer_isr() {
if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) {
if(LL_TIM_GetAutoReload(TIM17) == 0) {
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
LL_TIM_DisableCounter(TIM17);
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd;
if(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) {
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF);
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd;
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
if(subghz_device_cc1101_ext->async_mirror_pin != NULL)
furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false);
LL_TIM_DisableCounter(TIM17);
}
}
LL_TIM_ClearFlag_UPDATE(TIM17);
}
@@ -766,16 +822,18 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
// Configure TIM
// Set the timer resolution to 2 us
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetAutoReload(TIM17, 0xFFFF);
LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_SetAutoReload(TIM17, 500);
LL_TIM_SetPrescaler(TIM17, (64 << 1) - 1);
LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_DisableARRPreload(TIM17);
furi_hal_interrupt_set_isr(
FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL);
subghz_device_cc1101_ext_async_tx_middleware_idle(
&subghz_device_cc1101_ext->async_tx.middleware);
subghz_device_cc1101_ext_async_tx_refill(
subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL);
@@ -821,7 +879,6 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
// Start counter
LL_TIM_EnableDMAReq_UPDATE(TIM17);
LL_TIM_GenerateEvent_UPDATE(TIM17);
subghz_device_cc1101_ext_tx();
@@ -840,11 +897,15 @@ void subghz_device_cc1101_ext_stop_async_tx() {
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx ||
subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd);
// Deinitialize GPIO
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
furi_hal_gpio_init(
subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
// Shutdown radio
subghz_device_cc1101_ext_idle();
// Deinitialize Timer
FURI_CRITICAL_ENTER();
furi_hal_bus_disable(FuriHalBusTIM17);
furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL);
@@ -853,17 +914,11 @@ void subghz_device_cc1101_ext_stop_async_tx() {
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF);
furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL);
// Deinitialize GPIO
furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false);
furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
// Stop debug
if(subghz_device_cc1101_ext_stop_debug()) {
LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF);
}
FURI_CRITICAL_EXIT();
free(subghz_device_cc1101_ext->async_tx.buffer);
subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle;

View File

@@ -5,27 +5,8 @@ static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) {
Popup* popup = app->popup;
char curr_buf[32] = {};
//TODO: use .txt file in resources for passwords.
const uint32_t default_passwords[] = {
0x51243648, 0x000D8787, 0x19920427, 0x50524F58, 0xF9DCEBA0, 0x65857569, 0x05D73B9F,
0x89A69E60, 0x314159E0, 0xAA55BBBB, 0xA5B4C3D2, 0x1C0B5848, 0x00434343, 0x444E4752,
0x4E457854, 0x44B44CAE, 0x88661858, 0xE9920427, 0x575F4F4B, 0x50520901, 0x20206666,
0x65857569, 0x5469616E, 0x7686962A, 0xC0F5009A, 0x07CEE75D, 0xfeedbeef, 0xdeadc0de,
0x00000000, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666,
0x77777777, 0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD,
0xEEEEEEEE, 0xFFFFFFFF, 0xa0a1a2a3, 0xb0b1b2b3, 0x50415353, 0x00000001, 0x00000002,
0x0000000a, 0x0000000b, 0x01020304, 0x02030405, 0x03040506, 0x04050607, 0x05060708,
0x06070809, 0x0708090A, 0x08090A0B, 0x090A0B0C, 0x0A0B0C0D, 0x0B0C0D0E, 0x0C0D0E0F,
0x01234567, 0x12345678, 0x10000000, 0x20000000, 0x30000000, 0x40000000, 0x50000000,
0x60000000, 0x70000000, 0x80000000, 0x90000000, 0xA0000000, 0xB0000000, 0xC0000000,
0xD0000000, 0xE0000000, 0xF0000000, 0x10101010, 0x01010101, 0x11223344, 0x22334455,
0x33445566, 0x44556677, 0x55667788, 0x66778899, 0x778899AA, 0x8899AABB, 0x99AABBCC,
0xAABBCCDD, 0xBBCCDDEE, 0xCCDDEEFF, 0x0CB7E7FC, 0xFABADA11, 0x87654321, 0x12341234,
0x69696969, 0x12121212, 0x12344321, 0x1234ABCD, 0x11112222, 0x13131313, 0x10041004,
0x31415926, 0xabcd1234, 0x20002000, 0x19721972, 0xaa55aa55, 0x55aa55aa, 0x4f271149,
0x07d7bb0b, 0x9636ef8f, 0xb5f44686, 0x9E3779B9, 0xC6EF3720, 0x7854794A, 0xF1EA5EED,
0x69314718, 0x57721566, 0x93C467E3, 0x27182818, 0x50415353};
const uint8_t default_passwords_len = sizeof(default_passwords) / sizeof(uint32_t);
uint8_t default_passwords_len;
const uint32_t* default_passwords = t5577_get_default_passwords(&default_passwords_len);
popup_set_header(popup, "Removing\npassword", 90, 36, AlignCenter, AlignCenter);
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);

View File

@@ -6,6 +6,7 @@ ADD_SCENE(lfrfid, exit_confirm, ExitConfirm)
ADD_SCENE(lfrfid, delete_confirm, DeleteConfirm)
ADD_SCENE(lfrfid, read_key_menu, ReadKeyMenu)
ADD_SCENE(lfrfid, write, Write)
ADD_SCENE(lfrfid, write_with_pass, WriteWithPass)
ADD_SCENE(lfrfid, write_success, WriteSuccess)
ADD_SCENE(lfrfid, emulate, Emulate)
ADD_SCENE(lfrfid, save_name, SaveName)

View File

@@ -4,6 +4,7 @@
typedef enum {
SubmenuIndexEmulate,
SubmenuIndexWrite,
SubmenuIndexWriteWithPass,
SubmenuIndexEdit,
SubmenuIndexDelete,
SubmenuIndexInfo,
@@ -23,6 +24,12 @@ void lfrfid_scene_saved_key_menu_on_enter(void* context) {
submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Write", SubmenuIndexWrite, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
submenu,
"Write with pass",
SubmenuIndexWriteWithPass,
lfrfid_scene_saved_key_menu_submenu_callback,
app);
submenu_add_item(
submenu, "Edit", SubmenuIndexEdit, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
@@ -48,6 +55,9 @@ bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite);
consumed = true;
} else if(event.event == SubmenuIndexWriteWithPass) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteWithPass);
consumed = true;
} else if(event.event == SubmenuIndexEdit) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData);
consumed = true;

View File

@@ -0,0 +1,94 @@
#include "../lfrfid_i.h"
static void lfrfid_write_with_pass_callback(LFRFIDWorkerWriteResult result, void* context) {
LfRfid* app = context;
uint32_t event = 0;
if(result == LFRFIDWorkerWriteOK) {
event = LfRfidEventWriteOK;
} else if(result == LFRFIDWorkerWriteProtocolCannotBeWritten) {
event = LfRfidEventWriteProtocolCannotBeWritten;
} else if(result == LFRFIDWorkerWriteFobCannotBeWritten) {
event = LfRfidEventWriteFobCannotBeWritten;
} else if(result == LFRFIDWorkerWriteTooLongToWrite) {
event = LfRfidEventWriteTooLongToWrite;
}
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void lfrfid_scene_write_with_pass_on_enter(void* context) {
LfRfid* app = context;
Popup* popup = app->popup;
popup_set_header(popup, "Writing", 89, 30, AlignCenter, AlignTop);
if(!furi_string_empty(app->file_name)) {
popup_set_text(popup, furi_string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
} else {
popup_set_text(
popup,
protocol_dict_get_name(app->dict, app->protocol_id),
89,
43,
AlignCenter,
AlignTop);
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size);
lfrfid_worker_start_thread(app->lfworker);
lfrfid_worker_write_with_pass_start(
app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_with_pass_callback, app);
notification_message(app->notifications, &sequence_blink_start_magenta);
}
bool lfrfid_scene_write_with_pass_on_event(void* context, SceneManagerEvent event) {
LfRfid* app = context;
Popup* popup = app->popup;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == LfRfidEventWriteOK) {
notification_message(app->notifications, &sequence_success);
scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteSuccess);
consumed = true;
} else if(event.event == LfRfidEventWriteProtocolCannotBeWritten) {
popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42);
popup_set_header(popup, "Error", 64, 3, AlignCenter, AlignTop);
popup_set_text(popup, "This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop);
notification_message(app->notifications, &sequence_blink_start_red);
consumed = true;
} else if(
(event.event == LfRfidEventWriteFobCannotBeWritten) ||
(event.event == LfRfidEventWriteTooLongToWrite)) {
popup_set_icon(popup, 83, 22, &I_WarningDolphinFlip_45x42);
popup_set_header(popup, "Still trying to write...", 64, 3, AlignCenter, AlignTop);
popup_set_text(
popup,
"Make sure this\ncard is writable\nand not\nprotected.",
3,
17,
AlignLeft,
AlignTop);
notification_message(app->notifications, &sequence_blink_start_yellow);
consumed = true;
}
}
return consumed;
}
void lfrfid_scene_write_with_pass_on_exit(void* context) {
LfRfid* app = context;
notification_message(app->notifications, &sequence_blink_stop);
popup_reset(app->popup);
lfrfid_worker_stop(app->lfworker);
lfrfid_worker_stop_thread(app->lfworker);
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size);
}

View File

@@ -161,7 +161,7 @@ static bool washcity_parse(const NfcDevice* device, FuriString* parsed_data) {
furi_string_printf(
parsed_data,
"\e#WashCity\nCard number: %0*llX\nBalance: %lu.%02u USD",
"\e#WashCity\nCard number: %0*llX\nBalance: %lu.%02u EUR",
uid_len * 2,
card_number,
balance_usd,

View File

@@ -173,7 +173,6 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) {
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic);
nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance);
instance->nfc_dict_context.is_card_present = true;
}
static void nfc_scene_mf_classic_dict_attack_notify_read(NfcApp* instance) {

View File

@@ -249,7 +249,7 @@ fw_artifacts.extend(
)
fwcdb = fwenv.CompilationDatabase()
fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase()
# without filtering, both updater & firmware commands would be generated in same file
fwenv.Replace(
COMPILATIONDB_PATH_FILTER=fwenv.subst("*${FW_FLAVOR}*"),

View File

@@ -8,12 +8,14 @@ typedef enum {
LFRFIDEventStopMode = (1 << 1),
LFRFIDEventRead = (1 << 2),
LFRFIDEventWrite = (1 << 3),
LFRFIDEventEmulate = (1 << 4),
LFRFIDEventReadRaw = (1 << 5),
LFRFIDEventEmulateRaw = (1 << 6),
LFRFIDEventWriteWithPass = (1 << 4),
LFRFIDEventEmulate = (1 << 5),
LFRFIDEventReadRaw = (1 << 6),
LFRFIDEventEmulateRaw = (1 << 7),
LFRFIDEventAll =
(LFRFIDEventStopThread | LFRFIDEventStopMode | LFRFIDEventRead | LFRFIDEventWrite |
LFRFIDEventEmulate | LFRFIDEventReadRaw | LFRFIDEventEmulateRaw),
LFRFIDEventWriteWithPass | LFRFIDEventEmulate | LFRFIDEventReadRaw |
LFRFIDEventEmulateRaw),
} LFRFIDEventType;
static int32_t lfrfid_worker_thread(void* thread_context);
@@ -69,6 +71,18 @@ void lfrfid_worker_write_start(
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventWrite);
}
void lfrfid_worker_write_with_pass_start(
LFRFIDWorker* worker,
LFRFIDProtocol protocol,
LFRFIDWorkerWriteCallback callback,
void* context) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
worker->protocol = protocol;
worker->write_cb = callback;
worker->cb_ctx = context;
furi_thread_flags_set(furi_thread_get_id(worker->thread), LFRFIDEventWriteWithPass);
}
void lfrfid_worker_emulate_start(LFRFIDWorker* worker, LFRFIDProtocol protocol) {
furi_assert(worker->mode_index == LFRFIDWorkerIdle);
worker->protocol = protocol;
@@ -145,6 +159,7 @@ static int32_t lfrfid_worker_thread(void* thread_context) {
// switch mode
if(flags & LFRFIDEventRead) worker->mode_index = LFRFIDWorkerRead;
if(flags & LFRFIDEventWrite) worker->mode_index = LFRFIDWorkerWrite;
if(flags & LFRFIDEventWriteWithPass) worker->mode_index = LFRFIDWorkerWriteWithPass;
if(flags & LFRFIDEventEmulate) worker->mode_index = LFRFIDWorkerEmulate;
if(flags & LFRFIDEventReadRaw) worker->mode_index = LFRFIDWorkerReadRaw;
if(flags & LFRFIDEventEmulateRaw) worker->mode_index = LFRFIDWorkerEmulateRaw;

View File

@@ -106,6 +106,20 @@ void lfrfid_worker_write_start(
LFRFIDWorkerWriteCallback callback,
void* context);
/**
* @brief Start write with pass mode
*
* @param worker
* @param protocol
* @param callback
* @param context
*/
void lfrfid_worker_write_with_pass_start(
LFRFIDWorker* worker,
LFRFIDProtocol protocol,
LFRFIDWorkerWriteCallback callback,
void* context);
/**
* Start emulate mode
* @param worker

View File

@@ -22,6 +22,7 @@ typedef enum {
LFRFIDWorkerIdle,
LFRFIDWorkerRead,
LFRFIDWorkerWrite,
LFRFIDWorkerWriteWithPass,
LFRFIDWorkerEmulate,
LFRFIDWorkerReadRaw,
LFRFIDWorkerEmulateRaw,

View File

@@ -574,6 +574,96 @@ static void lfrfid_worker_mode_write_process(LFRFIDWorker* worker) {
free(read_data);
}
static void lfrfid_worker_mode_write_with_pass_process(LFRFIDWorker* worker) {
LFRFIDProtocol protocol = worker->protocol;
LFRFIDWriteRequest* request = malloc(sizeof(LFRFIDWriteRequest));
request->write_type = LFRFIDWriteTypeT5577;
bool can_be_written = protocol_dict_get_write_data(worker->protocols, protocol, request);
uint32_t write_start_time = furi_get_tick();
bool too_long = false;
size_t unsuccessful_reads = 0;
size_t data_size = protocol_dict_get_data_size(worker->protocols, protocol);
uint8_t* verify_data = malloc(data_size);
uint8_t* read_data = malloc(data_size);
protocol_dict_get_data(worker->protocols, protocol, verify_data, data_size);
if(can_be_written) {
while(!lfrfid_worker_check_for_stop(worker)) {
FURI_LOG_D(TAG, "Data write");
uint8_t size;
const uint32_t* password_list = t5577_get_default_passwords(&size);
uint32_t pass = password_list[rand() % size];
request->t5577.mask = 0b1111111;
request->t5577.block[0] |= 0b10000;
request->t5577.block[7] = pass;
t5577_write_with_mask(&request->t5577, 0, 0);
ProtocolId read_result = PROTOCOL_NO;
LFRFIDWorkerReadState state = lfrfid_worker_read_internal(
worker,
protocol_dict_get_features(worker->protocols, protocol),
LFRFID_WORKER_WRITE_VERIFY_TIME_MS,
&read_result);
if(state == LFRFIDWorkerReadOK) {
bool read_success = false;
if(read_result == protocol) {
protocol_dict_get_data(worker->protocols, protocol, read_data, data_size);
if(memcmp(read_data, verify_data, data_size) == 0) {
read_success = true;
}
}
if(read_success) {
FURI_LOG_D(TAG, "Write with password %08lX success", pass);
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteOK, worker->cb_ctx);
}
break;
} else {
unsuccessful_reads++;
if(unsuccessful_reads == LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS) {
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteFobCannotBeWritten, worker->cb_ctx);
}
}
}
} else if(state == LFRFIDWorkerReadExit) {
break;
}
if(!too_long &&
(furi_get_tick() - write_start_time) > LFRFID_WORKER_WRITE_TOO_LONG_TIME_MS) {
too_long = true;
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteTooLongToWrite, worker->cb_ctx);
}
}
lfrfid_worker_delay(worker, LFRFID_WORKER_WRITE_DROP_TIME_MS);
}
} else {
if(worker->write_cb) {
worker->write_cb(LFRFIDWorkerWriteProtocolCannotBeWritten, worker->cb_ctx);
}
}
free(request);
free(verify_data);
free(read_data);
}
/**************************************************************************************************/
/******************************************* READ RAW *********************************************/
/**************************************************************************************************/
@@ -629,6 +719,7 @@ const LFRFIDWorkerModeType lfrfid_worker_modes[] = {
[LFRFIDWorkerIdle] = {.process = NULL},
[LFRFIDWorkerRead] = {.process = lfrfid_worker_mode_read_process},
[LFRFIDWorkerWrite] = {.process = lfrfid_worker_mode_write_process},
[LFRFIDWorkerWriteWithPass] = {.process = lfrfid_worker_mode_write_with_pass_process},
[LFRFIDWorkerEmulate] = {.process = lfrfid_worker_mode_emulate_process},
[LFRFIDWorkerReadRaw] = {.process = lfrfid_worker_mode_read_raw_process},
[LFRFIDWorkerEmulateRaw] = {.process = lfrfid_worker_mode_emulate_raw_process},

View File

@@ -13,6 +13,33 @@
#define T5577_OPCODE_PAGE_1 0b11
#define T5577_OPCODE_RESET 0b00
#define T5577_BLOCKS_IN_PAGE_0 8
#define T5577_BLOCKS_IN_PAGE_1 4
//TODO: use .txt file in resources for passwords.
const uint32_t default_passwords[] = {
0x51243648, 0x000D8787, 0x19920427, 0x50524F58, 0xF9DCEBA0, 0x65857569, 0x05D73B9F, 0x89A69E60,
0x314159E0, 0xAA55BBBB, 0xA5B4C3D2, 0x1C0B5848, 0x00434343, 0x444E4752, 0x4E457854, 0x44B44CAE,
0x88661858, 0xE9920427, 0x575F4F4B, 0x50520901, 0x20206666, 0x65857569, 0x5469616E, 0x7686962A,
0xC0F5009A, 0x07CEE75D, 0xfeedbeef, 0xdeadc0de, 0x00000000, 0x11111111, 0x22222222, 0x33333333,
0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB,
0xCCCCCCCC, 0xDDDDDDDD, 0xEEEEEEEE, 0xFFFFFFFF, 0xa0a1a2a3, 0xb0b1b2b3, 0x50415353, 0x00000001,
0x00000002, 0x0000000a, 0x0000000b, 0x01020304, 0x02030405, 0x03040506, 0x04050607, 0x05060708,
0x06070809, 0x0708090A, 0x08090A0B, 0x090A0B0C, 0x0A0B0C0D, 0x0B0C0D0E, 0x0C0D0E0F, 0x01234567,
0x12345678, 0x10000000, 0x20000000, 0x30000000, 0x40000000, 0x50000000, 0x60000000, 0x70000000,
0x80000000, 0x90000000, 0xA0000000, 0xB0000000, 0xC0000000, 0xD0000000, 0xE0000000, 0xF0000000,
0x10101010, 0x01010101, 0x11223344, 0x22334455, 0x33445566, 0x44556677, 0x55667788, 0x66778899,
0x778899AA, 0x8899AABB, 0x99AABBCC, 0xAABBCCDD, 0xBBCCDDEE, 0xCCDDEEFF, 0x0CB7E7FC, 0xFABADA11,
0x87654321, 0x12341234, 0x69696969, 0x12121212, 0x12344321, 0x1234ABCD, 0x11112222, 0x13131313,
0x10041004, 0x31415926, 0xabcd1234, 0x20002000, 0x19721972, 0xaa55aa55, 0x55aa55aa, 0x4f271149,
0x07d7bb0b, 0x9636ef8f, 0xb5f44686, 0x9E3779B9, 0xC6EF3720, 0x7854794A, 0xF1EA5EED, 0x69314718,
0x57721566, 0x93C467E3, 0x27182818, 0x50415353};
const uint32_t* t5577_get_default_passwords(uint8_t* len) {
*len = sizeof(default_passwords) / sizeof(uint32_t);
return default_passwords;
}
static void t5577_start() {
furi_hal_rfid_tim_read_start(125000, 0.5);
@@ -52,6 +79,7 @@ static void t5577_write_reset() {
}
static void t5577_write_block_pass(
uint8_t page,
uint8_t block,
bool lock_bit,
uint32_t data,
@@ -62,8 +90,8 @@ static void t5577_write_block_pass(
// start gap
t5577_write_gap(T5577_TIMING_START_GAP);
// opcode for page 0
t5577_write_opcode(T5577_OPCODE_PAGE_0);
// opcode for page
t5577_write_opcode((page == 1) ? T5577_OPCODE_PAGE_1 : T5577_OPCODE_PAGE_0);
// password
if(with_pass) {
@@ -92,7 +120,7 @@ static void t5577_write_block_pass(
}
static void t5577_write_block_simple(uint8_t block, bool lock_bit, uint32_t data) {
t5577_write_block_pass(block, lock_bit, data, false, 0);
t5577_write_block_pass(0, block, lock_bit, data, false, 0);
}
void t5577_write(LFRFIDT5577* data) {
@@ -110,7 +138,26 @@ void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password) {
t5577_start();
FURI_CRITICAL_ENTER();
for(size_t i = 0; i < data->blocks_to_write; i++) {
t5577_write_block_pass(i, false, data->block[i], true, password);
t5577_write_block_pass(0, i, false, data->block[i], true, password);
}
t5577_write_reset();
FURI_CRITICAL_EXIT();
t5577_stop();
}
void t5577_write_with_mask(LFRFIDT5577* data, uint8_t page, uint32_t password) {
t5577_start();
FURI_CRITICAL_ENTER();
uint8_t mask = data->mask;
size_t pages_total = (page == 0) ? T5577_BLOCKS_IN_PAGE_0 : T5577_BLOCKS_IN_PAGE_1;
for(size_t i = 0; i < pages_total; i++) {
bool need_to_write = mask & 1;
mask >>= 1;
if(!need_to_write) continue;
t5577_write_block_pass(page, i, false, data->block[i], true, password);
}
t5577_write_reset();
FURI_CRITICAL_EXIT();

View File

@@ -42,8 +42,11 @@ extern "C" {
typedef struct {
uint32_t block[LFRFID_T5577_BLOCK_COUNT];
uint32_t blocks_to_write;
uint8_t mask;
} LFRFIDT5577;
const uint32_t* t5577_get_default_passwords(uint8_t* len);
/**
* @brief Write T5577 tag data to tag
*
@@ -53,6 +56,8 @@ void t5577_write(LFRFIDT5577* data);
void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password);
void t5577_write_with_mask(LFRFIDT5577* data, uint8_t page, uint32_t password);
#ifdef __cplusplus
}
#endif

View File

@@ -22,6 +22,7 @@ MfClassicPoller* mf_classic_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller)
instance->rx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE);
instance->rx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE);
instance->current_type_check = MfClassicType4k;
instance->card_state = MfClassicCardStateLost;
instance->mfc_event.data = &instance->mfc_event_data;

View File

@@ -18,7 +18,6 @@ struct SubGhzFileEncoderWorker {
volatile bool worker_running;
volatile bool worker_stopping;
bool level;
bool is_storage_slow;
FuriString* str_data;
FuriString* file_path;
@@ -41,19 +40,8 @@ void subghz_file_encoder_worker_callback_end(
void subghz_file_encoder_worker_add_level_duration(
SubGhzFileEncoderWorker* instance,
int32_t duration) {
bool res = true;
if(duration < 0 && !instance->level) {
res = false;
} else if(duration > 0 && instance->level) {
res = false;
}
if(res) {
instance->level = !instance->level;
furi_stream_buffer_send(instance->stream, &duration, sizeof(int32_t), 100);
} else {
FURI_LOG_E(TAG, "Invalid level in the stream");
}
size_t ret = furi_stream_buffer_send(instance->stream, &duration, sizeof(int32_t), 100);
if(sizeof(int32_t) != ret) FURI_LOG_E(TAG, "Invalid add duration in the stream");
}
bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, const char* strStart) {
@@ -214,7 +202,6 @@ SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() {
instance->str_data = furi_string_alloc();
instance->file_path = furi_string_alloc();
instance->level = false;
instance->worker_stopping = true;
return instance;

View File

@@ -25,6 +25,9 @@ ICONS_TEMPLATE_C_FRAME = "const uint8_t {name}[] = {data};\n"
ICONS_TEMPLATE_C_DATA = "const uint8_t* const {name}[] = {data};\n"
ICONS_TEMPLATE_C_ICONS = "Icon {name} = {{.width={width},.height={height},.frame_count={frame_count},.frame_rate={frame_rate},.frames=_{name}}};\n"
MAX_IMAGE_WIDTH = 128
MAX_IMAGE_HEIGHT = 64
class Main(App):
def init(self):
@@ -112,6 +115,10 @@ class Main(App):
def _icon2header(self, file):
image = file2image(file)
if image.width > MAX_IMAGE_WIDTH or image.height > MAX_IMAGE_HEIGHT:
raise Exception(
f"Image {file} is too big ({image.width}x{image.height} vs. {MAX_IMAGE_WIDTH}x{MAX_IMAGE_HEIGHT})"
)
return image.width, image.height, image.data_as_carray()
def _iconIsSupported(self, filename):

View File

@@ -275,15 +275,16 @@ Default(install_and_check)
# Compilation database
fwcdb = appenv.CompilationDatabase(
app_cdb = appenv.CompilationDatabase(
original_app_dir.Dir(".vscode").File("compile_commands.json")
)
AlwaysBuild(fwcdb)
Precious(fwcdb)
NoClean(fwcdb)
AlwaysBuild(app_cdb)
Precious(app_cdb)
NoClean(app_cdb)
if len(apps_artifacts):
Default(fwcdb)
Default(app_cdb)
Alias("cdb", app_cdb)
# launch handler
@@ -381,7 +382,7 @@ for config_file in project_template_dir.glob(".*"):
dist_env.Precious(vscode_dist)
dist_env.NoClean(vscode_dist)
dist_env.Alias("vscode_dist", vscode_dist)
dist_env.Alias("vscode_dist", (vscode_dist, app_cdb))
# Creating app from base template

View File

@@ -18,6 +18,8 @@ Building:
Build all FAP apps
fap_{APPID}, launch APPSRC={APPID}:
Build FAP app with appid={APPID}; upload & start it over USB
cdb:
regenerate "compile_commands.json" file (for IDE integration)
Flashing & debugging:
flash, *jflash:

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,50.1,,
Version,+,50.2,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
1 entry status name type params
2 Version + 50.1 50.2
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,50.1,,
Version,+,50.2,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/main/archive/helpers/archive_helpers_ext.h,,
Header,+,applications/services/applications.h,,
@@ -2093,6 +2093,7 @@ Function,+,lfrfid_worker_start_thread,void,LFRFIDWorker*
Function,+,lfrfid_worker_stop,void,LFRFIDWorker*
Function,+,lfrfid_worker_stop_thread,void,LFRFIDWorker*
Function,+,lfrfid_worker_write_start,void,"LFRFIDWorker*, LFRFIDProtocol, LFRFIDWorkerWriteCallback, void*"
Function,+,lfrfid_worker_write_with_pass_start,void,"LFRFIDWorker*, LFRFIDProtocol, LFRFIDWorkerWriteCallback, void*"
Function,-,lgamma,double,double
Function,-,lgamma_r,double,"double, int*"
Function,-,lgammaf,float,float
@@ -3278,7 +3279,9 @@ Function,+,submenu_set_header,void,"Submenu*, const char*"
Function,+,submenu_set_orientation,void,"Submenu*, ViewOrientation"
Function,+,submenu_set_selected_item,void,"Submenu*, uint32_t"
Function,-,system,int,const char*
Function,+,t5577_get_default_passwords,const uint32_t*,uint8_t*
Function,+,t5577_write,void,LFRFIDT5577*
Function,+,t5577_write_with_mask,void,"LFRFIDT5577*, uint8_t, uint32_t"
Function,+,t5577_write_with_pass,void,"LFRFIDT5577*, uint32_t"
Function,-,tan,double,double
Function,-,tanf,float,float
1 entry status name type params
2 Version + 50.1 50.2
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/main/archive/helpers/archive_helpers_ext.h
5 Header + applications/services/applications.h
2093 Function + lfrfid_worker_stop void LFRFIDWorker*
2094 Function + lfrfid_worker_stop_thread void LFRFIDWorker*
2095 Function + lfrfid_worker_write_start void LFRFIDWorker*, LFRFIDProtocol, LFRFIDWorkerWriteCallback, void*
2096 Function + lfrfid_worker_write_with_pass_start void LFRFIDWorker*, LFRFIDProtocol, LFRFIDWorkerWriteCallback, void*
2097 Function - lgamma double double
2098 Function - lgamma_r double double, int*
2099 Function - lgammaf float float
3279 Function + submenu_set_orientation void Submenu*, ViewOrientation
3280 Function + submenu_set_selected_item void Submenu*, uint32_t
3281 Function - system int const char*
3282 Function + t5577_get_default_passwords const uint32_t* uint8_t*
3283 Function + t5577_write void LFRFIDT5577*
3284 Function + t5577_write_with_mask void LFRFIDT5577*, uint8_t, uint32_t
3285 Function + t5577_write_with_pass void LFRFIDT5577*, uint32_t
3286 Function - tan double double
3287 Function - tanf float float

View File

@@ -17,13 +17,13 @@
#define TAG "FuriHalSubGhz"
static uint32_t furi_hal_subghz_debug_gpio_buff[2];
static uint32_t furi_hal_subghz_debug_gpio_buff[2] = {0};
/* DMA Channels definition */
#define SUBGHZ_DMA DMA2
#define SUBGHZ_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1
#define SUBGHZ_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2
#define SUBGHZ_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1
#define SUBGHZ_DMA (DMA2)
#define SUBGHZ_DMA_CH1_CHANNEL (LL_DMA_CHANNEL_1)
#define SUBGHZ_DMA_CH2_CHANNEL (LL_DMA_CHANNEL_2)
#define SUBGHZ_DMA_CH1_IRQ (FuriHalInterruptIdDma2Ch1)
#define SUBGHZ_DMA_CH1_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH1_CHANNEL
#define SUBGHZ_DMA_CH2_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH2_CHANNEL
@@ -36,7 +36,6 @@ typedef enum {
SubGhzStateAsyncRx, /**< Async RX started */
SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */
SubGhzStateAsyncTxLast, /**< Async TX continue, DMA completed and timer got last value to go */
SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */
} SubGhzState;
@@ -106,6 +105,10 @@ void furi_hal_subghz_init() {
&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
#endif
#ifdef FURI_HAL_SUBGHZ_ASYNC_MIRROR_GPIO
furi_hal_subghz_set_async_mirror_pin(&FURI_HAL_SUBGHZ_ASYNC_MIRROR_GPIO);
#endif
// Reset
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
@@ -185,8 +188,8 @@ void furi_hal_subghz_dump_state() {
void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) {
//load config
furi_hal_subghz_reset();
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
uint32_t i = 0;
uint8_t pa[8] = {0};
while(preset_data[i]) {
@@ -214,8 +217,8 @@ void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) {
}
void furi_hal_subghz_load_registers(const uint8_t* data) {
furi_hal_subghz_reset();
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
uint32_t i = 0;
while(data[i]) {
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i], data[i + 1]);
@@ -294,6 +297,7 @@ void furi_hal_subghz_reset() {
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
// Warning: push pull cc1101 clock output on GD0
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
}
@@ -435,6 +439,7 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
static bool furi_hal_subghz_start_debug() {
bool ret = false;
if(furi_hal_subghz.async_mirror_pin != NULL) {
furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false);
furi_hal_gpio_init(
furi_hal_subghz.async_mirror_pin,
GpioModeOutputPushPull,
@@ -576,73 +581,121 @@ void furi_hal_subghz_stop_async_rx() {
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
}
typedef enum {
FuriHalSubGhzAsyncTxMiddlewareStateIdle,
FuriHalSubGhzAsyncTxMiddlewareStateReset,
FuriHalSubGhzAsyncTxMiddlewareStateRun,
} FuriHalSubGhzAsyncTxMiddlewareState;
typedef struct {
FuriHalSubGhzAsyncTxMiddlewareState state;
bool is_odd_level;
uint32_t adder_duration;
} FuriHalSubGhzAsyncTxMiddleware;
typedef struct {
uint32_t* buffer;
LevelDuration carry_ld;
FuriHalSubGhzAsyncTxCallback callback;
void* callback_context;
uint64_t duty_high;
uint64_t duty_low;
FuriHalSubGhzAsyncTxMiddleware middleware;
} FuriHalSubGhzAsyncTx;
static FuriHalSubGhzAsyncTx furi_hal_subghz_async_tx = {0};
static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx);
while(samples > 0) {
bool is_odd = samples % 2;
LevelDuration ld;
if(level_duration_is_reset(furi_hal_subghz_async_tx.carry_ld)) {
ld = furi_hal_subghz_async_tx.callback(furi_hal_subghz_async_tx.callback_context);
} else {
ld = furi_hal_subghz_async_tx.carry_ld;
furi_hal_subghz_async_tx.carry_ld = level_duration_reset();
void furi_hal_subghz_async_tx_middleware_idle(FuriHalSubGhzAsyncTxMiddleware* middleware) {
middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateIdle;
middleware->is_odd_level = false;
middleware->adder_duration = 0;
}
static inline uint32_t furi_hal_subghz_async_tx_middleware_get_duration(
FuriHalSubGhzAsyncTxMiddleware* middleware,
FuriHalSubGhzAsyncTxCallback callback) {
uint32_t ret = 0;
bool is_level = false;
if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateReset) return 0;
while(1) {
LevelDuration ld = callback(furi_hal_subghz_async_tx.callback_context);
if(level_duration_is_reset(ld)) {
middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateReset;
if(!middleware->is_odd_level) {
return 0;
} else {
return middleware->adder_duration;
}
} else if(level_duration_is_wait(ld)) {
middleware->is_odd_level = !middleware->is_odd_level;
ret = middleware->adder_duration + FURI_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
middleware->adder_duration = 0;
return ret;
}
if(level_duration_is_wait(ld)) {
*buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
buffer++;
samples--;
} else if(level_duration_is_reset(ld)) {
is_level = level_duration_get_level(ld);
if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateIdle) {
if(is_level != middleware->is_odd_level) {
middleware->state = FuriHalSubGhzAsyncTxMiddlewareStateRun;
middleware->is_odd_level = is_level;
middleware->adder_duration = 0;
} else {
continue;
}
}
if(middleware->state == FuriHalSubGhzAsyncTxMiddlewareStateRun) {
if(is_level == middleware->is_odd_level) {
middleware->adder_duration += level_duration_get_duration(ld);
continue;
} else {
middleware->is_odd_level = is_level;
ret = middleware->adder_duration;
middleware->adder_duration = level_duration_get_duration(ld);
return ret;
}
}
}
}
static void furi_hal_subghz_async_tx_refill(uint32_t* buffer, size_t samples) {
furi_assert(furi_hal_subghz.state == SubGhzStateAsyncTx);
while(samples > 0) {
volatile uint32_t duration = furi_hal_subghz_async_tx_middleware_get_duration(
&furi_hal_subghz_async_tx.middleware, furi_hal_subghz_async_tx.callback);
if(duration == 0) {
*buffer = 0;
buffer++;
samples--;
LL_DMA_DisableIT_HT(SUBGHZ_DMA_CH1_DEF);
LL_DMA_DisableIT_TC(SUBGHZ_DMA_CH1_DEF);
if(LL_DMA_IsActiveFlag_HT1(SUBGHZ_DMA)) {
LL_DMA_ClearFlag_HT1(SUBGHZ_DMA);
}
if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) {
LL_DMA_ClearFlag_TC1(SUBGHZ_DMA);
}
LL_TIM_EnableIT_UPDATE(TIM2);
break;
} else {
bool level = level_duration_get_level(ld);
// Inject guard time if level is incorrect
if(is_odd != level) {
*buffer = API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
buffer++;
samples--;
if(is_odd) {
furi_hal_subghz_async_tx.duty_high += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
} else {
furi_hal_subghz_async_tx.duty_low += API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME;
}
// Special case: prevent buffer overflow if sample is last
if(samples == 0) {
furi_hal_subghz_async_tx.carry_ld = ld;
break;
}
// Lowest possible value is 2us
if(duration > 2) {
// Subtract 1 since we counting from 0
*buffer = duration - 1;
} else {
*buffer = 1;
}
uint32_t duration = level_duration_get_duration(ld);
furi_assert(duration > 0);
*buffer = duration;
buffer++;
samples--;
}
if(is_odd) {
furi_hal_subghz_async_tx.duty_high += duration;
} else {
furi_hal_subghz_async_tx.duty_low += duration;
}
if(samples % 2) {
furi_hal_subghz_async_tx.duty_high += duration;
} else {
furi_hal_subghz_async_tx.duty_low += duration;
}
}
}
@@ -654,13 +707,13 @@ static void furi_hal_subghz_async_tx_dma_isr() {
if(LL_DMA_IsActiveFlag_HT1(SUBGHZ_DMA)) {
LL_DMA_ClearFlag_HT1(SUBGHZ_DMA);
furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
}
if(LL_DMA_IsActiveFlag_TC1(SUBGHZ_DMA)) {
LL_DMA_ClearFlag_TC1(SUBGHZ_DMA);
furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer + API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF,
API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
furi_hal_subghz_async_tx.buffer + FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF,
FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF);
}
#else
#error Update this code. Would you kindly?
@@ -672,15 +725,11 @@ static void furi_hal_subghz_async_tx_timer_isr() {
LL_TIM_ClearFlag_UPDATE(TIM2);
if(LL_TIM_GetAutoReload(TIM2) == 0) {
if(furi_hal_subghz.state == SubGhzStateAsyncTx) {
furi_hal_subghz.state = SubGhzStateAsyncTxLast;
LL_DMA_DisableChannel(SUBGHZ_DMA_CH1_DEF);
} else if(furi_hal_subghz.state == SubGhzStateAsyncTxLast) {
furi_hal_subghz.state = SubGhzStateAsyncTxEnd;
LL_DMA_DisableChannel(SUBGHZ_DMA_CH1_DEF);
//forcibly pulls the pin to the ground so that there is no carrier
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullDown, GpioSpeedLow);
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
LL_TIM_DisableCounter(TIM2);
} else {
furi_crash();
}
}
}
@@ -702,7 +751,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
furi_hal_subghz_async_tx.duty_high = 0;
furi_hal_subghz_async_tx.buffer =
malloc(API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
malloc(FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t));
// Connect CC1101_GD0 to TIM2 as output
furi_hal_gpio_init_ex(
@@ -718,7 +767,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
dma_config.NbData = API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL;
dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL;
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
dma_config.Priority = LL_DMA_MODE_NORMAL;
LL_DMA_Init(SUBGHZ_DMA_CH1_DEF, &dma_config);
@@ -730,14 +779,12 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
furi_hal_bus_enable(FuriHalBusTIM2);
// Configure TIM2
LL_TIM_InitTypeDef TIM_InitStruct = {0};
TIM_InitStruct.Prescaler = 64 - 1;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 1000;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
LL_TIM_Init(TIM2, &TIM_InitStruct);
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_SetAutoReload(TIM2, 1000);
LL_TIM_SetPrescaler(TIM2, 64 - 1);
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_EnableARRPreload(TIM2);
LL_TIM_DisableARRPreload(TIM2);
// Configure TIM2 CH2
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
@@ -745,21 +792,21 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.CompareValue = 0;
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_LOW;
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct);
LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2);
LL_TIM_DisableMasterSlaveMode(TIM2);
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_async_tx_timer_isr, NULL);
furi_hal_subghz_async_tx_middleware_idle(&furi_hal_subghz_async_tx.middleware);
furi_hal_subghz_async_tx_refill(
furi_hal_subghz_async_tx.buffer, API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
furi_hal_subghz_async_tx.buffer, FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL);
LL_TIM_EnableDMAReq_UPDATE(TIM2);
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
// Start counter
LL_TIM_GenerateEvent_UPDATE(TIM2);
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
furi_hal_gpio_write(&FURI_HAL_SUBGHZ_TX_GPIO, true);
#endif
@@ -776,8 +823,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
// furi_hal_subghz_debug_gpio_buff[0] = 0;
// furi_hal_subghz_debug_gpio_buff[1] = 0;
furi_hal_subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
furi_hal_subghz_debug_gpio_buff[1] = gpio->pin;
furi_hal_subghz_debug_gpio_buff[0] = gpio->pin;
furi_hal_subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER;
dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff;
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR);
@@ -805,9 +852,12 @@ bool furi_hal_subghz_is_async_tx_complete() {
void furi_hal_subghz_stop_async_tx() {
furi_assert(
furi_hal_subghz.state == SubGhzStateAsyncTx ||
furi_hal_subghz.state == SubGhzStateAsyncTxLast ||
furi_hal_subghz.state == SubGhzStateAsyncTxEnd);
// Deinitialize GPIO
// Keep in mind that cc1101 will try to pull it up in idle.
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
// Shutdown radio
furi_hal_subghz_idle();
#ifdef FURI_HAL_SUBGHZ_TX_GPIO
@@ -815,7 +865,6 @@ void furi_hal_subghz_stop_async_tx() {
#endif
// Deinitialize Timer
FURI_CRITICAL_ENTER();
furi_hal_bus_disable(FuriHalBusTIM2);
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL);
@@ -824,16 +873,11 @@ void furi_hal_subghz_stop_async_tx() {
furi_hal_interrupt_set_isr(SUBGHZ_DMA_CH1_IRQ, NULL, NULL);
// Deinitialize GPIO
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
// Stop debug
if(furi_hal_subghz_stop_debug()) {
LL_DMA_DisableChannel(SUBGHZ_DMA_CH2_DEF);
}
FURI_CRITICAL_EXIT();
free(furi_hal_subghz_async_tx.buffer);
float duty_cycle =

View File

@@ -18,10 +18,10 @@
extern "C" {
#endif
/** Low level buffer dimensions and guard times */
#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256)
#define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2)
#define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 999
/** Various subghz defines */
#define FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL (256u)
#define FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2)
#define FURI_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME (999u)
/** Switchable Radio Paths */
typedef enum {