From 8c04947aa2802502d58cc66bcb9f03e0d3faf5e7 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 10 Jan 2024 14:37:28 +0300 Subject: [PATCH 1/5] ufbt: fixed generated project paths on Windows (#3339) --- scripts/ufbt/SConstruct | 2 +- scripts/ufbt/project_template/.vscode/c_cpp_properties.json | 2 +- scripts/ufbt/project_template/.vscode/extensions.json | 4 ++++ scripts/ufbt/project_template/.vscode/launch.json | 4 ++++ scripts/ufbt/project_template/.vscode/settings.json | 4 ++++ scripts/ufbt/project_template/.vscode/tasks.json | 4 ++++ 6 files changed, 18 insertions(+), 2 deletions(-) diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 2fc170ad9..9edeb46fc 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -365,7 +365,7 @@ for template_file in project_template_dir.Dir(".vscode").glob("*"): "@UFBT_TOOLCHAIN_OPENOCD@": _path_as_posix(dist_env.WhereIs("openocd")), "@UFBT_APP_DIR@": _path_as_posix(original_app_dir.abspath), "@UFBT_ROOT_DIR@": _path_as_posix(Dir("#").abspath), - "@UFBT_DEBUG_DIR@": dist_env["FBT_DEBUG_DIR"], + "@UFBT_DEBUG_DIR@": _path_as_posix(dist_env["FBT_DEBUG_DIR"].abspath), "@UFBT_DEBUG_ELF_DIR@": _path_as_posix( dist_env["FBT_FAP_DEBUG_ELF_ROOT"].abspath ), diff --git a/scripts/ufbt/project_template/.vscode/c_cpp_properties.json b/scripts/ufbt/project_template/.vscode/c_cpp_properties.json index 922a9091b..f957ee98b 100644 --- a/scripts/ufbt/project_template/.vscode/c_cpp_properties.json +++ b/scripts/ufbt/project_template/.vscode/c_cpp_properties.json @@ -8,7 +8,7 @@ "configurationProvider": "ms-vscode.cpptools", "cStandard": "gnu17", "cppStandard": "c++17" - }, + } ], "version": 4 } \ No newline at end of file diff --git a/scripts/ufbt/project_template/.vscode/extensions.json b/scripts/ufbt/project_template/.vscode/extensions.json index ead935b08..9daefb430 100644 --- a/scripts/ufbt/project_template/.vscode/extensions.json +++ b/scripts/ufbt/project_template/.vscode/extensions.json @@ -1,3 +1,7 @@ +// This file is autogeneated by the ufbt. +// You can modify it, and it will not be overwritten if exists. +// Some paths are absolute, and will need to be updated if you move the project. +// To regenerate the file, delete it and run `ufbt vscode_dist` again. { // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp diff --git a/scripts/ufbt/project_template/.vscode/launch.json b/scripts/ufbt/project_template/.vscode/launch.json index 3269bab57..a5639743f 100644 --- a/scripts/ufbt/project_template/.vscode/launch.json +++ b/scripts/ufbt/project_template/.vscode/launch.json @@ -1,3 +1,7 @@ +// This file is autogeneated by the ufbt. +// You can modify it, and it will not be overwritten if exists. +// Some paths are absolute, and will need to be updated if you move the project. +// To regenerate the file, delete it and run `ufbt vscode_dist` again. { // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", diff --git a/scripts/ufbt/project_template/.vscode/settings.json b/scripts/ufbt/project_template/.vscode/settings.json index 33cd3f035..ce5210f5f 100644 --- a/scripts/ufbt/project_template/.vscode/settings.json +++ b/scripts/ufbt/project_template/.vscode/settings.json @@ -1,3 +1,7 @@ +// This file is autogeneated by the ufbt. +// You can modify it, and it will not be overwritten if exists. +// Some paths are absolute, and will need to be updated if you move the project. +// To regenerate the file, delete it and run `ufbt vscode_dist` again. { "cortex-debug.enableTelemetry": false, "cortex-debug.variableUseNaturalFormat": false, diff --git a/scripts/ufbt/project_template/.vscode/tasks.json b/scripts/ufbt/project_template/.vscode/tasks.json index 4b3f4bda5..65c749e07 100644 --- a/scripts/ufbt/project_template/.vscode/tasks.json +++ b/scripts/ufbt/project_template/.vscode/tasks.json @@ -1,3 +1,7 @@ +// This file is autogeneated by the ufbt. +// You can modify it, and it will not be overwritten if exists. +// Some paths are absolute, and will need to be updated if you move the project. +// To regenerate the file, delete it and run `ufbt vscode_dist` again. { // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format From 3452fbc351081abce881280181c963df3aa744e9 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:46:55 +0300 Subject: [PATCH 2/5] [FL-3744] [NFC] Ntag success write freeze when not saved card (#3354) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New scenes for ultralight poller write mode * Added new button and transition logic for write operation For now write is only possible for NTAG21x cards with default password and no AUTHLIM set * Poller states extended * Enums and datatypes extended for new poller mode * Added mode field to poller instance datatype * New states for poller added in order to implement write mode * Added new event type for locked cards in order to simplify state flow * New logic for poller write commands * Scenes adjustments * Scenes renamed * New field added to poller instance * Now we write in 'page per call' mode * Now function takes callback return value into account * Callback will be called only in write mode * Event type added * Log adjusted and start page to write set * Logs added and check in now false at start, then it moves to true * Now mf_ultralight_poller_handler_request_write_data halts card in case of check failure and stops poller * All fail events now returns NfcCommandStop callback * In case of fail we move back properly * Remove garbage * Fix moving to previous screen in case of not saved ultralight Co-authored-by: gornekich Co-authored-by: あく --- .../main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c index 9726ef283..bb34190d2 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c @@ -28,8 +28,11 @@ bool nfc_scene_mf_ultralight_write_success_on_event(void* context, SceneManagerE if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { + bool was_saved = + scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu); + consumed = scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, NfcSceneSavedMenu); + instance->scene_manager, was_saved ? NfcSceneSavedMenu : NfcSceneReadSuccess); } } return consumed; From 4d99a454fda10eac58a496e80159a1a983b42e7e Mon Sep 17 00:00:00 2001 From: Leptopt1los <53914086+Leptopt1los@users.noreply.github.com> Date: Wed, 10 Jan 2024 20:55:45 +0900 Subject: [PATCH 3/5] NFC: parsers minor cleanup (#3329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WashCity cards parser cleanup * umarsh includes cleanup Co-authored-by: gornekich Co-authored-by: あく --- .../main/nfc/plugins/supported_cards/umarsh.c | 3 +-- .../main/nfc/plugins/supported_cards/washcity.c | 13 +++---------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/umarsh.c b/applications/main/nfc/plugins/supported_cards/umarsh.c index a85c056f6..bf643d21c 100644 --- a/applications/main/nfc/plugins/supported_cards/umarsh.c +++ b/applications/main/nfc/plugins/supported_cards/umarsh.c @@ -32,8 +32,7 @@ #include #include #include -#include -#include + #include #define TAG "Umarsh" diff --git a/applications/main/nfc/plugins/supported_cards/washcity.c b/applications/main/nfc/plugins/supported_cards/washcity.c index a0edeef6a..c90c8abbc 100644 --- a/applications/main/nfc/plugins/supported_cards/washcity.c +++ b/applications/main/nfc/plugins/supported_cards/washcity.c @@ -26,7 +26,6 @@ #include #include #include -#include #define TAG "WashCity" @@ -158,18 +157,12 @@ static bool washcity_parse(const NfcDevice* device, FuriString* parsed_data) { const uint8_t* uid = mf_classic_get_uid(data, &uid_len); // Card Number is printed in HEX (equal to UID) - char card_number[2 * uid_len + 1]; - - for(size_t i = 0; i < uid_len; ++i) { - card_number[2 * i] = "0123456789ABCDEF"[uid[i] >> 4]; - card_number[2 * i + 1] = "0123456789ABCDEF"[uid[i] & 0xF]; - } - - card_number[2 * uid_len] = '\0'; + uint64_t card_number = nfc_util_bytes2num(uid, uid_len); furi_string_printf( parsed_data, - "\e#WashCity\nCard number: %s\nBalance: %lu.%02u EUR", + "\e#WashCity\nCard number: %0*llX\nBalance: %lu.%02u EUR", + uid_len * 2, card_number, balance_eur, balance_cents); From 0b15fc38078716e4bd8af689deac124aeb0dbcbd Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Wed, 10 Jan 2024 14:49:30 +0100 Subject: [PATCH 4/5] Fix MyKey production date parsing (#3332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: gornekich Co-authored-by: あく --- .../main/nfc/plugins/supported_cards/mykey.c | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/mykey.c b/applications/main/nfc/plugins/supported_cards/mykey.c index a0e206f9c..1b7493307 100644 --- a/applications/main/nfc/plugins/supported_cards/mykey.c +++ b/applications/main/nfc/plugins/supported_cards/mykey.c @@ -16,6 +16,35 @@ static bool mykey_has_lockid(const St25tbData* data) { return (data->blocks[5] & 0xFF) == 0x7F; } +static bool check_invalid_low_nibble(uint8_t value) { + uint8_t value_lo = value & 0xF; + return value_lo >= 0xA; +} + +static bool mykey_get_production_date( + const St25tbData* data, + uint16_t* year_ptr, + uint8_t* month_ptr, + uint8_t* day_ptr) { + uint32_t date_block = data->blocks[8]; + uint8_t year = date_block >> 16 & 0xFF; + uint8_t month = date_block >> 8 & 0xFF; + uint8_t day = date_block & 0xFF; + // dates are coded in a peculiar way, the hexadecimal value should in fact be interpreted as a decimal value + // so anything in range A-F is invalid. + if(day > 0x31 || month > 0x12 || day == 0 || month == 0 || year == 0) { + return false; + } + if(check_invalid_low_nibble(day) || check_invalid_low_nibble(month) || + check_invalid_low_nibble(year) || check_invalid_low_nibble(year >> 4)) { + return false; + } + *year_ptr = year + 0x2000; + *month_ptr = month; + *day_ptr = day; + return true; +} + static bool mykey_parse(const NfcDevice* device, FuriString* parsed_data) { furi_assert(device); furi_assert(parsed_data); @@ -34,7 +63,10 @@ static bool mykey_parse(const NfcDevice* device, FuriString* parsed_data) { } } - if((data->blocks[8] >> 16 & 0xFF) > 0x31 || (data->blocks[8] >> 8 & 0xFF) > 0x12) { + uint16_t mfg_year; + uint8_t mfg_month, mfg_day; + + if(!mykey_get_production_date(data, &mfg_year, &mfg_month, &mfg_day)) { FURI_LOG_D(TAG, "bad mfg date"); return false; } @@ -56,13 +88,8 @@ static bool mykey_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_cat_printf(parsed_data, "Blank: %s\n", is_blank ? "yes" : "no"); furi_string_cat_printf(parsed_data, "LockID: %s\n", mykey_has_lockid(data) ? "maybe" : "no"); - uint32_t block8 = data->blocks[8]; furi_string_cat_printf( - parsed_data, - "Prod. date: %02lX/%02lX/%04lX", - block8 >> 16 & 0xFF, - block8 >> 8 & 0xFF, - 0x2000 + (block8 & 0xFF)); + parsed_data, "Prod. date: %02X/%02X/%04X", mfg_day, mfg_month, mfg_year); if(!is_blank) { furi_string_cat_printf( From 34539cda1738e70affb2718f12f1be72ee57afcd Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Thu, 11 Jan 2024 11:56:14 +0400 Subject: [PATCH 5/5] FuriHal: fix start duration furi_hal_subghz_async_tx (#3230) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FuriHal: fix start duration furi_hal_subghz_async_tx * FuriHal: add check min duration arr for the first level * FuriHal: fix conflict dev * SubGhz: fix unit_test * FuriHal: subghz internal fix start/stop transmit duration * Drivers: subghz external fix start/stop transmit duration * FuriHal: subghz optimization * SubGhz: fix unit_test subghz * FuriHal: subghz fix end duration if size == size dma buf * FuriHal: revert enum values order, remove garbage * FuriHal: revert one more small bit in subghz * FuriHal: handle various corner cases in subghz transmission * FuriHal: cleanup subghz code * FuriHal: add parenthesis around value in subghz defines * FuriHal: add packer subghz_async_tx * FuriHal: more reliable subghz transmission end handling, fixes stuck transmission * FuriHal: add subghz crutch docs, and rename some defines to conform naming standards * FuriHal: subghz, the logic of timers has been changed. disabling the shadow register ARR * FuriHal: fix subghz off dma irq * SubGhzExt: fun rename * FuriHal,SubGhz: fix g0 state on reset, fix incorrect async_tx stop sequence, remove dead code. Co-authored-by: あく --- .../debug/unit_tests/subghz/subghz_test.c | 32 +-- .../drivers/subghz/cc1101_ext/cc1101_ext.c | 177 +++++++++------ lib/subghz/subghz_file_encoder_worker.c | 17 +- targets/f7/furi_hal/furi_hal_subghz.c | 206 +++++++++++------- targets/f7/furi_hal/furi_hal_subghz.h | 8 +- 5 files changed, 264 insertions(+), 176 deletions(-) diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index 60c7abd03..53894c551 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -231,17 +231,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 { @@ -251,36 +251,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 { @@ -294,20 +294,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 { @@ -334,6 +334,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); diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c index c70831628..348f3891b 100644 --- a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -18,14 +18,14 @@ #define TAG "SubGhzDeviceCc1101Ext" -#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2 +#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO (&gpio_ext_pb2) /* 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 \ @@ -34,10 +34,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 { @@ -55,13 +55,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 { @@ -259,8 +271,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]) { @@ -289,8 +301,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]); @@ -371,6 +383,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); @@ -563,50 +576,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--; } @@ -638,12 +692,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); } @@ -693,16 +749,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); @@ -748,7 +806,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(); @@ -767,11 +824,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); @@ -780,17 +841,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; diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 3c045c269..239e02985 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -18,7 +18,6 @@ struct SubGhzFileEncoderWorker { volatile bool worker_running; volatile bool worker_stoping; - 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) { @@ -190,7 +178,6 @@ SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() { instance->str_data = furi_string_alloc(); instance->file_path = furi_string_alloc(); - instance->level = false; instance->worker_stoping = true; return instance; diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index a00ca7bf6..43164a096 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -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; @@ -79,6 +78,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); @@ -158,8 +161,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]) { @@ -187,8 +190,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]); @@ -266,6 +269,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); } @@ -382,6 +386,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, @@ -522,73 +527,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; } } } @@ -600,13 +653,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? @@ -618,15 +671,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(); } } } @@ -648,7 +697,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( @@ -664,7 +713,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); @@ -676,14 +725,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}; @@ -691,21 +738,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 @@ -717,8 +764,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* // Start debug if(furi_hal_subghz_start_debug()) { const GpioPin* gpio = furi_hal_subghz.async_mirror_pin; - 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); @@ -746,9 +793,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 @@ -756,7 +806,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); @@ -765,16 +814,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 = diff --git a/targets/f7/furi_hal/furi_hal_subghz.h b/targets/f7/furi_hal/furi_hal_subghz.h index 855ce3161..757f7089a 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.h +++ b/targets/f7/furi_hal/furi_hal_subghz.h @@ -17,10 +17,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 {