From 03f889962bc6fec3ed19ef558ef65e9683f6fd86 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sat, 25 Feb 2023 23:59:50 -0800 Subject: [PATCH 01/35] Picopass: factory key support, app rename and move to NFC category, minor code cleanup (#2417) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * message on successful card write * auth using factory key * auth using factory default * factory default screen * write standard iclass key * pass block explicitly * Fix array indexing, add empty detection * PicoPass: rename app and move to NFC group, minor code cleanup Co-authored-by: あく --- applications/plugins/picopass/application.fam | 4 +- applications/plugins/picopass/picopass.c | 10 ++ .../plugins/picopass/picopass_device.c | 2 +- .../plugins/picopass/picopass_device.h | 1 + applications/plugins/picopass/picopass_i.h | 12 ++ .../plugins/picopass/picopass_worker.c | 165 +++++++++++++++++- .../plugins/picopass/picopass_worker.h | 1 + .../plugins/picopass/picopass_worker_i.h | 1 + .../picopass/scenes/picopass_scene_config.h | 2 + .../scenes/picopass_scene_read_card.c | 11 +- .../scenes/picopass_scene_read_card_success.c | 41 +++-- .../picopass_scene_read_factory_success.c | 78 +++++++++ .../picopass_scene_write_card_success.c | 13 ++ .../scenes/picopass_scene_write_key.c | 53 ++++++ 14 files changed, 367 insertions(+), 27 deletions(-) create mode 100644 applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c create mode 100644 applications/plugins/picopass/scenes/picopass_scene_write_key.c diff --git a/applications/plugins/picopass/application.fam b/applications/plugins/picopass/application.fam index f2da6a9fab..c5087b8045 100644 --- a/applications/plugins/picopass/application.fam +++ b/applications/plugins/picopass/application.fam @@ -1,6 +1,6 @@ App( appid="picopass", - name="PicoPass Reader", + name="PicoPass", apptype=FlipperAppType.EXTERNAL, targets=["f7"], entry_point="picopass_app", @@ -11,7 +11,7 @@ App( stack_size=4 * 1024, order=30, fap_icon="125_10px.png", - fap_category="Tools", + fap_category="NFC", fap_libs=["mbedtls"], fap_private_libs=[ Lib( diff --git a/applications/plugins/picopass/picopass.c b/applications/plugins/picopass/picopass.c index 217f963d36..96ea82c3d7 100644 --- a/applications/plugins/picopass/picopass.c +++ b/applications/plugins/picopass/picopass.c @@ -171,6 +171,16 @@ void picopass_show_loading_popup(void* context, bool show) { } } +bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size) { + bool result = size > 0; + while(size > 0) { + result &= (*data == pattern); + data++; + size--; + } + return result; +} + int32_t picopass_app(void* p) { UNUSED(p); Picopass* picopass = picopass_alloc(); diff --git a/applications/plugins/picopass/picopass_device.c b/applications/plugins/picopass/picopass_device.c index fd8ddbfbd2..e3940698c2 100644 --- a/applications/plugins/picopass/picopass_device.c +++ b/applications/plugins/picopass/picopass_device.c @@ -368,7 +368,7 @@ ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* r record->CardNumber = (bot >> 1) & 0xFFFF; record->FacilityCode = (bot >> 17) & 0xFF; - FURI_LOG_D(TAG, "FC:%u CN: %u\n", record->FacilityCode, record->CardNumber); + FURI_LOG_D(TAG, "FC: %u CN: %u", record->FacilityCode, record->CardNumber); record->valid = true; } else { record->CardNumber = 0; diff --git a/applications/plugins/picopass/picopass_device.h b/applications/plugins/picopass/picopass_device.h index 150b095a77..99f1ceea64 100644 --- a/applications/plugins/picopass/picopass_device.h +++ b/applications/plugins/picopass/picopass_device.h @@ -22,6 +22,7 @@ #define PICOPASS_KD_BLOCK_INDEX 3 #define PICOPASS_KC_BLOCK_INDEX 4 #define PICOPASS_AIA_BLOCK_INDEX 5 +#define PICOPASS_PACS_CFG_BLOCK_INDEX 6 #define PICOPASS_APP_FOLDER ANY_PATH("picopass") #define PICOPASS_APP_EXTENSION ".picopass" diff --git a/applications/plugins/picopass/picopass_i.h b/applications/plugins/picopass/picopass_i.h index 469a672b7e..54533e8236 100644 --- a/applications/plugins/picopass/picopass_i.h +++ b/applications/plugins/picopass/picopass_i.h @@ -81,3 +81,15 @@ void picopass_blink_start(Picopass* picopass); void picopass_blink_stop(Picopass* picopass); void picopass_show_loading_popup(void* context, bool show); + +/** Check if memory is set to pattern + * + * @warning zero size will return false + * + * @param[in] data Pointer to the byte array + * @param[in] pattern The pattern + * @param[in] size The byte array size + * + * @return True if memory is set to pattern, false otherwise + */ +bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size); diff --git a/applications/plugins/picopass/picopass_worker.c b/applications/plugins/picopass/picopass_worker.c index 1ee814aa59..6d904478ca 100644 --- a/applications/plugins/picopass/picopass_worker.c +++ b/applications/plugins/picopass/picopass_worker.c @@ -5,7 +5,8 @@ #define TAG "PicopassWorker" const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78}; -const uint8_t picopass_factory_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; +const uint8_t picopass_factory_credit_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; +const uint8_t picopass_factory_debit_key[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87}; static void picopass_worker_enable_field() { furi_hal_nfc_ll_txrx_on(); @@ -197,6 +198,28 @@ static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) { return rfalPicoPassPollerCheck(mac, &chkRes); } +static ReturnCode picopass_auth_factory(uint8_t* csn, uint8_t* div_key) { + rfalPicoPassReadCheckRes rcRes; + rfalPicoPassCheckRes chkRes; + + ReturnCode err; + + uint8_t mac[4] = {0}; + uint8_t ccnr[12] = {0}; + + err = rfalPicoPassPollerReadCheck(&rcRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); + return err; + } + memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 + + loclass_diversifyKey(csn, picopass_factory_debit_key, div_key); + loclass_opt_doReaderMAC(ccnr, div_key, mac); + + return rfalPicoPassPollerCheck(mac, &chkRes); +} + static ReturnCode picopass_auth_dict( uint8_t* csn, PicopassPacs* pacs, @@ -264,14 +287,23 @@ static ReturnCode picopass_auth_dict( ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { ReturnCode err; - FURI_LOG_E(TAG, "Trying standard legacy key"); + FURI_LOG_I(TAG, "Trying standard legacy key"); err = picopass_auth_standard( AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data); if(err == ERR_NONE) { + memcpy(pacs->key, picopass_iclass_key, PICOPASS_BLOCK_LEN); + return ERR_NONE; + } + + FURI_LOG_I(TAG, "Trying factory default key"); + err = picopass_auth_factory( + AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data); + if(err == ERR_NONE) { + memcpy(pacs->key, picopass_factory_debit_key, PICOPASS_BLOCK_LEN); return ERR_NONE; } - FURI_LOG_E(TAG, "Starting user dictionary attack"); + FURI_LOG_I(TAG, "Starting user dictionary attack"); err = picopass_auth_dict( AA1[PICOPASS_CSN_BLOCK_INDEX].data, pacs, @@ -281,7 +313,7 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { return ERR_NONE; } - FURI_LOG_E(TAG, "Starting in-built dictionary attack"); + FURI_LOG_I(TAG, "Starting system dictionary attack"); err = picopass_auth_dict( AA1[PICOPASS_CSN_BLOCK_INDEX].data, pacs, @@ -406,6 +438,84 @@ ReturnCode picopass_write_card(PicopassBlock* AA1) { return ERR_NONE; } +ReturnCode picopass_write_block(PicopassPacs* pacs, uint8_t blockNo, uint8_t* newBlock) { + rfalPicoPassIdentifyRes idRes; + rfalPicoPassSelectRes selRes; + rfalPicoPassReadCheckRes rcRes; + rfalPicoPassCheckRes chkRes; + + ReturnCode err; + + uint8_t div_key[8] = {0}; + uint8_t mac[4] = {0}; + uint8_t ccnr[12] = {0}; + + err = rfalPicoPassPollerIdentify(&idRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err); + return err; + } + + err = rfalPicoPassPollerSelect(idRes.CSN, &selRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err); + return err; + } + + err = rfalPicoPassPollerReadCheck(&rcRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); + return err; + } + memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 + + loclass_diversifyKey(selRes.CSN, pacs->key, div_key); + loclass_opt_doReaderMAC(ccnr, div_key, mac); + + err = rfalPicoPassPollerCheck(mac, &chkRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err); + return err; + } + + FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", blockNo); + uint8_t data[9] = { + blockNo, + newBlock[0], + newBlock[1], + newBlock[2], + newBlock[3], + newBlock[4], + newBlock[5], + newBlock[6], + newBlock[7]}; + loclass_doMAC_N(data, sizeof(data), div_key, mac); + FURI_LOG_D( + TAG, + "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x", + blockNo, + data[1], + data[2], + data[3], + data[4], + data[5], + data[6], + data[7], + data[8], + mac[0], + mac[1], + mac[2], + mac[3]); + + err = rfalPicoPassPollerWriteBlock(data[0], data + 1, mac); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err); + return err; + } + + return ERR_NONE; +} + int32_t picopass_worker_task(void* context) { PicopassWorker* picopass_worker = context; @@ -414,6 +524,8 @@ int32_t picopass_worker_task(void* context) { picopass_worker_detect(picopass_worker); } else if(picopass_worker->state == PicopassWorkerStateWrite) { picopass_worker_write(picopass_worker); + } else if(picopass_worker->state == PicopassWorkerStateWriteStandardKey) { + picopass_worker_write_standard_key(picopass_worker); } picopass_worker_disable_field(ERR_NONE); @@ -448,7 +560,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { } // Thank you proxmark! - pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); + pacs->legacy = picopass_is_memset(AA1[5].data, 0xFF, 8); pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); if(pacs->se_enabled) { FURI_LOG_D(TAG, "SE enabled"); @@ -520,3 +632,46 @@ void picopass_worker_write(PicopassWorker* picopass_worker) { furi_delay_ms(100); } } + +void picopass_worker_write_standard_key(PicopassWorker* picopass_worker) { + PicopassDeviceData* dev_data = picopass_worker->dev_data; + PicopassBlock* AA1 = dev_data->AA1; + PicopassPacs* pacs = &dev_data->pacs; + ReturnCode err; + PicopassWorkerEvent nextState = PicopassWorkerEventSuccess; + + uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data; + uint8_t* configBlock = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data; + uint8_t fuses = configBlock[7]; + uint8_t* oldKey = AA1[PICOPASS_KD_BLOCK_INDEX].data; + + uint8_t newKey[PICOPASS_BLOCK_LEN] = {0}; + loclass_diversifyKey(csn, picopass_iclass_key, newKey); + + if((fuses & 0x80) == 0x80) { + FURI_LOG_D(TAG, "Plain write for personalized mode key change"); + } else { + FURI_LOG_D(TAG, "XOR write for application mode key change"); + // XOR when in application mode + for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { + newKey[i] ^= oldKey[i]; + } + } + + while(picopass_worker->state == PicopassWorkerStateWriteStandardKey) { + if(picopass_detect_card(1000) == ERR_NONE) { + err = picopass_write_block(pacs, PICOPASS_KD_BLOCK_INDEX, newKey); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "picopass_write_block error %d", err); + nextState = PicopassWorkerEventFail; + } + + // Notify caller and exit + if(picopass_worker->callback) { + picopass_worker->callback(nextState, picopass_worker->context); + } + break; + } + furi_delay_ms(100); + } +} diff --git a/applications/plugins/picopass/picopass_worker.h b/applications/plugins/picopass/picopass_worker.h index 29a890a188..775212c661 100644 --- a/applications/plugins/picopass/picopass_worker.h +++ b/applications/plugins/picopass/picopass_worker.h @@ -12,6 +12,7 @@ typedef enum { // Main worker states PicopassWorkerStateDetect, PicopassWorkerStateWrite, + PicopassWorkerStateWriteStandardKey, // Transition PicopassWorkerStateStop, } PicopassWorkerState; diff --git a/applications/plugins/picopass/picopass_worker_i.h b/applications/plugins/picopass/picopass_worker_i.h index ded40e6c63..cf55fbdf58 100644 --- a/applications/plugins/picopass/picopass_worker_i.h +++ b/applications/plugins/picopass/picopass_worker_i.h @@ -31,3 +31,4 @@ int32_t picopass_worker_task(void* context); void picopass_worker_detect(PicopassWorker* picopass_worker); void picopass_worker_write(PicopassWorker* picopass_worker); +void picopass_worker_write_standard_key(PicopassWorker* picopass_worker); diff --git a/applications/plugins/picopass/scenes/picopass_scene_config.h b/applications/plugins/picopass/scenes/picopass_scene_config.h index 27d6bbcd77..95700787fb 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_config.h +++ b/applications/plugins/picopass/scenes/picopass_scene_config.h @@ -11,3 +11,5 @@ ADD_SCENE(picopass, delete, Delete) ADD_SCENE(picopass, delete_success, DeleteSuccess) ADD_SCENE(picopass, write_card, WriteCard) ADD_SCENE(picopass, write_card_success, WriteCardSuccess) +ADD_SCENE(picopass, read_factory_success, ReadFactorySuccess) +ADD_SCENE(picopass, write_key, WriteKey) diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_card.c b/applications/plugins/picopass/scenes/picopass_scene_read_card.c index 8188207a2a..90422a2e73 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_read_card.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_card.c @@ -1,6 +1,8 @@ #include "../picopass_i.h" #include +const uint8_t picopass_factory_key_check[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87}; + void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context) { UNUSED(event); Picopass* picopass = context; @@ -34,7 +36,14 @@ bool picopass_scene_read_card_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == PicopassCustomEventWorkerExit) { - scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); + if(memcmp( + picopass->dev->dev_data.pacs.key, + picopass_factory_key_check, + PICOPASS_BLOCK_LEN) == 0) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadFactorySuccess); + } else { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); + } consumed = true; } } diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c b/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c index d89a5d89bb..f078d460a2 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c @@ -15,6 +15,7 @@ void picopass_scene_read_card_success_widget_callback( void picopass_scene_read_card_success_on_enter(void* context) { Picopass* picopass = context; + FuriString* csn_str = furi_string_alloc_set("CSN:"); FuriString* credential_str = furi_string_alloc(); FuriString* wiegand_str = furi_string_alloc(); @@ -30,27 +31,31 @@ void picopass_scene_read_card_success_on_enter(void* context) { PicopassPacs* pacs = &picopass->dev->dev_data.pacs; Widget* widget = picopass->widget; - uint8_t csn[PICOPASS_BLOCK_LEN]; - memcpy(csn, &AA1->data[PICOPASS_CSN_BLOCK_INDEX], PICOPASS_BLOCK_LEN); + uint8_t csn[PICOPASS_BLOCK_LEN] = {0}; + memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN); for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { furi_string_cat_printf(csn_str, "%02X ", csn[i]); } - // Neither of these are valid. Indicates the block was all 0x00 or all 0xff - if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) { + bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN); + bool empty = + picopass_is_memset(AA1[PICOPASS_PACS_CFG_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN); + + if(no_key) { furi_string_cat_printf(wiegand_str, "Read Failed"); if(pacs->se_enabled) { furi_string_cat_printf(credential_str, "SE enabled"); } + } else if(empty) { + furi_string_cat_printf(wiegand_str, "Empty"); + } else if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) { + // Neither of these are valid. Indicates the block was all 0x00 or all 0xff + furi_string_cat_printf(wiegand_str, "Invalid PACS"); - widget_add_button_element( - widget, - GuiButtonTypeLeft, - "Retry", - picopass_scene_read_card_success_widget_callback, - picopass); - + if(pacs->se_enabled) { + furi_string_cat_printf(credential_str, "SE enabled"); + } } else { size_t bytesLength = 1 + pacs->record.bitLength / 8; furi_string_set(credential_str, ""); @@ -82,13 +87,6 @@ void picopass_scene_read_card_success_on_enter(void* context) { } } - widget_add_button_element( - widget, - GuiButtonTypeLeft, - "Retry", - picopass_scene_read_card_success_widget_callback, - picopass); - widget_add_button_element( widget, GuiButtonTypeRight, @@ -97,6 +95,13 @@ void picopass_scene_read_card_success_on_enter(void* context) { picopass); } + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + picopass_scene_read_card_success_widget_callback, + picopass); + widget_add_string_element( widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(csn_str)); widget_add_string_element( diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c b/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c new file mode 100644 index 0000000000..8e32d21f7b --- /dev/null +++ b/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c @@ -0,0 +1,78 @@ +#include "../picopass_i.h" +#include + +void picopass_scene_read_factory_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + Picopass* picopass = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(picopass->view_dispatcher, result); + } +} + +void picopass_scene_read_factory_success_on_enter(void* context) { + Picopass* picopass = context; + FuriString* title = furi_string_alloc_set("Factory Default"); + FuriString* subtitle = furi_string_alloc_set(""); + + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + // Send notification + notification_message(picopass->notifications, &sequence_success); + + // Setup view + Widget* widget = picopass->widget; + //PicopassPacs* pacs = &picopass->dev->dev_data.pacs; + PicopassBlock* AA1 = picopass->dev->dev_data.AA1; + + uint8_t* configBlock = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data; + uint8_t fuses = configBlock[7]; + + if((fuses & 0x80) == 0x80) { + furi_string_cat_printf(subtitle, "Personalization mode"); + } else { + furi_string_cat_printf(subtitle, "Application mode"); + } + + widget_add_button_element( + widget, + GuiButtonTypeCenter, + "Write Standard iClass Key", + picopass_scene_read_factory_success_widget_callback, + picopass); + + widget_add_string_element( + widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(title)); + widget_add_string_element( + widget, 64, 20, AlignCenter, AlignCenter, FontPrimary, furi_string_get_cstr(subtitle)); + + furi_string_free(title); + furi_string_free(subtitle); + + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); +} + +bool picopass_scene_read_factory_success_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(picopass->scene_manager); + } else if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); + consumed = true; + } + } + return consumed; +} + +void picopass_scene_read_factory_success_on_exit(void* context) { + Picopass* picopass = context; + + // Clear view + widget_reset(picopass->widget); +} diff --git a/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c b/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c index 108e7d1cef..4bbca816aa 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c +++ b/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c @@ -16,6 +16,7 @@ void picopass_scene_write_card_success_widget_callback( void picopass_scene_write_card_success_on_enter(void* context) { Picopass* picopass = context; Widget* widget = picopass->widget; + FuriString* str = furi_string_alloc_set("Write Success!"); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); @@ -29,6 +30,18 @@ void picopass_scene_write_card_success_on_enter(void* context) { picopass_scene_write_card_success_widget_callback, picopass); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "Menu", + picopass_scene_write_card_success_widget_callback, + picopass); + + widget_add_string_element( + widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(str)); + + furi_string_free(str); + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); } diff --git a/applications/plugins/picopass/scenes/picopass_scene_write_key.c b/applications/plugins/picopass/scenes/picopass_scene_write_key.c new file mode 100644 index 0000000000..83d594ca2b --- /dev/null +++ b/applications/plugins/picopass/scenes/picopass_scene_write_key.c @@ -0,0 +1,53 @@ +#include "../picopass_i.h" +#include + +void picopass_write_key_worker_callback(PicopassWorkerEvent event, void* context) { + UNUSED(event); + Picopass* picopass = context; + view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventWorkerExit); +} + +void picopass_scene_write_key_on_enter(void* context) { + Picopass* picopass = context; + DOLPHIN_DEED(DolphinDeedNfcSave); + + // Setup view + Popup* popup = picopass->popup; + popup_set_header(popup, "Writing\niClass\nkey", 68, 30, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + + // Start worker + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); + picopass_worker_start( + picopass->worker, + PicopassWorkerStateWriteStandardKey, + &picopass->dev->dev_data, + picopass_write_key_worker_callback, + picopass); + + picopass_blink_start(picopass); +} + +bool picopass_scene_write_key_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == PicopassCustomEventWorkerExit) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCardSuccess); + consumed = true; + } + } + return consumed; +} + +void picopass_scene_write_key_on_exit(void* context) { + Picopass* picopass = context; + + // Stop worker + picopass_worker_stop(picopass->worker); + // Clear view + popup_reset(picopass->popup); + + picopass_blink_stop(picopass); +} From 12c1ec37a20a2b4f3a4ed5359bb708fcab79ca6c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 26 Feb 2023 11:08:05 +0300 Subject: [PATCH 02/35] Fix PVS warnings (#2430) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/bad_usb/bad_usb_script.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c index d66ce8a917..beb35b894f 100644 --- a/applications/main/bad_usb/bad_usb_script.c +++ b/applications/main/bad_usb/bad_usb_script.c @@ -511,7 +511,7 @@ static uint32_t bad_usb_flags_get(uint32_t flags_mask, uint32_t timeout) { furi_check((flags & FuriFlagError) == 0); if(flags == 0) { flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout); - furi_check(((flags & FuriFlagError) == 0) || (flags == FuriFlagErrorTimeout)); + furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout)); } else { uint32_t state = furi_thread_flags_clear(flags); furi_check((state & FuriFlagError) == 0); @@ -610,7 +610,7 @@ static int32_t bad_usb_worker(void* context) { WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtToggle, FuriFlagWaitAny | FuriFlagNoClear, 1500); - if(flags == FuriFlagErrorTimeout) { + if(flags == (unsigned)FuriFlagErrorTimeout) { // If nothing happened - start script execution worker_state = BadUsbStateRunning; } else if(flags & WorkerEvtToggle) { From 33dd256dfbdab13e26a56147edcdbdfb4d2514b0 Mon Sep 17 00:00:00 2001 From: matthisc Date: Sun, 26 Feb 2023 10:10:00 +0100 Subject: [PATCH 03/35] Correcting bug on DEL and DELETE key --- applications/plugins/mousejacker/mousejacker_ducky.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index b3b04d8362..b57330c0d4 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -89,7 +89,7 @@ static uint32_t mj_ducky_get_command_len(const char* line) { static bool mj_get_ducky_key(char* key, size_t keylen, MJDuckyKey* dk) { //FURI_LOG_D(TAG, "looking up key %s with length %d", key, keylen); for(uint i = 0; i < sizeof(mj_ducky_keys) / sizeof(MJDuckyKey); i++) { - if(!strncmp(mj_ducky_keys[i].name, key, keylen)) { + if(strncmp(mj_ducky_keys[i].name, key, keylen) == 0) { memcpy(dk, &mj_ducky_keys[i], sizeof(MJDuckyKey)); return true; } From 2bb76e09c6255f8ae3581e5816aa33173f4545d3 Mon Sep 17 00:00:00 2001 From: matthisc Date: Sun, 26 Feb 2023 10:14:14 +0100 Subject: [PATCH 04/35] Adding TAB command --- applications/plugins/mousejacker/mousejacker_ducky.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index b57330c0d4..3a6cc3f467 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -344,7 +344,11 @@ static bool mj_process_ducky_line( if(!mj_get_ducky_key("SPACE", 5, &dk)) return false; send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); return true; - } + } else if(strncmp(line_tmp, "TAB", strlen("TAB")) == 0) { + if(!mj_get_ducky_key("TAB", 3, &dk)) return false; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + return true; + } return false; } From 958797062dc88fcead7dd0fcd7503e466da54879 Mon Sep 17 00:00:00 2001 From: matthisc Date: Sun, 26 Feb 2023 10:23:33 +0100 Subject: [PATCH 05/35] Improving logic of mod keys when releasing a key --- .../plugins/mousejacker/mousejacker_ducky.c | 71 +++++++++++++++---- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index 3a6cc3f467..b30bc6e4a3 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -11,6 +11,10 @@ static uint8_t LOGITECH_HELLO[] = {0x00, 0x4F, 0x00, 0x04, 0xB0, 0x10, 0x00, 0x0 static uint8_t LOGITECH_KEEPALIVE[] = {0x00, 0x40, 0x00, 0x55, 0x6B}; uint8_t prev_hid = 0; +static bool holding_ctrl = false; +static bool holding_shift = false; +static bool holding_alt = false; +static bool holding_gui = false; #define RT_THRESHOLD 50 #define LOGITECH_MIN_CHANNEL 2 @@ -152,18 +156,24 @@ static void build_hid_packet(uint8_t mod, uint8_t hid, uint8_t* payload) { checksum(payload, LOGITECH_HID_TEMPLATE_SIZE); } -static void send_hid_packet( +static void release_key( FuriHalSpiBusHandle* handle, uint8_t* addr, uint8_t addr_size, uint8_t rate, - uint8_t mod, - uint8_t hid, - PluginState* plugin_state) { + PluginState* plugin_state +) { + // This function release keys currently pressed, but keep pressing special keys + // if holding mod keys variable are set to true + uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0}; - build_hid_packet(0, 0, hid_payload); - if(hid == prev_hid) - inject_packet( + build_hid_packet( + 0 | holding_ctrl + | holding_shift << 1 + | holding_alt << 2 + | holding_gui << 3, + 0, hid_payload); + inject_packet( handle, addr, addr_size, @@ -171,9 +181,26 @@ static void send_hid_packet( hid_payload, LOGITECH_HID_TEMPLATE_SIZE, plugin_state); // empty hid packet +} + +static void send_hid_packet( + FuriHalSpiBusHandle* handle, + uint8_t* addr, + uint8_t addr_size, + uint8_t rate, + uint8_t mod, + uint8_t hid, + PluginState* plugin_state) { + uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0}; + if(hid == prev_hid ) + release_key(handle, addr, addr_size, rate, plugin_state); prev_hid = hid; - build_hid_packet(mod, hid, hid_payload); + build_hid_packet(mod + | holding_ctrl + | holding_shift << 1 + | holding_alt << 2 + | holding_gui << 3, hid, hid_payload); inject_packet( handle, addr, addr_size, rate, hid_payload, LOGITECH_HID_TEMPLATE_SIZE, plugin_state); furi_delay_ms(12); @@ -269,7 +296,9 @@ static bool mj_process_ducky_line( } else if(strncmp(line_tmp, "ALT", strlen("ALT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 4, dk.hid, plugin_state); + holding_alt = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_alt = false; return true; } else if( strncmp(line_tmp, "GUI", strlen("GUI")) == 0 || @@ -277,33 +306,47 @@ static bool mj_process_ducky_line( strncmp(line_tmp, "COMMAND", strlen("COMMAND")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 8, dk.hid, plugin_state); + holding_gui = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_gui = false; return true; } else if( strncmp(line_tmp, "CTRL-ALT", strlen("CTRL-ALT")) == 0 || strncmp(line_tmp, "CONTROL-ALT", strlen("CONTROL-ALT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 4 | 1, dk.hid, plugin_state); + holding_ctrl = true; + holding_alt = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_ctrl = false; + holding_alt = false; return true; } else if( strncmp(line_tmp, "CTRL-SHIFT", strlen("CTRL-SHIFT")) == 0 || strncmp(line_tmp, "CONTROL-SHIFT", strlen("CONTROL-SHIFT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 1 | 2, dk.hid, plugin_state); + holding_ctrl = true; + holding_shift = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_ctrl = false; + holding_shift = false; return true; } else if( strncmp(line_tmp, "CTRL", strlen("CTRL")) == 0 || strncmp(line_tmp, "CONTROL", strlen("CONTROL")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 1, dk.hid, plugin_state); + holding_ctrl = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_ctrl = false; return true; } else if(strncmp(line_tmp, "SHIFT", strlen("SHIFT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 2, dk.hid, plugin_state); + holding_shift = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_shift = false; return true; } else if( strncmp(line_tmp, "ESC", strlen("ESC")) == 0 || From 16fe62e98db853ca1659ea4d8885ac1b5c55e09c Mon Sep 17 00:00:00 2001 From: matthisc Date: Sun, 26 Feb 2023 10:29:56 +0100 Subject: [PATCH 06/35] Adding ALTSTRING feature for non-qwerty keyboards --- .../plugins/mousejacker/mousejacker_ducky.c | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index b30bc6e4a3..79d8bbec55 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -3,6 +3,7 @@ static const char ducky_cmd_comment[] = {"REM"}; static const char ducky_cmd_delay[] = {"DELAY "}; static const char ducky_cmd_string[] = {"STRING "}; +static const char ducky_cmd_altstring[] = {"ALTSTRING "}; static const char ducky_cmd_repeat[] = {"REPEAT "}; static uint8_t LOGITECH_HID_TEMPLATE[] = @@ -69,7 +70,10 @@ MJDuckyKey mj_ducky_keys[] = {{" ", 44, 0}, {"!", 30, 2}, {"\"" {"LEFTARROW", 80, 0}, {"RIGHTARROW", 79, 0}, {"PAGEDOWN", 78, 0}, {"PAUSE", 72, 0}, {"SPACE", 44, 0}, {"UPARROW", 82, 0}, {"F11", 68, 0}, {"F7", 64, 0}, {"UP", 82, 0}, - {"LEFT", 80, 0}}; + {"LEFT", 80, 0}, {"NUM 1", 89, 0}, {"NUM 2", 90, 0}, + {"NUM 3", 91, 0}, {"NUM 4", 92, 0}, {"NUM 5", 93, 0}, + {"NUM 6", 94, 0}, {"NUM 7", 95, 0}, {"NUM 8", 96, 0}, + {"NUM 9", 97, 0}, {"NUM 0", 98, 0}}; /* static bool mj_ducky_get_number(const char* param, uint32_t* val) { @@ -278,6 +282,32 @@ static bool mj_process_ducky_line( send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); } + return true; + } else if(strncmp(line_tmp, ducky_cmd_altstring, strlen(ducky_cmd_altstring)) == 0) { + // ALTSTRING + line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; + for(size_t i = 0; i < strlen(line_tmp); i++) { + if((line_tmp[i] < ' ') || (line_tmp[i] > '~')) { + continue; // Skip non-printable chars + } + + char alt_code[4]; + // Getting altcode of the char + snprintf(alt_code, 4, "%u", line_tmp[i]); + + uint8_t j = 0; + while(!ducky_end_line(alt_code[j])) { + char pad_num[5] = {'N', 'U', 'M', ' ', alt_code[j]}; + if(!mj_get_ducky_key(pad_num, 5, &dk)) return false; + holding_alt = true; + FURI_LOG_D(TAG, "Sending %s", pad_num); + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + j++; + } + holding_alt = false; + release_key(handle, addr, addr_size, rate, plugin_state); + } + return true; } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { // REPEAT From 905273e066e49313e2335b41d5d19a2436a929fc Mon Sep 17 00:00:00 2001 From: matthisc Date: Sun, 26 Feb 2023 10:38:40 +0100 Subject: [PATCH 07/35] Adding function to detect end of altcode --- applications/plugins/mousejacker/mousejacker_ducky.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index 79d8bbec55..d5a32c4842 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -210,6 +210,10 @@ static void send_hid_packet( furi_delay_ms(12); } +static bool ducky_end_line(const char chr) { + return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n')); +} + // returns false if there was an error processing script line static bool mj_process_ducky_line( FuriHalSpiBusHandle* handle, @@ -307,7 +311,7 @@ static bool mj_process_ducky_line( holding_alt = false; release_key(handle, addr, addr_size, rate, plugin_state); } - + return true; } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { // REPEAT From 9bda3e62eec4d81cc59352431ee468024c5921ed Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Sun, 26 Feb 2023 14:28:51 +0300 Subject: [PATCH 08/35] SD Cache: moved to diskio layer, invalidation in case of error (#2428) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- firmware/targets/f7/fatfs/sd_spi_io.c | 38 +------------------------ firmware/targets/f7/fatfs/sd_spi_io.h | 1 + firmware/targets/f7/fatfs/user_diskio.c | 37 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/firmware/targets/f7/fatfs/sd_spi_io.c b/firmware/targets/f7/fatfs/sd_spi_io.c index 93b837e852..68903acfb6 100644 --- a/firmware/targets/f7/fatfs/sd_spi_io.c +++ b/firmware/targets/f7/fatfs/sd_spi_io.c @@ -17,7 +17,6 @@ #define SD_DUMMY_BYTE 0xFF #define SD_ANSWER_RETRY_COUNT 8 #define SD_IDLE_RETRY_COUNT 100 -#define SD_BLOCK_SIZE 512 #define FLAG_SET(x, y) (((x) & (y)) == (y)) @@ -598,23 +597,6 @@ static SdSpiStatus sd_spi_get_cid(SD_CID* Cid) { return ret; } -static inline bool sd_cache_get(uint32_t address, uint32_t* data) { - uint8_t* cached_data = sector_cache_get(address); - if(cached_data) { - memcpy(data, cached_data, SD_BLOCK_SIZE); - return true; - } - return false; -} - -static inline void sd_cache_put(uint32_t address, uint32_t* data) { - sector_cache_put(address, (uint8_t*)data); -} - -static inline void sd_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) { - sector_cache_invalidate_range(start_sector, end_sector); -} - static SdSpiStatus sd_spi_cmd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { uint32_t block_address = address; @@ -833,30 +815,12 @@ SdSpiStatus sd_get_card_info(SD_CardInfo* card_info) { SdSpiStatus sd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { - SdSpiStatus status = SdSpiStatusError; - - bool single_sector_read = (blocks == 1); - - if(single_sector_read) { - if(sd_cache_get(address, data)) { - return SdSpiStatusOK; - } - - status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms); - - if(status == SdSpiStatusOK) { - sd_cache_put(address, data); - } - } else { - status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms); - } - + SdSpiStatus status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms); return status; } SdSpiStatus sd_write_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { - sd_cache_invalidate_range(address, address + blocks); SdSpiStatus status = sd_spi_cmd_write_blocks(data, address, blocks, timeout_ms); return status; } diff --git a/firmware/targets/f7/fatfs/sd_spi_io.h b/firmware/targets/f7/fatfs/sd_spi_io.h index 8850eceb76..954c78c408 100644 --- a/firmware/targets/f7/fatfs/sd_spi_io.h +++ b/firmware/targets/f7/fatfs/sd_spi_io.h @@ -5,6 +5,7 @@ #define __IO volatile #define SD_TIMEOUT_MS (1000) +#define SD_BLOCK_SIZE 512 typedef enum { SdSpiStatusOK, diff --git a/firmware/targets/f7/fatfs/user_diskio.c b/firmware/targets/f7/fatfs/user_diskio.c index 16ac78e4dc..d7be09c531 100644 --- a/firmware/targets/f7/fatfs/user_diskio.c +++ b/firmware/targets/f7/fatfs/user_diskio.c @@ -36,6 +36,7 @@ /* Includes ------------------------------------------------------------------*/ #include "user_diskio.h" #include +#include "sector_cache.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ @@ -79,6 +80,26 @@ Diskio_drvTypeDef USER_Driver = { }; /* Private functions ---------------------------------------------------------*/ +static inline bool sd_cache_get(uint32_t address, uint32_t* data) { + uint8_t* cached_data = sector_cache_get(address); + if(cached_data) { + memcpy(data, cached_data, SD_BLOCK_SIZE); + return true; + } + return false; +} + +static inline void sd_cache_put(uint32_t address, uint32_t* data) { + sector_cache_put(address, (uint8_t*)data); +} + +static inline void sd_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) { + sector_cache_invalidate_range(start_sector, end_sector); +} + +static inline void sd_cache_invalidate_all() { + sector_cache_init(); +} /** * @brief Initializes a Drive @@ -125,6 +146,14 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { UNUSED(pdrv); DRESULT res = RES_ERROR; + bool single_sector = count == 1; + + if(single_sector) { + if(sd_cache_get(sector, (uint32_t*)buff)) { + return RES_OK; + } + } + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; @@ -145,6 +174,10 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { furi_hal_sd_spi_handle = NULL; furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); + if(single_sector && res == RES_OK) { + sd_cache_put(sector, (uint32_t*)buff); + } + return res; /* USER CODE END READ */ } @@ -164,6 +197,8 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { UNUSED(pdrv); DRESULT res = RES_ERROR; + sd_cache_invalidate_range(sector, sector + count); + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; @@ -175,6 +210,8 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { res = RES_OK; while(sd_get_card_state() != SdSpiStatusOK) { if(furi_hal_cortex_timer_is_expired(timer)) { + sd_cache_invalidate_all(); + res = RES_ERROR; break; } From 0c06e54831f85e0b4d11efda860e44a6db2a4a8e Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Sun, 26 Feb 2023 14:28:52 +0200 Subject: [PATCH 09/35] [FL-3105] Unify power info, power debug, and device_info into one info command (#2393) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Unify power info, power debug, and device_info into one info command * Fix the storage script * Cli: return device_info command for compatibility, rollback storage script * Cli: remove unused context in info_get calls * Cli: cleanup device info callbacks, switch to new separator Co-authored-by: あく --- applications/services/cli/cli_commands.c | 41 ++++++++++++++++++------ applications/services/power/power_cli.c | 30 ----------------- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index b0f1bdbdf0..ca9d8b98a6 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -12,20 +12,42 @@ // Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'` #define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d" -void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) { - UNUSED(context); +void cli_command_info_callback(const char* key, const char* value, bool last, void* context) { UNUSED(last); + UNUSED(context); printf("%-30s: %s\r\n", key, value); } -/* - * Device Info Command +/** Info Command + * * This command is intended to be used by humans + * + * Arguments: + * - device - print device info + * - power - print power info + * - power_debug - print power debug info + * + * @param cli The cli instance + * @param args The arguments + * @param context The context */ -void cli_command_device_info(Cli* cli, FuriString* args, void* context) { +void cli_command_info(Cli* cli, FuriString* args, void* context) { UNUSED(cli); - UNUSED(args); - furi_hal_info_get(cli_command_device_info_callback, '_', context); + + if(context) { + furi_hal_info_get(cli_command_info_callback, '_', NULL); + return; + } + + if(!furi_string_cmp(args, "device")) { + furi_hal_info_get(cli_command_info_callback, '.', NULL); + } else if(!furi_string_cmp(args, "power")) { + furi_hal_power_info_get(cli_command_info_callback, '.', NULL); + } else if(!furi_string_cmp(args, "power_debug")) { + furi_hal_power_debug_get(cli_command_info_callback, NULL); + } else { + cli_print_usage("info", "", furi_string_get_cstr(args)); + } } void cli_command_help(Cli* cli, FuriString* args, void* context) { @@ -410,8 +432,9 @@ void cli_command_i2c(Cli* cli, FuriString* args, void* context) { } void cli_commands_init(Cli* cli) { - cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_device_info, NULL); - cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_device_info, NULL); + cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_info, (void*)true); + cli_add_command(cli, "info", CliCommandFlagParallelSafe, cli_command_info, NULL); + cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_info, (void*)true); cli_add_command(cli, "?", CliCommandFlagParallelSafe, cli_command_help, NULL); cli_add_command(cli, "help", CliCommandFlagParallelSafe, cli_command_help, NULL); diff --git a/applications/services/power/power_cli.c b/applications/services/power/power_cli.c index f4a10f0a98..021ce35536 100644 --- a/applications/services/power/power_cli.c +++ b/applications/services/power/power_cli.c @@ -26,24 +26,6 @@ void power_cli_reboot2dfu(Cli* cli, FuriString* args) { power_reboot(PowerBootModeDfu); } -static void power_cli_callback(const char* key, const char* value, bool last, void* context) { - UNUSED(last); - UNUSED(context); - printf("%-24s: %s\r\n", key, value); -} - -void power_cli_info(Cli* cli, FuriString* args) { - UNUSED(cli); - UNUSED(args); - furi_hal_power_info_get(power_cli_callback, '_', NULL); -} - -void power_cli_debug(Cli* cli, FuriString* args) { - UNUSED(cli); - UNUSED(args); - furi_hal_power_debug_get(power_cli_callback, NULL); -} - void power_cli_5v(Cli* cli, FuriString* args) { UNUSED(cli); if(!furi_string_cmp(args, "0")) { @@ -74,8 +56,6 @@ static void power_cli_command_print_usage() { printf("\toff\t - shutdown power\r\n"); printf("\treboot\t - reboot\r\n"); printf("\treboot2dfu\t - reboot to dfu bootloader\r\n"); - printf("\tinfo\t - show power info\r\n"); - printf("\tdebug\t - show debug information\r\n"); printf("\t5v <0 or 1>\t - enable or disable 5v ext\r\n"); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { printf("\t3v3 <0 or 1>\t - enable or disable 3v3 ext\r\n"); @@ -108,16 +88,6 @@ void power_cli(Cli* cli, FuriString* args, void* context) { break; } - if(furi_string_cmp_str(cmd, "info") == 0) { - power_cli_info(cli, args); - break; - } - - if(furi_string_cmp_str(cmd, "debug") == 0) { - power_cli_debug(cli, args); - break; - } - if(furi_string_cmp_str(cmd, "5v") == 0) { power_cli_5v(cli, args); break; From 3efb7d4050ef3183a43e59fd65dc2ef24fd4f604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 27 Feb 2023 00:15:26 +0900 Subject: [PATCH 10/35] Updater: handle storage errors when removing files, fix folder remove routine, prevent unused services from starting (#2432) * Updater: handle storage errors when removing files * Updater: properly handle folder removal in post update cleanup stage. Prevent power, desktop and dolphin services from starting on update. * Desktop, Dolphin, Power: proper handling and message for special boot mode. * Desktop, Power: add missing TAG * Updater: unify start skip message and fix double delete in backup worker * Cli: unify special boot mode message --- applications/services/bt/bt_service/bt.c | 2 +- applications/services/cli/cli.c | 2 +- applications/services/desktop/desktop.c | 8 +++++ applications/services/dolphin/dolphin.c | 6 ++++ .../services/power/power_service/power.c | 7 ++++ .../updater/util/update_task_worker_backup.c | 33 ++++++++++--------- furi/core/thread.c | 4 +-- furi/flipper.c | 7 ++-- 8 files changed, 46 insertions(+), 23 deletions(-) diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index 9e57826903..16b60231b2 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -373,7 +373,7 @@ int32_t bt_srv(void* p) { Bt* bt = bt_alloc(); if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { - FURI_LOG_W(TAG, "Skipped BT init: device in special startup mode"); + FURI_LOG_W(TAG, "Skipping start in special boot mode"); ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT); furi_record_create(RECORD_BT, bt); return 0; diff --git a/applications/services/cli/cli.c b/applications/services/cli/cli.c index 384d17808d..b68505c51b 100644 --- a/applications/services/cli/cli.c +++ b/applications/services/cli/cli.c @@ -461,7 +461,7 @@ int32_t cli_srv(void* p) { if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) { cli_session_open(cli, &cli_vcp); } else { - FURI_LOG_W(TAG, "Skipped CLI session open: device in special startup mode"); + FURI_LOG_W(TAG, "Skipping start in special boot mode"); } while(1) { diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 848f5cb636..f8716e6cb9 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -17,6 +17,8 @@ #include "helpers/pin_lock.h" #include "helpers/slideshow_filename.h" +#define TAG "Desktop" + static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); @@ -321,6 +323,12 @@ static bool desktop_check_file_flag(const char* flag_path) { int32_t desktop_srv(void* p) { UNUSED(p); + + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + FURI_LOG_W(TAG, "Skipping start in special boot mode"); + return 0; + } + Desktop* desktop = desktop_alloc(); bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings); diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index 41eeef3b1d..dd8b7105f0 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -154,6 +154,12 @@ static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) { int32_t dolphin_srv(void* p) { UNUSED(p); + + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + FURI_LOG_W(TAG, "Skipping start in special boot mode"); + return 0; + } + Dolphin* dolphin = dolphin_alloc(); furi_record_create(RECORD_DOLPHIN, dolphin); diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 5df611a746..d9319d3d91 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -4,6 +4,7 @@ #include #define POWER_OFF_TIMEOUT 90 +#define TAG "Power" void power_draw_battery_callback(Canvas* canvas, void* context) { furi_assert(context); @@ -217,6 +218,12 @@ static void power_check_battery_level_change(Power* power) { int32_t power_srv(void* p) { UNUSED(p); + + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + FURI_LOG_W(TAG, "Skipping start in special boot mode"); + return 0; + } + Power* power = power_alloc(); power_update_info(power); furi_record_create(RECORD_POWER, power); diff --git a/applications/system/updater/util/update_task_worker_backup.c b/applications/system/updater/util/update_task_worker_backup.c index ed53c353bd..f2c33c2edb 100644 --- a/applications/system/updater/util/update_task_worker_backup.c +++ b/applications/system/updater/util/update_task_worker_backup.c @@ -97,7 +97,16 @@ static void update_task_cleanup_resources(UpdateTask* update_task, const uint32_ path_concat( STORAGE_EXT_PATH_PREFIX, furi_string_get_cstr(entry_ptr->name), file_path); FURI_LOG_D(TAG, "Removing %s", furi_string_get_cstr(file_path)); - storage_simply_remove(update_task->storage, furi_string_get_cstr(file_path)); + + FS_Error result = + storage_common_remove(update_task->storage, furi_string_get_cstr(file_path)); + if(result != FSE_OK && result != FSE_EXIST) { + FURI_LOG_E( + TAG, + "%s remove failed, cause %s", + furi_string_get_cstr(file_path), + storage_error_get_desc(result)); + } furi_string_free(file_path); } else if(entry_ptr->type == ResourceManifestEntryTypeDirectory) { n_dir_entries++; @@ -116,7 +125,6 @@ static void update_task_cleanup_resources(UpdateTask* update_task, const uint32_ n_dir_entries); FuriString* folder_path = furi_string_alloc(); - File* folder_file = storage_file_alloc(update_task->storage); do { path_concat( @@ -125,24 +133,17 @@ static void update_task_cleanup_resources(UpdateTask* update_task, const uint32_ folder_path); FURI_LOG_D(TAG, "Removing folder %s", furi_string_get_cstr(folder_path)); - if(!storage_dir_open(folder_file, furi_string_get_cstr(folder_path))) { - FURI_LOG_W( + FS_Error result = storage_common_remove( + update_task->storage, furi_string_get_cstr(folder_path)); + if(result != FSE_OK && result != FSE_EXIST) { + FURI_LOG_E( TAG, - "%s can't be opened, skipping", - furi_string_get_cstr(folder_path)); - break; - } - - if(storage_dir_read(folder_file, NULL, NULL, 0)) { - FURI_LOG_I( - TAG, "%s is not empty, skipping", furi_string_get_cstr(folder_path)); - break; + "%s remove failed, cause %s", + furi_string_get_cstr(folder_path), + storage_error_get_desc(result)); } - - storage_simply_remove(update_task->storage, furi_string_get_cstr(folder_path)); } while(false); - storage_file_free(folder_file); furi_string_free(folder_path); } } diff --git a/furi/core/thread.c b/furi/core/thread.c index 9a112d9a87..ea9f45e842 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -96,9 +96,9 @@ static void furi_thread_body(void* context) { furi_assert(thread->state == FuriThreadStateRunning); if(thread->is_service) { - FURI_LOG_E( + FURI_LOG_W( TAG, - "%s service thread exited. Thread memory cannot be reclaimed.", + "%s service thread TCB memory will not be reclaimed", thread->name ? thread->name : ""); } diff --git a/furi/flipper.c b/furi/flipper.c index 73899e58bf..d16a84a101 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -3,6 +3,7 @@ #include #include #include +#include #define TAG "Flipper" @@ -29,10 +30,10 @@ static void flipper_print_version(const char* target, const Version* version) { void flipper_init() { flipper_print_version("Firmware", furi_hal_version_get_firmware_version()); - FURI_LOG_I(TAG, "starting services"); + FURI_LOG_I(TAG, "Boot mode %d, starting services", furi_hal_rtc_get_boot_mode()); for(size_t i = 0; i < FLIPPER_SERVICES_COUNT; i++) { - FURI_LOG_I(TAG, "starting service %s", FLIPPER_SERVICES[i].name); + FURI_LOG_I(TAG, "Starting service %s", FLIPPER_SERVICES[i].name); FuriThread* thread = furi_thread_alloc_ex( FLIPPER_SERVICES[i].name, @@ -44,7 +45,7 @@ void flipper_init() { furi_thread_start(thread); } - FURI_LOG_I(TAG, "services startup complete"); + FURI_LOG_I(TAG, "Startup complete"); } void vApplicationGetIdleTaskMemory( From 1d55aee39cbb329758a50f0110f6d69bc0d00274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 27 Feb 2023 01:29:42 +0900 Subject: [PATCH 11/35] Fix incorrect type choise condition in image compressor (#2434) --- scripts/flipper/assets/icon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index ed85b024e8..f0dae25bea 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -105,7 +105,7 @@ def file2image(file): data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc # Use encoded data only if its length less than original, including header - if len(data_enc) < len(data_bin) + 1: + if len(data_enc) + 2 < len(data_bin) + 1: data = b"\x01\x00" + data_enc else: data = b"\x00" + data_bin From 09edf66a2a00c20bce65203c84c6081c9d129aa7 Mon Sep 17 00:00:00 2001 From: Shane Synan Date: Sun, 26 Feb 2023 12:23:39 -0500 Subject: [PATCH 12/35] FuriHal, Power, UnitTests: fix, rename battery charging voltage limit API (#2228) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FuriHal, Power, UnitTests: rename battery charge voltage limit API * FuriHal: bump API, power info major versions * Power: fix battery charge voltage limit for > 7.935v Co-authored-by: あく --- .../debug/unit_tests/power/power_test.c | 61 +++++++++++-------- .../services/power/power_service/power.c | 6 +- .../services/power/power_service/power.h | 2 +- .../power_settings_scene_battery_info.c | 2 +- .../power_settings_app/views/battery_info.c | 6 +- .../power_settings_app/views/battery_info.h | 2 +- firmware/targets/f7/api_symbols.csv | 4 +- firmware/targets/f7/furi_hal/furi_hal_power.c | 12 ++-- .../targets/furi_hal_include/furi_hal_power.h | 10 +-- lib/drivers/bq25896.c | 17 +++--- lib/drivers/bq25896.h | 4 +- 11 files changed, 69 insertions(+), 57 deletions(-) diff --git a/applications/debug/unit_tests/power/power_test.c b/applications/debug/unit_tests/power/power_test.c index ce2c7aad72..a9b66b2211 100644 --- a/applications/debug/unit_tests/power/power_test.c +++ b/applications/debug/unit_tests/power/power_test.c @@ -3,56 +3,63 @@ #include "../minunit.h" static void power_test_deinit(void) { - // Try to reset to default charging voltage - furi_hal_power_set_battery_charging_voltage(4.208f); + // Try to reset to default charge voltage limit + furi_hal_power_set_battery_charge_voltage_limit(4.208f); } -MU_TEST(test_power_charge_voltage_exact) { - // Power of 16mV charge voltages get applied exactly +MU_TEST(test_power_charge_voltage_limit_exact) { + // Power of 16mV charge voltage limits get applied exactly // (bq25896 charge controller works in 16mV increments) // // This test may need adapted if other charge controllers are used in the future. for(uint16_t charge_mv = 3840; charge_mv <= 4208; charge_mv += 16) { float charge_volt = (float)charge_mv / 1000.0f; - furi_hal_power_set_battery_charging_voltage(charge_volt); - mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(charge_volt); + mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charge_voltage_limit()); } } -MU_TEST(test_power_charge_voltage_floating_imprecision) { +MU_TEST(test_power_charge_voltage_limit_floating_imprecision) { // 4.016f should act as 4.016 V, even with floating point imprecision - furi_hal_power_set_battery_charging_voltage(4.016f); - mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(4.016f); + mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charge_voltage_limit()); } -MU_TEST(test_power_charge_voltage_inexact) { - // Charge voltages that are not power of 16mV get truncated down - furi_hal_power_set_battery_charging_voltage(3.841f); - mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage()); +MU_TEST(test_power_charge_voltage_limit_inexact) { + // Charge voltage limits that are not power of 16mV get truncated down + furi_hal_power_set_battery_charge_voltage_limit(3.841f); + mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit()); - furi_hal_power_set_battery_charging_voltage(3.900f); - mu_assert_double_eq(3.888, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(3.900f); + mu_assert_double_eq(3.888, furi_hal_power_get_battery_charge_voltage_limit()); - furi_hal_power_set_battery_charging_voltage(4.200f); - mu_assert_double_eq(4.192, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(4.200f); + mu_assert_double_eq(4.192, furi_hal_power_get_battery_charge_voltage_limit()); } -MU_TEST(test_power_charge_voltage_invalid_clamped) { - // Out-of-range charge voltages get clamped to 3.840 V and 4.208 V - furi_hal_power_set_battery_charging_voltage(3.808f); - mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage()); +MU_TEST(test_power_charge_voltage_limit_invalid_clamped) { + // Out-of-range charge voltage limits get clamped to 3.840 V and 4.208 V + furi_hal_power_set_battery_charge_voltage_limit(3.808f); + mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit()); + furi_hal_power_set_battery_charge_voltage_limit(1.0f); + mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit()); // NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an // unhappy battery if this fails. - furi_hal_power_set_battery_charging_voltage(4.240f); - mu_assert_double_eq(4.208, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(4.240f); + mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit()); + // Likewise, picking a number that the uint8_t wraparound in the driver would result in a + // VREG value under 23 if this test fails. + // E.g. (uint8_t)((8105-3840)/16) -> 10 + furi_hal_power_set_battery_charge_voltage_limit(8.105f); + mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit()); } MU_TEST_SUITE(test_power_suite) { - MU_RUN_TEST(test_power_charge_voltage_exact); - MU_RUN_TEST(test_power_charge_voltage_floating_imprecision); - MU_RUN_TEST(test_power_charge_voltage_inexact); - MU_RUN_TEST(test_power_charge_voltage_invalid_clamped); + MU_RUN_TEST(test_power_charge_voltage_limit_exact); + MU_RUN_TEST(test_power_charge_voltage_limit_floating_imprecision); + MU_RUN_TEST(test_power_charge_voltage_limit_inexact); + MU_RUN_TEST(test_power_charge_voltage_limit_invalid_clamped); power_test_deinit(); } diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index d9319d3d91..56dbd0f87c 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -13,8 +13,8 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { if(power->info.gauge_is_ok) { canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4); - if(power->info.voltage_battery_charging < 4.2) { - // Battery charging voltage is modified, indicate with cross pattern + if(power->info.voltage_battery_charge_limit < 4.2) { + // Battery charge voltage limit is modified, indicate with cross pattern canvas_invert_color(canvas); uint8_t battery_bar_width = (power->info.charge + 4) / 5; bool cross_odd = false; @@ -147,7 +147,7 @@ static bool power_update_info(Power* power) { info.capacity_full = furi_hal_power_get_battery_full_capacity(); info.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger); info.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge); - info.voltage_battery_charging = furi_hal_power_get_battery_charging_voltage(); + info.voltage_battery_charge_limit = furi_hal_power_get_battery_charge_voltage_limit(); info.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger); info.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge); info.voltage_vbus = furi_hal_power_get_usb_voltage(); diff --git a/applications/services/power/power_service/power.h b/applications/services/power/power_service/power.h index 8b9019c424..c7f5d7e350 100644 --- a/applications/services/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -41,7 +41,7 @@ typedef struct { float current_charger; float current_gauge; - float voltage_battery_charging; + float voltage_battery_charge_limit; float voltage_charger; float voltage_gauge; float voltage_vbus; diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c index 5fa38df729..5181c93f7b 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c @@ -7,7 +7,7 @@ static void power_settings_scene_battery_info_update_model(PowerSettingsApp* app .gauge_voltage = app->info.voltage_gauge, .gauge_current = app->info.current_gauge, .gauge_temperature = app->info.temperature_gauge, - .charging_voltage = app->info.voltage_battery_charging, + .charge_voltage_limit = app->info.voltage_battery_charge_limit, .charge = app->info.charge, .health = app->info.health, }; diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index d29769d218..7394fd3c5a 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -69,7 +69,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); } else if(drain_current != 0) { snprintf(header, 20, "..."); - } else if(data->charging_voltage < 4.2) { + } else if(data->charge_voltage_limit < 4.2) { // Non-default battery charging limit, mention it snprintf(emote, sizeof(emote), "Charged!"); snprintf(header, sizeof(header), "Limited to"); @@ -77,8 +77,8 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { value, sizeof(value), "%lu.%luV", - (uint32_t)(data->charging_voltage), - (uint32_t)(data->charging_voltage * 10) % 10); + (uint32_t)(data->charge_voltage_limit), + (uint32_t)(data->charge_voltage_limit * 10) % 10); } else { snprintf(header, sizeof(header), "Charged!"); } diff --git a/applications/settings/power_settings_app/views/battery_info.h b/applications/settings/power_settings_app/views/battery_info.h index 7bfacf69e2..e52d1844c8 100644 --- a/applications/settings/power_settings_app/views/battery_info.h +++ b/applications/settings/power_settings_app/views/battery_info.h @@ -9,7 +9,7 @@ typedef struct { float gauge_voltage; float gauge_current; float gauge_temperature; - float charging_voltage; + float charge_voltage_limit; uint8_t charge; uint8_t health; } BatteryInfoModel; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index e320fc92ba..8a76f8c94f 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1211,7 +1211,7 @@ Function,+,furi_hal_power_enable_external_3_3v,void, Function,+,furi_hal_power_enable_otg,void, Function,+,furi_hal_power_gauge_is_ok,_Bool, Function,+,furi_hal_power_get_bat_health_pct,uint8_t, -Function,+,furi_hal_power_get_battery_charging_voltage,float, +Function,+,furi_hal_power_get_battery_charge_voltage_limit,float, Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC Function,+,furi_hal_power_get_battery_design_capacity,uint32_t, Function,+,furi_hal_power_get_battery_full_capacity,uint32_t, @@ -1230,7 +1230,7 @@ Function,+,furi_hal_power_is_charging_done,_Bool, Function,+,furi_hal_power_is_otg_enabled,_Bool, Function,+,furi_hal_power_off,void, Function,+,furi_hal_power_reset,void, -Function,+,furi_hal_power_set_battery_charging_voltage,void,float +Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float Function,+,furi_hal_power_shutdown,void, Function,+,furi_hal_power_sleep,void, Function,+,furi_hal_power_sleep_available,_Bool, diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index 2d709620d5..dd7c34ae73 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -341,14 +341,14 @@ bool furi_hal_power_is_otg_enabled() { return ret; } -float furi_hal_power_get_battery_charging_voltage() { +float furi_hal_power_get_battery_charge_voltage_limit() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); float ret = (float)bq25896_get_vreg_voltage(&furi_hal_i2c_handle_power) / 1000.0f; furi_hal_i2c_release(&furi_hal_i2c_handle_power); return ret; } -void furi_hal_power_set_battery_charging_voltage(float voltage) { +void furi_hal_power_set_battery_charge_voltage_limit(float voltage) { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); // Adding 0.0005 is necessary because 4.016f is 4.015999794000, which gets truncated bq25896_set_vreg_voltage(&furi_hal_i2c_handle_power, (uint16_t)(voltage * 1000.0f + 0.0005f)); @@ -486,7 +486,7 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context) property_value_out(&property_context, NULL, 2, "format", "major", "2"); property_value_out(&property_context, NULL, 2, "format", "minor", "1"); } else { - property_value_out(&property_context, NULL, 3, "power", "info", "major", "1"); + property_value_out(&property_context, NULL, 3, "power", "info", "major", "2"); property_value_out(&property_context, NULL, 3, "power", "info", "minor", "1"); } @@ -505,8 +505,10 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context) } property_value_out(&property_context, NULL, 2, "charge", "state", charge_state); - uint16_t charge_voltage = (uint16_t)(furi_hal_power_get_battery_charging_voltage() * 1000.f); - property_value_out(&property_context, "%u", 2, "charge", "voltage", charge_voltage); + uint16_t charge_voltage_limit = + (uint16_t)(furi_hal_power_get_battery_charge_voltage_limit() * 1000.f); + property_value_out( + &property_context, "%u", 3, "charge", "voltage", "limit", charge_voltage_limit); uint16_t voltage = (uint16_t)(furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge) * 1000.f); property_value_out(&property_context, "%u", 2, "battery", "voltage", voltage); diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index 39a11e99f7..462e20e41d 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -121,21 +121,21 @@ void furi_hal_power_check_otg_status(); */ bool furi_hal_power_is_otg_enabled(); -/** Get battery charging voltage in V +/** Get battery charge voltage limit in V * * @return voltage in V */ -float furi_hal_power_get_battery_charging_voltage(); +float furi_hal_power_get_battery_charge_voltage_limit(); -/** Set battery charging voltage in V +/** Set battery charge voltage limit in V * - * Invalid values will be clamped to the nearest valid value. + * Invalid values will be clamped downward to the nearest valid value. * * @param voltage[in] voltage in V * * @return voltage in V */ -void furi_hal_power_set_battery_charging_voltage(float voltage); +void furi_hal_power_set_battery_charge_voltage_limit(float voltage); /** Get remaining battery battery capacity in mAh * diff --git a/lib/drivers/bq25896.c b/lib/drivers/bq25896.c index 7e3008d62d..99534fb13a 100644 --- a/lib/drivers/bq25896.c +++ b/lib/drivers/bq25896.c @@ -140,15 +140,18 @@ uint16_t bq25896_get_vreg_voltage(FuriHalI2cBusHandle* handle) { void bq25896_set_vreg_voltage(FuriHalI2cBusHandle* handle, uint16_t vreg_voltage) { if(vreg_voltage < 3840) { - // Minimum value is 3840 mV - bq25896_regs.r06.VREG = 0; - } else { - // Find the nearest voltage value (subtract offset, divide into sections) - // Values are truncated downward as needed (e.g. 4200mV -> 4192 mV) - bq25896_regs.r06.VREG = (uint8_t)((vreg_voltage - 3840) / 16); + // Minimum valid value is 3840 mV + vreg_voltage = 3840; + } else if(vreg_voltage > 4208) { + // Maximum safe value is 4208 mV + vreg_voltage = 4208; } - // Do not allow values above 23 (0x17, 4208mV) + // Find the nearest voltage value (subtract offset, divide into sections) + // Values are truncated downward as needed (e.g. 4200mV -> 4192 mV) + bq25896_regs.r06.VREG = (uint8_t)((vreg_voltage - 3840) / 16); + + // Double check: do not allow values above 23 (0x17, 4208mV) // Exceeding 4.2v will overcharge the battery! if(bq25896_regs.r06.VREG > 23) { bq25896_regs.r06.VREG = 23; diff --git a/lib/drivers/bq25896.h b/lib/drivers/bq25896.h index c8a8526a16..f3d1d0e058 100644 --- a/lib/drivers/bq25896.h +++ b/lib/drivers/bq25896.h @@ -36,10 +36,10 @@ void bq25896_disable_otg(FuriHalI2cBusHandle* handle); /** Is otg enabled */ bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle); -/** Get VREG (charging) voltage in mV */ +/** Get VREG (charging limit) voltage in mV */ uint16_t bq25896_get_vreg_voltage(FuriHalI2cBusHandle* handle); -/** Set VREG (charging) voltage in mV +/** Set VREG (charging limit) voltage in mV * * Valid range: 3840mV - 4208mV, in steps of 16mV */ From b054912167764e37e968a8996fc50047392c6be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 27 Feb 2023 02:39:26 +0900 Subject: [PATCH 13/35] F8, F18: bump API symbols version (#2435) --- firmware/targets/f18/api_symbols.csv | 6 +++--- firmware/targets/f7/api_symbols.csv | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 462fbf739d..549d381296 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,14.0,, +Version,+,15.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -979,7 +979,7 @@ Function,+,furi_hal_power_enable_external_3_3v,void, Function,+,furi_hal_power_enable_otg,void, Function,+,furi_hal_power_gauge_is_ok,_Bool, Function,+,furi_hal_power_get_bat_health_pct,uint8_t, -Function,+,furi_hal_power_get_battery_charging_voltage,float, +Function,+,furi_hal_power_get_battery_charge_voltage_limit,float, Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC Function,+,furi_hal_power_get_battery_design_capacity,uint32_t, Function,+,furi_hal_power_get_battery_full_capacity,uint32_t, @@ -998,7 +998,7 @@ Function,+,furi_hal_power_is_charging_done,_Bool, Function,+,furi_hal_power_is_otg_enabled,_Bool, Function,+,furi_hal_power_off,void, Function,+,furi_hal_power_reset,void, -Function,+,furi_hal_power_set_battery_charging_voltage,void,float +Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float Function,+,furi_hal_power_shutdown,void, Function,+,furi_hal_power_sleep,void, Function,+,furi_hal_power_sleep_available,_Bool, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 8a76f8c94f..8152095dca 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,14.1,, +Version,+,15.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, From 478390de191f876ef12ed9a54301390a01e8ce40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 27 Feb 2023 03:06:19 +0900 Subject: [PATCH 14/35] Drivers: remove excessive check in bq25896 and make PVS happy (#2436) --- lib/drivers/bq25896.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/drivers/bq25896.c b/lib/drivers/bq25896.c index 99534fb13a..4c1d687cb0 100644 --- a/lib/drivers/bq25896.c +++ b/lib/drivers/bq25896.c @@ -151,12 +151,6 @@ void bq25896_set_vreg_voltage(FuriHalI2cBusHandle* handle, uint16_t vreg_voltage // Values are truncated downward as needed (e.g. 4200mV -> 4192 mV) bq25896_regs.r06.VREG = (uint8_t)((vreg_voltage - 3840) / 16); - // Double check: do not allow values above 23 (0x17, 4208mV) - // Exceeding 4.2v will overcharge the battery! - if(bq25896_regs.r06.VREG > 23) { - bq25896_regs.r06.VREG = 23; - } - // Apply changes furi_hal_i2c_write_reg_8( handle, BQ25896_ADDRESS, 0x06, *(uint8_t*)&bq25896_regs.r06, BQ25896_I2C_TIMEOUT); From cd14380dbaa38628a8c68e3ab99a76dfa7d54641 Mon Sep 17 00:00:00 2001 From: matthisc Date: Sun, 26 Feb 2023 20:09:05 +0100 Subject: [PATCH 15/35] Correcting bug on DEL and DELETE --- applications/plugins/mousejacker/mousejacker_ducky.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index d5a32c4842..f9ded2d034 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -97,7 +97,7 @@ static uint32_t mj_ducky_get_command_len(const char* line) { static bool mj_get_ducky_key(char* key, size_t keylen, MJDuckyKey* dk) { //FURI_LOG_D(TAG, "looking up key %s with length %d", key, keylen); for(uint i = 0; i < sizeof(mj_ducky_keys) / sizeof(MJDuckyKey); i++) { - if(strncmp(mj_ducky_keys[i].name, key, keylen) == 0) { + if(strlen(mj_ducky_keys[i].name) == keylen && !strncmp(mj_ducky_keys[i].name, key, keylen)) { memcpy(dk, &mj_ducky_keys[i], sizeof(MJDuckyKey)); return true; } From 182296d8af1a61b21b72e7451c4c8ff78f0f1244 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 27 Feb 2023 01:13:21 +0300 Subject: [PATCH 16/35] Nice flor s - custom buttons --- CHANGELOG.md | 18 ++-- ReadMe.md | 2 +- .../scenes/subghz_scene_receiver_info.c | 2 + .../main/subghz/scenes/subghz_scene_rpc.c | 2 + .../subghz/scenes/subghz_scene_transmitter.c | 3 + applications/main/subghz/views/transmitter.c | 16 ++++ applications/main/unirfremix/unirfremix_app.c | 2 + firmware/targets/f7/api_symbols.csv | 4 + lib/subghz/protocols/nice_flor_s.c | 92 +++++++++++++++++++ lib/subghz/protocols/nice_flor_s.h | 8 ++ 10 files changed, 140 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 128c9465aa..6cc844c23c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,14 @@ ### New changes -* SubGHz: **Keeloq: Beninca - protocol support** -* SubGHz: **Hold right in received signal list to delete selected signal** -* SubGHz: **Custom buttons for Keeloq and Alutech AT4N** - now you can use arrow buttons to send signal with different button code -* SubGHz: Debug mode counter increase settings (+5, +10, default: +1) -* Infrared: Debug TX PIN output settings (ability to move tx signal out to GPIO) (implemented #364) -* Plugins: Updated -> [BH1750] Lightmeter [(by oleksiikutuzov)](https://github.com/oleksiikutuzov/flipperzero-lightmeter) -* OFW: BadUSB -> STRINGDELAY(STRING_DELAY) feature, worker signal handling refactoring -> (Fixed #365 (BadUSB won't detect connection and/or hangs)) -* OFW: Grammar fixes +* SubGHz: **Custom buttons for Nice Flor S** - now you can use arrow buttons to send signal with different button code +* OFW: Drivers: remove excessive check in bq25896 and make PVS happy +* OFW: FuriHal, Power, UnitTests: fix, rename battery charging voltage limit API -> **Breaking API change, api was changed from 14.x to 15.x** +**(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** + +* OFW: Fix incorrect type choise condition in image compressor +* OFW: Updater: handle storage errors when removing files, fix folder remove routine, prevent unused services from starting +* OFW: Unify power info, power debug, and device_info into one info command +* OFW: SD Cache: moved to diskio layer, invalidation in case of error +* OFW: Picopass: factory key support, minor code cleanup #### [🎲 Download latest extra apps pack](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps) diff --git a/ReadMe.md b/ReadMe.md index a78f749e04..6f99a19932 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -166,7 +166,7 @@ Games: - Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79) - Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107) * SubGHz -> **Hold right in received signal list to delete selected signal** -* SubGHz -> **Custom buttons for Keeloq and Alutech AT4N** - now you can use arrow buttons to send signal with different button code +* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S** - now you can use arrow buttons to send signal with different button code * SubGHz -> Debug mode counter increase settings (+5, +10, default: +1) * SubGHz -> Debug PIN output settings for protocol development * Infrared -> Debug TX PIN output settings diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 4f4924b06d..c654ad0c53 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -3,6 +3,7 @@ #include #include #include +#include void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); @@ -236,6 +237,7 @@ void subghz_scene_receiver_info_on_exit(void* context) { keeloq_reset_kl_type(); keeloq_reset_original_btn(); alutech_reset_original_btn(); + nice_flors_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 0ff801d79a..b64f92de2d 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -2,6 +2,7 @@ #include #include #include +#include typedef enum { SubGhzRpcStateIdle, @@ -113,6 +114,7 @@ void subghz_scene_rpc_on_exit(void* context) { keeloq_reset_kl_type(); keeloq_reset_original_btn(); alutech_reset_original_btn(); + nice_flors_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 53fc95981e..a10e10a37a 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -4,6 +4,7 @@ #include #include #include +#include void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { furi_assert(context); @@ -93,6 +94,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(keeloq_get_custom_btn() != 0) { keeloq_set_btn(0); alutech_set_btn(0); + nice_flors_set_btn(0); uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); furi_hal_subghz_set_rolling_counter_mult(0); // Calling restore! @@ -135,6 +137,7 @@ void subghz_scene_transmitter_on_exit(void* context) { keeloq_reset_kl_type(); keeloq_reset_original_btn(); alutech_reset_original_btn(); + nice_flors_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 218bf8f7ef..5a64f27e23 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -6,6 +6,7 @@ #include #include +#include struct SubGhzViewTransmitter { View* view; @@ -159,6 +160,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) { keeloq_set_btn(1); alutech_set_btn(1); + nice_flors_set_btn(1); with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, @@ -170,6 +172,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { } else if(alutech_get_original_btn() != 0) { furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn()); model->draw_temp_button = true; + } else if(nice_flors_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", nice_flors_get_original_btn()); + model->draw_temp_button = true; } }, true); @@ -185,6 +191,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) { keeloq_set_btn(2); alutech_set_btn(2); + nice_flors_set_btn(2); with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, @@ -196,6 +203,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { } else if(alutech_get_original_btn() != 0) { furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn()); model->draw_temp_button = true; + } else if(nice_flors_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", nice_flors_get_original_btn()); + model->draw_temp_button = true; } }, true); @@ -211,6 +222,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) { keeloq_set_btn(3); alutech_set_btn(3); + nice_flors_set_btn(3); with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, @@ -222,6 +234,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { } else if(alutech_get_original_btn() != 0) { furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn()); model->draw_temp_button = true; + } else if(nice_flors_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", nice_flors_get_original_btn()); + model->draw_temp_button = true; } }, true); diff --git a/applications/main/unirfremix/unirfremix_app.c b/applications/main/unirfremix/unirfremix_app.c index 81d8ceb1a6..4f8d5fa01d 100644 --- a/applications/main/unirfremix/unirfremix_app.c +++ b/applications/main/unirfremix/unirfremix_app.c @@ -20,6 +20,7 @@ #include #include #include +#include #define UNIRFMAP_FOLDER "/ext/unirf" #define UNIRFMAP_EXTENSION ".txt" @@ -484,6 +485,7 @@ void unirfremix_tx_stop(UniRFRemix* app) { keeloq_reset_kl_type(); keeloq_reset_original_btn(); alutech_reset_original_btn(); + nice_flors_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 7dc6378fe2..08c95fe1f0 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2063,6 +2063,10 @@ Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" Function,-,nfca_signal_alloc,NfcaSignal*, Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" Function,-,nfca_signal_free,void,NfcaSignal* +Function,-,nice_flors_get_custom_btn,uint8_t, +Function,-,nice_flors_get_original_btn,uint8_t, +Function,-,nice_flors_reset_original_btn,void, +Function,-,nice_flors_set_btn,void,uint8_t Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 5120573f07..f58c6084ff 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -84,6 +84,25 @@ const SubGhzProtocol subghz_protocol_nice_flor_s = { .encoder = &subghz_protocol_nice_flor_s_encoder, }; +static uint8_t n_btn_temp_id; +static uint8_t n_btn_temp_id_original; + +void nice_flors_set_btn(uint8_t b) { + n_btn_temp_id = b; +} + +uint8_t nice_flors_get_original_btn() { + return n_btn_temp_id_original; +} + +uint8_t nice_flors_get_custom_btn() { + return n_btn_temp_id; +} + +void nice_flors_reset_original_btn() { + n_btn_temp_id_original = 0; +} + static void subghz_protocol_nice_flor_s_remote_controller( SubGhzBlockGeneric* instance, const char* file_name); @@ -128,6 +147,74 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( size_t index = 0; btn = instance->generic.btn; + // Save original button for later use + if(n_btn_temp_id_original == 0) { + n_btn_temp_id_original = btn; + } + + // Set custom button + if(n_btn_temp_id == 1) { + switch(n_btn_temp_id_original) { + case 0x1: + btn = 0x2; + break; + case 0x2: + btn = 0x1; + break; + case 0x4: + btn = 0x1; + break; + case 0x8: + btn = 0x1; + break; + + default: + break; + } + } + if(n_btn_temp_id == 2) { + switch(n_btn_temp_id_original) { + case 0x1: + btn = 0x4; + break; + case 0x2: + btn = 0x4; + break; + case 0x4: + btn = 0x2; + break; + case 0x8: + btn = 0x4; + break; + + default: + break; + } + } + if(n_btn_temp_id == 3) { + switch(n_btn_temp_id_original) { + case 0x1: + btn = 0x8; + break; + case 0x2: + btn = 0x8; + break; + case 0x4: + btn = 0x8; + break; + case 0x8: + btn = 0x2; + break; + + default: + break; + } + } + + if((n_btn_temp_id == 0) && (n_btn_temp_id_original != 0)) { + btn = n_btn_temp_id_original; + } + size_t size_upload = ((instance->generic.data_count_bit * 2) + ((37 + 2 + 2) * 2) * 16); if(size_upload > instance->encoder.size_upload) { FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); @@ -646,6 +733,11 @@ static void subghz_protocol_nice_flor_s_remote_controller( instance->serial = (decrypt >> 16) & 0xFFFFFFF; instance->btn = (decrypt >> 48) & 0xF; } + + // Save original button for later use + if(n_btn_temp_id_original == 0) { + n_btn_temp_id_original = instance->btn; + } } uint8_t subghz_protocol_decoder_nice_flor_s_get_hash_data(void* context) { diff --git a/lib/subghz/protocols/nice_flor_s.h b/lib/subghz/protocols/nice_flor_s.h index e333fc9798..52f0ca7458 100644 --- a/lib/subghz/protocols/nice_flor_s.h +++ b/lib/subghz/protocols/nice_flor_s.h @@ -11,6 +11,14 @@ extern const SubGhzProtocolDecoder subghz_protocol_nice_flor_s_decoder; extern const SubGhzProtocolEncoder subghz_protocol_nice_flor_s_encoder; extern const SubGhzProtocol subghz_protocol_nice_flor_s; +// Custom buttons +void nice_flors_set_btn(uint8_t b); + +uint8_t nice_flors_get_original_btn(); +uint8_t nice_flors_get_custom_btn(); + +void nice_flors_reset_original_btn(); + /** * Allocate SubGhzProtocolEncoderNiceFlorS. * @param environment Pointer to a SubGhzEnvironment instance From 4439a8373394eb265cf452b49ef11361d251e11a Mon Sep 17 00:00:00 2001 From: Clashlab Date: Mon, 27 Feb 2023 09:19:30 +0100 Subject: [PATCH 17/35] hc_sr04: Improve accuracy by measuring micro-seconds --- applications/plugins/hc_sr04/hc_sr04.c | 27 +++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/applications/plugins/hc_sr04/hc_sr04.c b/applications/plugins/hc_sr04/hc_sr04.c index dbbf4f3ec0..3cb9e72d6d 100644 --- a/applications/plugins/hc_sr04/hc_sr04.c +++ b/applications/plugins/hc_sr04/hc_sr04.c @@ -3,6 +3,7 @@ // Ported and modified by @xMasterX #include +#include #include #include #include @@ -26,7 +27,7 @@ typedef struct { NotificationApp* notification; bool have_5v; bool measurement_made; - uint32_t echo; // ms + uint32_t echo; // us float distance; // meters } PluginState; @@ -72,7 +73,7 @@ static void render_callback(Canvas* const canvas, void* ctx) { FuriString* str_buf; str_buf = furi_string_alloc(); - furi_string_printf(str_buf, "Echo: %ld ms", plugin_state->echo); + furi_string_printf(str_buf, "Echo: %ld us", plugin_state->echo); canvas_draw_str_aligned( canvas, 8, 38, AlignLeft, AlignTop, furi_string_get_cstr(str_buf)); @@ -110,9 +111,11 @@ static void hc_sr04_state_init(PluginState* const plugin_state) { } } -float hc_sr04_ms_to_m(uint32_t ms) { - const float speed_sound_m_per_s = 343.0f; - const float time_s = ms / 1e3f; +float hc_sr04_us_to_m(uint32_t us) { + //speed of sound for 20°C, 50% relative humidity + //331.3 + 20 * 0.606 + 50 * 0.0124 = 0.034404 + const float speed_sound_m_per_s = 344.04f; + const float time_s = us / 1e6f; const float total_dist = time_s * speed_sound_m_per_s; return total_dist / 2.0f; } @@ -147,10 +150,6 @@ static void hc_sr04_measure(PluginState* const plugin_state) { furi_delay_ms(10); furi_hal_gpio_write(&gpio_usart_tx, false); - // TODO change from furi_get_tick(), which returns ms, - // to DWT->CYCCNT, which is a more precise counter with - // us precision (see furi_hal_cortex_delay_us) - const uint32_t start = furi_get_tick(); while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx)) @@ -158,16 +157,16 @@ static void hc_sr04_measure(PluginState* const plugin_state) { while(furi_get_tick() - start < timeout_ms && !furi_hal_gpio_read(&gpio_usart_rx)) ; - const uint32_t pulse_start = furi_get_tick(); + const uint32_t pulse_start = DWT->CYCCNT; while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx)) ; + const uint32_t pulse_end = DWT->CYCCNT; - const uint32_t pulse_end = furi_get_tick(); //FURI_CRITICAL_EXIT(); - plugin_state->echo = pulse_end - pulse_start; - plugin_state->distance = hc_sr04_ms_to_m(pulse_end - pulse_start); + plugin_state->echo = (pulse_end - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); + plugin_state->distance = hc_sr04_us_to_m(plugin_state->echo); plugin_state->measurement_made = true; //furi_hal_light_set(LightRed, 0x00); @@ -270,4 +269,4 @@ int32_t hc_sr04_app() { delete_mutex(&state_mutex); return 0; -} \ No newline at end of file +} From e6d1bcc42126ec2f0aa7df3811a2aa98caec0eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 27 Feb 2023 22:33:45 +0900 Subject: [PATCH 18/35] Plugins: move to designated categories (#2438) --- applications/plugins/dap_link/application.fam | 2 +- applications/plugins/hid_app/application.fam | 8 ++++---- applications/plugins/music_player/application.fam | 2 +- applications/plugins/nfc_magic/application.fam | 2 +- applications/plugins/signal_generator/application.fam | 2 +- applications/plugins/spi_mem_manager/application.fam | 2 +- applications/plugins/weather_station/application.fam | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/applications/plugins/dap_link/application.fam b/applications/plugins/dap_link/application.fam index 3b99d5ef37..711e4833d0 100644 --- a/applications/plugins/dap_link/application.fam +++ b/applications/plugins/dap_link/application.fam @@ -10,7 +10,7 @@ App( stack_size=4 * 1024, order=20, fap_icon="dap_link.png", - fap_category="Tools", + fap_category="GPIO", fap_private_libs=[ Lib( name="free-dap", diff --git a/applications/plugins/hid_app/application.fam b/applications/plugins/hid_app/application.fam index b8c13e3538..b6e4e3bf8f 100644 --- a/applications/plugins/hid_app/application.fam +++ b/applications/plugins/hid_app/application.fam @@ -1,10 +1,10 @@ App( appid="hid_usb", - name="USB Remote", + name="Remote", apptype=FlipperAppType.PLUGIN, entry_point="hid_usb_app", stack_size=1 * 1024, - fap_category="Tools", + fap_category="USB", fap_icon="hid_usb_10px.png", fap_icon_assets="assets", fap_icon_assets_symbol="hid", @@ -13,11 +13,11 @@ App( App( appid="hid_ble", - name="Bluetooth Remote", + name="Remote", apptype=FlipperAppType.PLUGIN, entry_point="hid_ble_app", stack_size=1 * 1024, - fap_category="Tools", + fap_category="Bluetooth", fap_icon="hid_ble_10px.png", fap_icon_assets="assets", fap_icon_assets_symbol="hid", diff --git a/applications/plugins/music_player/application.fam b/applications/plugins/music_player/application.fam index a369889833..c51abf1944 100644 --- a/applications/plugins/music_player/application.fam +++ b/applications/plugins/music_player/application.fam @@ -12,7 +12,7 @@ App( stack_size=2 * 1024, order=20, fap_icon="icons/music_10px.png", - fap_category="Misc", + fap_category="Media", fap_icon_assets="icons", ) diff --git a/applications/plugins/nfc_magic/application.fam b/applications/plugins/nfc_magic/application.fam index bf42681cae..a89b45d009 100644 --- a/applications/plugins/nfc_magic/application.fam +++ b/applications/plugins/nfc_magic/application.fam @@ -11,7 +11,7 @@ App( stack_size=4 * 1024, order=30, fap_icon="../../../assets/icons/Archive/125_10px.png", - fap_category="Tools", + fap_category="NFC", fap_private_libs=[ Lib( name="magic", diff --git a/applications/plugins/signal_generator/application.fam b/applications/plugins/signal_generator/application.fam index de915733c4..60f8deffb9 100644 --- a/applications/plugins/signal_generator/application.fam +++ b/applications/plugins/signal_generator/application.fam @@ -8,6 +8,6 @@ App( stack_size=1 * 1024, order=50, fap_icon="signal_gen_10px.png", - fap_category="Tools", + fap_category="GPIO", fap_icon_assets="icons", ) diff --git a/applications/plugins/spi_mem_manager/application.fam b/applications/plugins/spi_mem_manager/application.fam index 09d8018769..c1b10bfee2 100644 --- a/applications/plugins/spi_mem_manager/application.fam +++ b/applications/plugins/spi_mem_manager/application.fam @@ -7,7 +7,7 @@ App( stack_size=1 * 2048, order=30, fap_icon="images/Dip8_10px.png", - fap_category="Tools", + fap_category="GPIO", fap_icon_assets="images", fap_private_libs=[ Lib( diff --git a/applications/plugins/weather_station/application.fam b/applications/plugins/weather_station/application.fam index 769b6dd275..935f92573b 100644 --- a/applications/plugins/weather_station/application.fam +++ b/applications/plugins/weather_station/application.fam @@ -9,6 +9,6 @@ App( stack_size=4 * 1024, order=50, fap_icon="weather_station_10px.png", - fap_category="Tools", + fap_category="Sub-GHz", fap_icon_assets="images", ) From 9ae58f5462b1a4d8efba88e0ac24cd1fff83ede6 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 27 Feb 2023 17:04:14 +0300 Subject: [PATCH 19/35] [FL-3116, FL-3136] BadUSB UI fixes (#2439) --- applications/main/bad_usb/bad_usb_app.c | 8 +++---- .../main/bad_usb/scenes/bad_usb_scene_work.c | 4 +++- .../main/bad_usb/views/bad_usb_view.c | 23 +++++++++++++++---- .../main/bad_usb/views/bad_usb_view.h | 2 ++ 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c index 1b24957915..ea97c44878 100644 --- a/applications/main/bad_usb/bad_usb_app.c +++ b/applications/main/bad_usb/bad_usb_app.c @@ -142,10 +142,6 @@ void bad_usb_app_free(BadUsbApp* app) { app->bad_usb_script = NULL; } - if(app->usb_if_prev) { - furi_check(furi_hal_usb_set_config(app->usb_if_prev, NULL)); - } - // Views view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); bad_usb_free(app->bad_usb_view); @@ -172,6 +168,10 @@ void bad_usb_app_free(BadUsbApp* app) { furi_string_free(app->file_path); furi_string_free(app->keyboard_layout); + if(app->usb_if_prev) { + furi_check(furi_hal_usb_set_config(app->usb_if_prev, NULL)); + } + free(app); } diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c index 187b83bd96..6f2b826935 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_work.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_work.c @@ -16,7 +16,9 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == InputKeyLeft) { - scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig); + if(bad_usb_is_idle_state(app->bad_usb_view)) { + scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig); + } consumed = true; } else if(event.event == InputKeyOk) { bad_usb_script_toggle(app->bad_usb_script); diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index bb9dc3b7e3..9ee9dc341c 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -48,17 +48,13 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone) || (model->state.state == BadUsbStateNotConnected)) { elements_button_center(canvas, "Run"); + elements_button_left(canvas, "Config"); } else if((model->state.state == BadUsbStateRunning) || (model->state.state == BadUsbStateDelay)) { elements_button_center(canvas, "Stop"); } else if(model->state.state == BadUsbStateWillRun) { elements_button_center(canvas, "Cancel"); } - if((model->state.state == BadUsbStateNotConnected) || - (model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone)) { - elements_button_left(canvas, "Config"); - } - if(model->state.state == BadUsbStateNotConnected) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); @@ -203,6 +199,7 @@ void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) { { strlcpy(model->layout, layout, MAX_NAME_LEN); }, true); } + void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { furi_assert(st); with_view_model( @@ -214,3 +211,19 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { }, true); } + +bool bad_usb_is_idle_state(BadUsb* bad_usb) { + bool is_idle = false; + with_view_model( + bad_usb->view, + BadUsbModel * model, + { + if((model->state.state == BadUsbStateIdle) || + (model->state.state == BadUsbStateDone) || + (model->state.state == BadUsbStateNotConnected)) { + is_idle = true; + } + }, + false); + return is_idle; +} diff --git a/applications/main/bad_usb/views/bad_usb_view.h b/applications/main/bad_usb/views/bad_usb_view.h index 8447fb0559..2fc01688aa 100644 --- a/applications/main/bad_usb/views/bad_usb_view.h +++ b/applications/main/bad_usb/views/bad_usb_view.h @@ -19,3 +19,5 @@ void bad_usb_set_file_name(BadUsb* bad_usb, const char* name); void bad_usb_set_layout(BadUsb* bad_usb, const char* layout); void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st); + +bool bad_usb_is_idle_state(BadUsb* bad_usb); From 568176d775a7a23535c290cc7512d1f45a71df16 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 27 Feb 2023 23:13:52 +0300 Subject: [PATCH 20/35] App categories --- applications/plugins/metronome/application.fam | 2 +- applications/plugins/morse_code/application.fam | 2 +- applications/plugins/music_player/application.fam | 2 +- applications/plugins/nfc_magic/application.fam | 2 +- applications/plugins/playlist/application.fam | 2 +- applications/plugins/pocsag_pager/application.fam | 2 +- applications/plugins/protoview/application.fam | 2 +- applications/plugins/spectrum_analyzer/application.fam | 2 +- applications/plugins/subbrute | 2 +- applications/plugins/swd_probe/application.fam | 2 +- applications/plugins/wav_player/application.fam | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/applications/plugins/metronome/application.fam b/applications/plugins/metronome/application.fam index 32588d06ef..a3435fd772 100644 --- a/applications/plugins/metronome/application.fam +++ b/applications/plugins/metronome/application.fam @@ -8,7 +8,7 @@ App( "gui", ], fap_icon="metronome_icon.png", - fap_category="Music", + fap_category="Media", fap_icon_assets="images", stack_size=2 * 1024, order=20, diff --git a/applications/plugins/morse_code/application.fam b/applications/plugins/morse_code/application.fam index 47a9862332..16a52fbd51 100644 --- a/applications/plugins/morse_code/application.fam +++ b/applications/plugins/morse_code/application.fam @@ -10,6 +10,6 @@ App( stack_size=1 * 1024, order=20, fap_icon="morse_code_10px.png", - fap_category="Music" + fap_category="Media" ) \ No newline at end of file diff --git a/applications/plugins/music_player/application.fam b/applications/plugins/music_player/application.fam index 74f6f6d5d4..b8bd75198f 100644 --- a/applications/plugins/music_player/application.fam +++ b/applications/plugins/music_player/application.fam @@ -13,7 +13,7 @@ App( order=20, fap_icon="icons/music_10px.png", fap_icon_assets="icons", - fap_category="Music", + fap_category="Media", ) App( diff --git a/applications/plugins/nfc_magic/application.fam b/applications/plugins/nfc_magic/application.fam index 717387d58a..db0af81d43 100644 --- a/applications/plugins/nfc_magic/application.fam +++ b/applications/plugins/nfc_magic/application.fam @@ -11,7 +11,7 @@ App( stack_size=4 * 1024, order=30, fap_icon="../../../assets/icons/Archive/Nfc_10px.png", - fap_category="NFC", + fap_category="Tools", fap_private_libs=[ Lib( name="magic", diff --git a/applications/plugins/playlist/application.fam b/applications/plugins/playlist/application.fam index fda109dab7..06357e24b7 100644 --- a/applications/plugins/playlist/application.fam +++ b/applications/plugins/playlist/application.fam @@ -8,6 +8,6 @@ App( stack_size=2 * 1024, order=14, fap_icon="playlist_10px.png", - fap_category="Tools", + fap_category="Sub-GHz", fap_icon_assets="images", ) diff --git a/applications/plugins/pocsag_pager/application.fam b/applications/plugins/pocsag_pager/application.fam index aafb6a5a37..86f8d528ba 100644 --- a/applications/plugins/pocsag_pager/application.fam +++ b/applications/plugins/pocsag_pager/application.fam @@ -8,6 +8,6 @@ App( stack_size=4 * 1024, order=50, fap_icon="pocsag_pager_10px.png", - fap_category="Tools", + fap_category="Sub-GHz", fap_icon_assets="images", ) diff --git a/applications/plugins/protoview/application.fam b/applications/plugins/protoview/application.fam index 6cd31372e2..234a00bc69 100644 --- a/applications/plugins/protoview/application.fam +++ b/applications/plugins/protoview/application.fam @@ -8,5 +8,5 @@ App( stack_size=8*1024, order=50, fap_icon="appicon.png", - fap_category="Tools", + fap_category="Sub-GHz", ) diff --git a/applications/plugins/spectrum_analyzer/application.fam b/applications/plugins/spectrum_analyzer/application.fam index 04bb946eea..344c2244f1 100644 --- a/applications/plugins/spectrum_analyzer/application.fam +++ b/applications/plugins/spectrum_analyzer/application.fam @@ -8,5 +8,5 @@ App( stack_size=2 * 1024, order=12, fap_icon="spectrum_10px.png", - fap_category="Tools", + fap_category="Sub-GHz", ) diff --git a/applications/plugins/subbrute b/applications/plugins/subbrute index 819b532937..7cdb9e1386 160000 --- a/applications/plugins/subbrute +++ b/applications/plugins/subbrute @@ -1 +1 @@ -Subproject commit 819b532937b8920504cd54385e25389c199285f9 +Subproject commit 7cdb9e1386778ad7351f7e3b3389980afaeafea3 diff --git a/applications/plugins/swd_probe/application.fam b/applications/plugins/swd_probe/application.fam index 64140d1301..c24813ed94 100644 --- a/applications/plugins/swd_probe/application.fam +++ b/applications/plugins/swd_probe/application.fam @@ -8,6 +8,6 @@ App( stack_size=2 * 1024, order=10, fap_icon="icons/app.png", - fap_category="Tools", + fap_category="GPIO", fap_icon_assets="icons" ) diff --git a/applications/plugins/wav_player/application.fam b/applications/plugins/wav_player/application.fam index 4040ed1598..6ab832d031 100644 --- a/applications/plugins/wav_player/application.fam +++ b/applications/plugins/wav_player/application.fam @@ -7,6 +7,6 @@ App( stack_size=4 * 1024, order=46, fap_icon="wav_10px.png", - fap_category="Music", + fap_category="Media", fap_icon_assets="images", ) From 2c95a7cba4b4ee32045e09354b8fb833af3939fe Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 00:02:30 +0300 Subject: [PATCH 21/35] Somfy Telis - Custom buttons + Prog mode --- CHANGELOG.md | 3 +- ReadMe.md | 5 +- .../scenes/subghz_scene_receiver_info.c | 2 + .../main/subghz/scenes/subghz_scene_rpc.c | 2 + .../subghz/scenes/subghz_scene_transmitter.c | 3 + applications/main/subghz/views/transmitter.c | 16 +++ applications/main/unirfremix/unirfremix_app.c | 2 + firmware/targets/f7/api_symbols.csv | 4 + lib/subghz/protocols/somfy_telis.c | 121 ++++++++++++++++-- lib/subghz/protocols/somfy_telis.h | 8 ++ 10 files changed, 153 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cc844c23c..a50bfb1cf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### New changes -* SubGHz: **Custom buttons for Nice Flor S** - now you can use arrow buttons to send signal with different button code +* SubGHz: **Custom buttons for Nice Flor S / Somfy Telis (+Programming mode)** - now you can use arrow buttons to send signal with different button code +* SubGHz: Somfy Telis -> Add manually (create new remote, now with programming button (Prog / 0x8) you can write it into receiver) * OFW: Drivers: remove excessive check in bq25896 and make PVS happy * OFW: FuriHal, Power, UnitTests: fix, rename battery charging voltage limit API -> **Breaking API change, api was changed from 14.x to 15.x** **(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** diff --git a/ReadMe.md b/ReadMe.md index 6f99a19932..2e9b0327eb 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -72,7 +72,7 @@ Encoders/sending made by Eng1n33r & @xMasterX: - CAME Atomo - Nice Flor S - FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: Nano#8998)] -- BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)] +- Keeloq: BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)] - Security+ v1 & v2 - Star Line @@ -166,7 +166,8 @@ Games: - Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79) - Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107) * SubGHz -> **Hold right in received signal list to delete selected signal** -* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S** - now you can use arrow buttons to send signal with different button code +* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis** - now you can use arrow buttons to send signal with different button code +* SubGHz -> BFT Mitto / Somfy Telis manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis) * SubGHz -> Debug mode counter increase settings (+5, +10, default: +1) * SubGHz -> Debug PIN output settings for protocol development * Infrared -> Debug TX PIN output settings diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index c654ad0c53..fd28421a81 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -4,6 +4,7 @@ #include #include #include +#include void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); @@ -238,6 +239,7 @@ void subghz_scene_receiver_info_on_exit(void* context) { keeloq_reset_original_btn(); alutech_reset_original_btn(); nice_flors_reset_original_btn(); + somfy_telis_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index b64f92de2d..01804492e1 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -3,6 +3,7 @@ #include #include #include +#include typedef enum { SubGhzRpcStateIdle, @@ -115,6 +116,7 @@ void subghz_scene_rpc_on_exit(void* context) { keeloq_reset_original_btn(); alutech_reset_original_btn(); nice_flors_reset_original_btn(); + somfy_telis_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index a10e10a37a..00839170c7 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -5,6 +5,7 @@ #include #include #include +#include void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { furi_assert(context); @@ -95,6 +96,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { keeloq_set_btn(0); alutech_set_btn(0); nice_flors_set_btn(0); + somfy_telis_set_btn(0); uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); furi_hal_subghz_set_rolling_counter_mult(0); // Calling restore! @@ -138,6 +140,7 @@ void subghz_scene_transmitter_on_exit(void* context) { keeloq_reset_original_btn(); alutech_reset_original_btn(); nice_flors_reset_original_btn(); + somfy_telis_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 5a64f27e23..e6ed16d814 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -7,6 +7,7 @@ #include #include #include +#include struct SubGhzViewTransmitter { View* view; @@ -161,6 +162,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { keeloq_set_btn(1); alutech_set_btn(1); nice_flors_set_btn(1); + somfy_telis_set_btn(1); with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, @@ -176,6 +178,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_printf( model->temp_button_id, "%01X", nice_flors_get_original_btn()); model->draw_temp_button = true; + } else if(somfy_telis_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", somfy_telis_get_original_btn()); + model->draw_temp_button = true; } }, true); @@ -192,6 +198,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { keeloq_set_btn(2); alutech_set_btn(2); nice_flors_set_btn(2); + somfy_telis_set_btn(2); with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, @@ -207,6 +214,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_printf( model->temp_button_id, "%01X", nice_flors_get_original_btn()); model->draw_temp_button = true; + } else if(somfy_telis_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", somfy_telis_get_original_btn()); + model->draw_temp_button = true; } }, true); @@ -223,6 +234,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { keeloq_set_btn(3); alutech_set_btn(3); nice_flors_set_btn(3); + somfy_telis_set_btn(3); with_view_model( subghz_transmitter->view, SubGhzViewTransmitterModel * model, @@ -238,6 +250,10 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_printf( model->temp_button_id, "%01X", nice_flors_get_original_btn()); model->draw_temp_button = true; + } else if(somfy_telis_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", somfy_telis_get_original_btn()); + model->draw_temp_button = true; } }, true); diff --git a/applications/main/unirfremix/unirfremix_app.c b/applications/main/unirfremix/unirfremix_app.c index 4f8d5fa01d..597870f940 100644 --- a/applications/main/unirfremix/unirfremix_app.c +++ b/applications/main/unirfremix/unirfremix_app.c @@ -21,6 +21,7 @@ #include #include #include +#include #define UNIRFMAP_FOLDER "/ext/unirf" #define UNIRFMAP_EXTENSION ".txt" @@ -486,6 +487,7 @@ void unirfremix_tx_stop(UniRFRemix* app) { keeloq_reset_original_btn(); alutech_reset_original_btn(); nice_flors_reset_original_btn(); + somfy_telis_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 08c95fe1f0..17df79bee3 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2463,6 +2463,10 @@ Function,-,siprintf,int,"char*, const char*, ..." Function,-,siscanf,int,"const char*, const char*, ..." Function,-,sniprintf,int,"char*, size_t, const char*, ..." Function,+,snprintf,int,"char*, size_t, const char*, ..." +Function,-,somfy_telis_get_custom_btn,uint8_t, +Function,-,somfy_telis_get_original_btn,uint8_t, +Function,-,somfy_telis_reset_original_btn,void, +Function,-,somfy_telis_set_btn,void,uint8_t Function,-,sprintf,int,"char*, const char*, ..." Function,-,sqrt,double,double Function,-,sqrtf,float,float diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 143171a054..5d6b1c6f3c 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -73,6 +73,25 @@ const SubGhzProtocol subghz_protocol_somfy_telis = { .encoder = &subghz_protocol_somfy_telis_encoder, }; +static uint8_t st_btn_temp_id; +static uint8_t st_btn_temp_id_original; + +void somfy_telis_set_btn(uint8_t b) { + st_btn_temp_id = b; +} + +uint8_t somfy_telis_get_original_btn() { + return st_btn_temp_id_original; +} + +uint8_t somfy_telis_get_custom_btn() { + return st_btn_temp_id; +} + +void somfy_telis_reset_original_btn() { + st_btn_temp_id_original = 0; +} + void* subghz_protocol_encoder_somfy_telis_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolEncoderSomfyTelis* instance = malloc(sizeof(SubGhzProtocolEncoderSomfyTelis)); @@ -95,13 +114,86 @@ void subghz_protocol_encoder_somfy_telis_free(void* context) { free(instance); } -static bool - subghz_protocol_somfy_telis_gen_data(SubGhzProtocolEncoderSomfyTelis* instance, uint8_t btn) { - UNUSED(btn); +static bool subghz_protocol_somfy_telis_gen_data( + SubGhzProtocolEncoderSomfyTelis* instance, + uint8_t btn, + bool new_remote) { + // If we doing a clone we will use its data uint64_t data = instance->generic.data ^ (instance->generic.data >> 8); - instance->generic.btn = (data >> 44) & 0xF; // ctrl - instance->generic.cnt = (data >> 24) & 0xFFFF; // rolling code - instance->generic.serial = data & 0xFFFFFF; // address + if(!new_remote) { + instance->generic.btn = (data >> 44) & 0xF; // ctrl + btn = instance->generic.btn; + instance->generic.cnt = (data >> 24) & 0xFFFF; // rolling code + instance->generic.serial = data & 0xFFFFFF; // address + } + + // Save original button for later use + if(st_btn_temp_id_original == 0) { + st_btn_temp_id_original = btn; + } + + // Set custom button + if(st_btn_temp_id == 1) { + switch(st_btn_temp_id_original) { + case 0x1: + btn = 0x2; + break; + case 0x2: + btn = 0x1; + break; + case 0x4: + btn = 0x1; + break; + case 0x8: + btn = 0x1; + break; + + default: + break; + } + } + if(st_btn_temp_id == 2) { + switch(st_btn_temp_id_original) { + case 0x1: + btn = 0x4; + break; + case 0x2: + btn = 0x4; + break; + case 0x4: + btn = 0x2; + break; + case 0x8: + btn = 0x4; + break; + + default: + break; + } + } + if(st_btn_temp_id == 3) { + switch(st_btn_temp_id_original) { + case 0x1: + btn = 0x8; + break; + case 0x2: + btn = 0x8; + break; + case 0x4: + btn = 0x8; + break; + case 0x8: + btn = 0x2; + break; + + default: + break; + } + } + + if((st_btn_temp_id == 0) && (st_btn_temp_id_original != 0)) { + btn = st_btn_temp_id_original; + } if(instance->generic.cnt < 0xFFFF) { if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { @@ -114,8 +206,12 @@ static bool } uint8_t frame[7]; - frame[0] = data >> 48; - frame[1] = instance->generic.btn << 4; + if(!new_remote) { + frame[0] = data >> 48; + } else { + frame[0] = 0xA7; + } + frame[1] = btn << 4; frame[2] = instance->generic.cnt >> 8; frame[3] = instance->generic.cnt; frame[4] = instance->generic.serial >> 16; @@ -154,7 +250,7 @@ bool subghz_protocol_somfy_telis_create_data( instance->generic.serial = serial; instance->generic.cnt = cnt; instance->generic.data_count_bit = 56; - bool res = subghz_protocol_somfy_telis_gen_data(instance, btn); + bool res = subghz_protocol_somfy_telis_gen_data(instance, btn, true); if(res) { res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } @@ -172,7 +268,7 @@ static bool subghz_protocol_encoder_somfy_telis_get_upload( furi_assert(instance); //gen new key - if(subghz_protocol_somfy_telis_gen_data(instance, btn)) { + if(subghz_protocol_somfy_telis_gen_data(instance, btn, false)) { //ToDo if you need to add a callback to automatically update the data on the display } else { return false; @@ -583,6 +679,11 @@ static void subghz_protocol_somfy_telis_check_remote_controller(SubGhzBlockGener instance->btn = (data >> 44) & 0xF; // ctrl instance->cnt = (data >> 24) & 0xFFFF; // rolling code instance->serial = data & 0xFFFFFF; // address + + // Save original button for later use + if(st_btn_temp_id_original == 0) { + st_btn_temp_id_original = instance->btn; + } } /** diff --git a/lib/subghz/protocols/somfy_telis.h b/lib/subghz/protocols/somfy_telis.h index b5e989866d..bca58b64b9 100644 --- a/lib/subghz/protocols/somfy_telis.h +++ b/lib/subghz/protocols/somfy_telis.h @@ -11,6 +11,14 @@ extern const SubGhzProtocolDecoder subghz_protocol_somfy_telis_decoder; extern const SubGhzProtocolEncoder subghz_protocol_somfy_telis_encoder; extern const SubGhzProtocol subghz_protocol_somfy_telis; +// Custom buttons +void somfy_telis_set_btn(uint8_t b); + +uint8_t somfy_telis_get_original_btn(); +uint8_t somfy_telis_get_custom_btn(); + +void somfy_telis_reset_original_btn(); + /** * Allocate SubGhzProtocolEncoderSomfyTelis. * @param environment Pointer to a SubGhzEnvironment instance From 21c52df09060a5a272ceace2978e2ce36f08e417 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 00:10:16 +0300 Subject: [PATCH 22/35] bft programming mode & run fbt format --- .../plugins/mousejacker/mousejacker_ducky.c | 46 +++++++++---------- lib/subghz/protocols/keeloq.c | 25 ++++++++-- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index f9ded2d034..04b0bfaca6 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -97,7 +97,8 @@ static uint32_t mj_ducky_get_command_len(const char* line) { static bool mj_get_ducky_key(char* key, size_t keylen, MJDuckyKey* dk) { //FURI_LOG_D(TAG, "looking up key %s with length %d", key, keylen); for(uint i = 0; i < sizeof(mj_ducky_keys) / sizeof(MJDuckyKey); i++) { - if(strlen(mj_ducky_keys[i].name) == keylen && !strncmp(mj_ducky_keys[i].name, key, keylen)) { + if(strlen(mj_ducky_keys[i].name) == keylen && + !strncmp(mj_ducky_keys[i].name, key, keylen)) { memcpy(dk, &mj_ducky_keys[i], sizeof(MJDuckyKey)); return true; } @@ -165,26 +166,23 @@ static void release_key( uint8_t* addr, uint8_t addr_size, uint8_t rate, - PluginState* plugin_state -) { + PluginState* plugin_state) { // This function release keys currently pressed, but keep pressing special keys // if holding mod keys variable are set to true uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0}; build_hid_packet( - 0 | holding_ctrl - | holding_shift << 1 - | holding_alt << 2 - | holding_gui << 3, - 0, hid_payload); + 0 | holding_ctrl | holding_shift << 1 | holding_alt << 2 | holding_gui << 3, + 0, + hid_payload); inject_packet( - handle, - addr, - addr_size, - rate, - hid_payload, - LOGITECH_HID_TEMPLATE_SIZE, - plugin_state); // empty hid packet + handle, + addr, + addr_size, + rate, + hid_payload, + LOGITECH_HID_TEMPLATE_SIZE, + plugin_state); // empty hid packet } static void send_hid_packet( @@ -196,15 +194,13 @@ static void send_hid_packet( uint8_t hid, PluginState* plugin_state) { uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0}; - if(hid == prev_hid ) - release_key(handle, addr, addr_size, rate, plugin_state); + if(hid == prev_hid) release_key(handle, addr, addr_size, rate, plugin_state); prev_hid = hid; - build_hid_packet(mod - | holding_ctrl - | holding_shift << 1 - | holding_alt << 2 - | holding_gui << 3, hid, hid_payload); + build_hid_packet( + mod | holding_ctrl | holding_shift << 1 | holding_alt << 2 | holding_gui << 3, + hid, + hid_payload); inject_packet( handle, addr, addr_size, rate, hid_payload, LOGITECH_HID_TEMPLATE_SIZE, plugin_state); furi_delay_ms(12); @@ -288,7 +284,7 @@ static bool mj_process_ducky_line( return true; } else if(strncmp(line_tmp, ducky_cmd_altstring, strlen(ducky_cmd_altstring)) == 0) { - // ALTSTRING + // ALTSTRING line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; for(size_t i = 0; i < strlen(line_tmp); i++) { if((line_tmp[i] < ' ') || (line_tmp[i] > '~')) { @@ -298,7 +294,7 @@ static bool mj_process_ducky_line( char alt_code[4]; // Getting altcode of the char snprintf(alt_code, 4, "%u", line_tmp[i]); - + uint8_t j = 0; while(!ducky_end_line(alt_code[j])) { char pad_num[5] = {'N', 'U', 'M', ' ', alt_code[j]}; @@ -425,7 +421,7 @@ static bool mj_process_ducky_line( if(!mj_get_ducky_key("TAB", 3, &dk)) return false; send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); return true; - } + } return false; } diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index efab023bc1..839972dca3 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -339,6 +339,11 @@ static bool btn_temp_id_original = btn; } + uint8_t klq_last_custom_btn = 0xA; + if(strcmp(instance->manufacture_name, "BFT") == 0) { + klq_last_custom_btn = 0xF; + } + // Set custom button if(btn_temp_id == 1) { switch(btn_temp_id_original) { @@ -357,6 +362,9 @@ static bool case 0x8: btn = 0x1; break; + case 0xF: + btn = 0x1; + break; default: break; @@ -374,11 +382,14 @@ static bool btn = 0x4; break; case 0x4: - btn = 0xA; + btn = klq_last_custom_btn; break; case 0x8: btn = 0x4; break; + case 0xF: + btn = 0x4; + break; default: break; @@ -401,6 +412,9 @@ static bool case 0x8: btn = 0x2; break; + case 0xF: + btn = 0x8; + break; default: break; @@ -409,10 +423,10 @@ static bool if(btn_temp_id == 4) { switch(btn_temp_id_original) { case 0x1: - btn = 0xA; + btn = klq_last_custom_btn; break; case 0x2: - btn = 0xA; + btn = klq_last_custom_btn; break; case 0xA: btn = 0x2; @@ -421,7 +435,10 @@ static bool btn = 0x2; break; case 0x8: - btn = 0xA; + btn = klq_last_custom_btn; + break; + case 0xF: + btn = 0x2; break; default: From 9c9688dd5b245172fdb25fd93804b4b0515407cc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 00:41:14 +0300 Subject: [PATCH 23/35] Nice One manual adding support --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../subghz/scenes/subghz_scene_set_type.c | 34 ++++++++++++++++++- firmware/targets/f7/api_symbols.csv | 2 +- lib/subghz/blocks/generic.c | 10 ++++++ lib/subghz/protocols/nice_flor_s.c | 22 ++++++++++-- lib/subghz/protocols/nice_flor_s.h | 4 ++- 6 files changed, 68 insertions(+), 5 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 9ac4552f51..e55ae32deb 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -13,6 +13,7 @@ typedef enum { SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, SubmenuIndexNiceFlorS_433_92, + SubmenuIndexNiceOne_433_92, SubmenuIndexNiceSmilo_433_92, SubmenuIndexCAME12bit, SubmenuIndexCAME24bit, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 95cb1ec03e..e209a80eae 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -115,6 +115,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexNiceFlorS_433_92, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Nice One 433MHz", + SubmenuIndexNiceOne_433_92, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "CAME 12bit 433MHz", @@ -367,7 +373,33 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { key & 0x0FFFFFFF, 0x1, 0x0003, - subghz->txrx->preset); + subghz->txrx->preset, + false); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; + case SubmenuIndexNiceOne_433_92: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); + subghz_preset_init( + subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_nice_flor_s_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key & 0x0FFFFFFF, + 0x1, + 0x0003, + subghz->txrx->preset, + true); generated_protocol = true; } else { generated_protocol = false; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 17df79bee3..8e3d0dd319 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -3197,7 +3197,7 @@ Function,-,subghz_protocol_encoder_star_line_yield,LevelDuration,void* Function,-,subghz_protocol_faac_slh_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, uint32_t, const char*, SubGhzRadioPreset*" Function,-,subghz_protocol_keeloq_bft_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, uint32_t, const char*, SubGhzRadioPreset*" Function,-,subghz_protocol_keeloq_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*" -Function,-,subghz_protocol_nice_flor_s_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" +Function,-,subghz_protocol_nice_flor_s_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*, _Bool" Function,-,subghz_protocol_nice_flor_s_encrypt,uint64_t,"uint64_t, const char*" Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhzProtocolEncoderRAW*, SubGhzProtocolEncoderRAWCallbackEnd, void*" Function,+,subghz_protocol_raw_gen_fff_data,void,"FlipperFormat*, const char*" diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index 3d59adc82c..54a401e050 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -78,6 +78,16 @@ bool subghz_block_generic_serialize( FURI_LOG_E(TAG, "Unable to add Key"); break; } + + // Nice One - Manual adding support + if(instance->data_count_bit == 72 && + (strcmp(instance->protocol_name, "Nice FloR-S") == 0)) { + uint32_t temp = (instance->data_2 >> 4) & 0xFFFFF; + if(!flipper_format_write_uint32(flipper_format, "Data", &temp, 1)) { + FURI_LOG_E(TAG, "Unable to add Data"); + break; + } + } res = true; } while(false); furi_string_free(temp_str); diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index f58c6084ff..135bd49728 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -543,18 +543,36 @@ bool subghz_protocol_nice_flor_s_create_data( uint32_t serial, uint8_t btn, uint16_t cnt, - SubGhzRadioPreset* preset) { + SubGhzRadioPreset* preset, + bool nice_one) { furi_assert(context); SubGhzProtocolEncoderNiceFlorS* instance = context; instance->generic.serial = serial; instance->generic.cnt = cnt; - instance->generic.data_count_bit = 52; + if(nice_one) { + instance->generic.data_count_bit = NICE_ONE_COUNT_BIT; + } else { + instance->generic.data_count_bit = 52; + } uint64_t decrypt = ((uint64_t)instance->generic.serial << 16) | instance->generic.cnt; uint64_t enc_part = subghz_protocol_nice_flor_s_encrypt( decrypt, instance->nice_flor_s_rainbow_table_file_name); uint8_t byte = btn << 4 | (0xF ^ btn ^ 0x3); instance->generic.data = (uint64_t)byte << 44 | enc_part; + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { + uint8_t add_data[10] = {0}; + for(size_t i = 0; i < 7; i++) { + add_data[i] = (instance->generic.data >> (48 - i * 8)) & 0xFF; + } + subghz_protocol_nice_one_get_data(add_data, 0, 0); + instance->generic.data_2 = 0; + for(size_t j = 7; j < 10; j++) { + instance->generic.data_2 <<= 8; + instance->generic.data_2 += add_data[j]; + } + } + bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); return res; diff --git a/lib/subghz/protocols/nice_flor_s.h b/lib/subghz/protocols/nice_flor_s.h index 52f0ca7458..3b22db304b 100644 --- a/lib/subghz/protocols/nice_flor_s.h +++ b/lib/subghz/protocols/nice_flor_s.h @@ -63,6 +63,7 @@ uint64_t subghz_protocol_nice_flor_s_encrypt(uint64_t data, const char* file_nam * @param btn Button number, 4 bit * @param cnt Counter value, 16 bit * @param preset Modulation, SubGhzRadioPreset + * @param nice_one Nice One if true, Nice Flor S if false * @return true On success */ bool subghz_protocol_nice_flor_s_create_data( @@ -71,7 +72,8 @@ bool subghz_protocol_nice_flor_s_create_data( uint32_t serial, uint8_t btn, uint16_t cnt, - SubGhzRadioPreset* preset); + SubGhzRadioPreset* preset, + bool nice_one); /** * Allocate SubGhzProtocolDecoderNiceFlorS. From cbb09b681279d4a316d261ff277794799dd53fce Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 06:02:22 +0300 Subject: [PATCH 24/35] BFT Programming mode and Add manually --- .../main/subghz/helpers/subghz_custom_event.h | 3 +- .../subghz/scenes/subghz_scene_set_type.c | 46 +++++- lib/subghz/protocols/keeloq.c | 146 +++++++++++------- 3 files changed, 136 insertions(+), 59 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index e55ae32deb..32b5fb3290 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -8,7 +8,8 @@ typedef enum { //SubmenuIndex SubmenuIndexFaacSLH_433, SubmenuIndexFaacSLH_868, - SubmenuIndexBFT, + SubmenuIndexBFTClone, + SubmenuIndexBFTMitto, SubmenuIndexPricenton, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index e209a80eae..41c22af20a 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -79,10 +79,16 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexFaacSLH_433, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "BFT [Manual] 433MHz", + SubmenuIndexBFTClone, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "BFT Mitto 433MHz", - SubmenuIndexBFT, + SubmenuIndexBFTMitto, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( @@ -236,7 +242,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case SubmenuIndexFaacSLH_433: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac); break; - case SubmenuIndexBFT: + case SubmenuIndexBFTClone: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft); break; case SubmenuIndexPricenton: @@ -312,6 +318,42 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { generated_protocol = true; } break; + case SubmenuIndexBFTMitto: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_keeloq_bft_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key & 0x000FFFFF, + 0x2, + 0x0002, + key & 0x000FFFFF, + "BFT", + subghz->txrx->preset); + + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = ((key & 0x000FFFFF) >> i * 8) & 0xFF; + } + + flipper_format_write_hex( + subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + + flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT"); + + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexDoorHan_433_92: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 839972dca3..add35c8270 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -88,6 +88,8 @@ static const char* mfname; static uint8_t kl_type; static uint8_t btn_temp_id; static uint8_t btn_temp_id_original; +static bool bft_prog_mode; +static uint16_t temp_counter; void keeloq_set_btn(uint8_t b) { btn_temp_id = b; @@ -158,22 +160,7 @@ static bool subghz_protocol_keeloq_gen_data( SubGhzProtocolEncoderKeeloq* instance, uint8_t btn, bool counter_up) { - if(counter_up) { - if(instance->generic.cnt < 0xFFFF) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); - } - } else if(instance->generic.cnt >= 0xFFFF) { - instance->generic.cnt = 0; - } - } uint32_t fix = (uint32_t)btn << 28 | instance->generic.serial; - uint32_t decrypt = (uint32_t)btn << 28 | - (instance->generic.serial & 0x3FF) - << 16 | //ToDo in some protocols the discriminator is 0 - instance->generic.cnt; uint32_t hop = 0; uint64_t man = 0; uint64_t code_found_reverse; @@ -182,36 +169,63 @@ static bool subghz_protocol_keeloq_gen_data( instance->manufacture_name = ""; } - // DTM Neo uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode -> 12bit normal learning - if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) || - (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || - (strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0)) { - decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt; + // BFT programming mode on / off conditions + if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn == 0xF)) { + bft_prog_mode = true; } - - // Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning - if((strcmp(instance->manufacture_name, "NICE_Smilo") == 0) || - (strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) || - (strcmp(instance->manufacture_name, "JCM_Tech") == 0) || - (strcmp(instance->manufacture_name, "Normstahl") == 0)) { - decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt; + if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && bft_prog_mode) { + bft_prog_mode = false; } - - // Beninca -> 4bit serial - simple XOR - if(strcmp(instance->manufacture_name, "Beninca") == 0) { - decrypt = btn << 28 | (instance->generic.serial & 0xF) << 16 | instance->generic.cnt; + // If we using BFT programming mode we will trasmit its seed in hop part like original remote + if(bft_prog_mode) { + hop = instance->generic.seed; + } + if(counter_up && !bft_prog_mode) { + if(instance->generic.cnt < 0xFFFF) { + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } } + if(!bft_prog_mode) { + uint32_t decrypt = (uint32_t)btn << 28 | + (instance->generic.serial & 0x3FF) + << 16 | //ToDo in some protocols the discriminator is 0 + instance->generic.cnt; + // DTM Neo uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode -> 12bit normal learning + if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) || + (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || + (strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0)) { + decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt; + } - if(strcmp(instance->manufacture_name, "Unknown") == 0) { - code_found_reverse = subghz_protocol_blocks_reverse_key( - instance->generic.data, instance->generic.data_count_bit); - hop = code_found_reverse & 0x00000000ffffffff; - } else if(strcmp(instance->manufacture_name, "AN-Motors") == 0) { - hop = (instance->generic.cnt & 0xFF) << 24 | (instance->generic.cnt & 0xFF) << 16 | - (btn & 0xF) << 12 | 0x404; - } else if(strcmp(instance->manufacture_name, "HCS101") == 0) { - hop = instance->generic.cnt << 16 | (btn & 0xF) << 12 | 0x000; - } else { + // Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning + if((strcmp(instance->manufacture_name, "NICE_Smilo") == 0) || + (strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) || + (strcmp(instance->manufacture_name, "JCM_Tech") == 0) || + (strcmp(instance->manufacture_name, "Normstahl") == 0)) { + decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt; + } + + // Beninca -> 4bit serial - simple XOR + if(strcmp(instance->manufacture_name, "Beninca") == 0) { + decrypt = btn << 28 | (instance->generic.serial & 0xF) << 16 | instance->generic.cnt; + } + + if(strcmp(instance->manufacture_name, "Unknown") == 0) { + code_found_reverse = subghz_protocol_blocks_reverse_key( + instance->generic.data, instance->generic.data_count_bit); + hop = code_found_reverse & 0x00000000ffffffff; + } else if(strcmp(instance->manufacture_name, "AN-Motors") == 0) { + hop = (instance->generic.cnt & 0xFF) << 24 | (instance->generic.cnt & 0xFF) << 16 | + (btn & 0xF) << 12 | 0x404; + } else if(strcmp(instance->manufacture_name, "HCS101") == 0) { + hop = instance->generic.cnt << 16 | (btn & 0xF) << 12 | 0x000; + } else { for M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { res = strcmp(furi_string_get_cstr(manufacture_code->name), instance->manufacture_name); @@ -270,6 +284,7 @@ static bool subghz_protocol_keeloq_gen_data( break; } } + } } if(hop) { uint64_t yek = (uint64_t)fix << 32 | hop; @@ -339,6 +354,12 @@ static bool btn_temp_id_original = btn; } + if(instance->manufacture_name == 0x0) { + instance->manufacture_name = ""; + } + if(bft_prog_mode) { + instance->manufacture_name = "BFT"; + } uint8_t klq_last_custom_btn = 0xA; if(strcmp(instance->manufacture_name, "BFT") == 0) { klq_last_custom_btn = 0xF; @@ -450,9 +471,10 @@ static bool btn = btn_temp_id_original; } - //gen new key + // Generate new key + if(subghz_protocol_keeloq_gen_data(instance, btn, true)) { - //ToDo if you need to add a callback to automatically update the data on the display + // OK } else { return false; } @@ -607,6 +629,8 @@ void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->keystore = subghz_environment_get_keystore(environment); instance->manufacture_from_file = furi_string_alloc(); + bft_prog_mode = false; + return instance; } @@ -723,7 +747,7 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur /** * Validation of decrypt data. * @param instance Pointer to a SubGhzBlockGeneric instance - * @param decrypt Decrypd data + * @param decrypt Decrypted data * @param btn Button number, 4 bit * @param end_serial decrement the last 10 bits of the serial number * @return true On success @@ -1105,19 +1129,29 @@ static void subghz_protocol_keeloq_check_remote_controller( uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); uint32_t key_fix = key >> 32; uint32_t key_hop = key & 0x00000000ffffffff; - // Check key AN-Motors - if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && - (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { - *manufacture_name = "AN-Motors"; - mfname = *manufacture_name; - instance->cnt = key_hop >> 16; - } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { - *manufacture_name = "HCS101"; - mfname = *manufacture_name; - instance->cnt = key_hop >> 16; + + // If we are in BFT programming mode we will set previous remembered counter and skip mf keys check + if(!bft_prog_mode) { + // Check key AN-Motors + if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && + (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { + *manufacture_name = "AN-Motors"; + mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { + *manufacture_name = "HCS101"; + mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } else { + subghz_protocol_keeloq_check_remote_controller_selector( + instance, key_fix, key_hop, keystore, manufacture_name); + } + temp_counter = instance->cnt; + } else { - subghz_protocol_keeloq_check_remote_controller_selector( - instance, key_fix, key_hop, keystore, manufacture_name); + *manufacture_name = "BFT"; + mfname = *manufacture_name; + instance->cnt = temp_counter; } instance->serial = key_fix & 0x0FFFFFFF; From 6bd5e228726044d542ccaed0c2ee2657acb82471 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 06:15:55 +0300 Subject: [PATCH 25/35] Somfy Telis - add manually --- .../main/subghz/helpers/subghz_custom_event.h | 1 + .../subghz/scenes/subghz_scene_set_type.c | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 32b5fb3290..4475045eeb 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -10,6 +10,7 @@ typedef enum { SubmenuIndexFaacSLH_868, SubmenuIndexBFTClone, SubmenuIndexBFTMitto, + SubmenuIndexSomfyTelis, SubmenuIndexPricenton, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 41c22af20a..5c5d5db3bd 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -91,6 +91,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexBFTMitto, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Somfy Telis 433MHz", + SubmenuIndexSomfyTelis, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "Princeton 433MHz", @@ -354,6 +360,30 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } break; + case SubmenuIndexSomfyTelis: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); + subghz_preset_init( + subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_somfy_telis_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key & 0x00FFFFFF, + 0x2, + 0x0003, + subghz->txrx->preset); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexDoorHan_433_92: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); From 24726ab8a319f0854696fb6cb4ee2b75155c36f7 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 06:19:21 +0300 Subject: [PATCH 26/35] More precise debug counter ++ --- .../scenes/subghz_scene_ext_module_settings.c | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c index 8d1154a137..df81eae290 100644 --- a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c @@ -17,9 +17,12 @@ const char* const debug_pin_text[DEBUG_P_COUNT] = { "17(1W)", }; -#define DEBUG_COUNTER_COUNT 3 +#define DEBUG_COUNTER_COUNT 6 const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = { "+1", + "+2", + "+3", + "+4", "+5", "+10", }; @@ -55,9 +58,18 @@ static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) { furi_hal_subghz_set_rolling_counter_mult(1); break; case 1: - furi_hal_subghz_set_rolling_counter_mult(5); + furi_hal_subghz_set_rolling_counter_mult(2); break; case 2: + furi_hal_subghz_set_rolling_counter_mult(3); + break; + case 3: + furi_hal_subghz_set_rolling_counter_mult(4); + break; + case 4: + furi_hal_subghz_set_rolling_counter_mult(5); + break; + case 5: furi_hal_subghz_set_rolling_counter_mult(10); break; default: @@ -101,12 +113,21 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { case 1: value_index_cnt = 0; break; - case 5: + case 2: value_index_cnt = 1; break; - case 10: + case 3: value_index_cnt = 2; break; + case 4: + value_index_cnt = 3; + break; + case 5: + value_index_cnt = 4; + break; + case 10: + value_index_cnt = 5; + break; default: break; } From 9f6f391354585958cb73b077b4b78938716ce131 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 06:56:54 +0300 Subject: [PATCH 27/35] Update changelog and docs --- CHANGELOG.md | 6 ++++ ReadMe.md | 15 ++++---- documentation/SubGHzRemoteProg.md | 60 +++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 documentation/SubGHzRemoteProg.md diff --git a/CHANGELOG.md b/CHANGELOG.md index a50bfb1cf3..3140f742b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ ### New changes * SubGHz: **Custom buttons for Nice Flor S / Somfy Telis (+Programming mode)** - now you can use arrow buttons to send signal with different button code * SubGHz: Somfy Telis -> Add manually (create new remote, now with programming button (Prog / 0x8) you can write it into receiver) +* SubGHz: BFT Mitto -> Add manually (create new remote, now with programming button (0xF) you can write it into receiver) +* SubGHz: Nice One -> Add manually (programming is possible using regular button) +* SubGHz: More precise settings for debug counter increase value +* Plugins -> MouseJacker: Features, Fixes and improvements (by @MatthisC | PR #366) +* OFW: BadUSB UI fixes +* OFW: Plugins: move to designated categories -> **We moved some plugins to new categories too** * OFW: Drivers: remove excessive check in bq25896 and make PVS happy * OFW: FuriHal, Power, UnitTests: fix, rename battery charging voltage limit API -> **Breaking API change, api was changed from 14.x to 15.x** **(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)** diff --git a/ReadMe.md b/ReadMe.md index 2e9b0327eb..9265fb6265 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -167,7 +167,7 @@ Games: - Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107) * SubGHz -> **Hold right in received signal list to delete selected signal** * SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis** - now you can use arrow buttons to send signal with different button code -* SubGHz -> BFT Mitto / Somfy Telis manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis) +* SubGHz -> BFT Mitto / Somfy Telis / Nice Flor S manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis) * SubGHz -> Debug mode counter increase settings (+5, +10, default: +1) * SubGHz -> Debug PIN output settings for protocol development * Infrared -> Debug TX PIN output settings @@ -183,6 +183,13 @@ Games: ## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md) +### **Sub-GHz** + +## [- Transmission is blocked? - How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md) + +## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md) + +## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md) ### **Plugins** ## [- 🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/unleashed-extra-pack) @@ -223,12 +230,6 @@ Games: ## [- How to use: [GPIO] SentrySafe plugin](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md) -### **Sub-GHz** - -## [- Transmission is blocked? - How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md) - -## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md) -

diff --git a/documentation/SubGHzRemoteProg.md b/documentation/SubGHzRemoteProg.md new file mode 100644 index 0000000000..5f453806ea --- /dev/null +++ b/documentation/SubGHzRemoteProg.md @@ -0,0 +1,60 @@ +# How to use Flipper as a new SubGHz remote (not clone of original remote) + +## Somfy Telis + +1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> Somfy Telis 433Mhz +2. Open your new remote file +3. Long press (hold) the ‘Prog’ button on a remote that is already registered to the device, until the blinds move shortly up and down. +4. Press and hold the ‘Prog’ button on the flipper (Left Arrow), until the blinds move shortly up and down again. +5. Done? + +## BFT Mitto + +1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> BFT Mitto 433Mhz +2. Open your new remote file +3. You need to be in minimum 3 meters to receiver +4. Original Remote: Press hidden button on back of remote with a pin or paper clip OR press Button 1 & 2 together until remote LED lights. +5. Original Remote: Momentarily press button that opens device +6. Long press (Right Arrow) - (0xF button - Btn:F) on Flipper for like 3-5 sec +7. Done? + +## Nice Flor S + +- Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> Nice FloR-S 433Mhz +- Open your new remote file + +### Coding using an existing remote +To enter the code of a new remote control without using your receiver, you will need +an authorised remote control (note: the first remote control must always be entered +using the receiver key). Now, with the two remote controls (your already coded +remote, and your new remote), which we shall call NEW (the one whose code we want +to enter) and OLD (the authorised one), position yourself within 3m of the gate/garage +receiver and then: +1. Press and hold the `Send` button on the flipper for at least 5 seconds and then +release. +2. Press the button on the already programmed remote 3 times slowly. +3. Press the `Send` button on the flipper slowly and then release. + +### Coding directly to your receiver +Your new remote will program to your receiver as per your original remote +instructions, so please refer to your manual. But for a typical NICE FLOX2R Receiver, +the programming procedure is as follows: +1. Press the learning button on your receiver for 1-2 seconds. The LED will turn on +for 5 seconds. Within 5 seconds, complete the next step. +2. Press a `Send` button on your flipper until the LED on your receiver turns off. +3. Release the remote button and wait for 2 seconds. +4. Press the `Send` button on your flipper again. The LED on your receiver +will now flash 3 times. This indicates that your remote has been successfully +coded. If this does not happen, repeat the whole procedure from the +beginning, and try again. +5. Wait 5 seconds. Press the button on your new remote to test if it opens your +garage/gate. + + +#### Follow links below to find more detailed instructions!!! + +#### Materials used: +- [Somfy Telis](https://pushstack.wordpress.com/somfy-rts-protocol/) +- [BFT Mitto](https://www.retroremotes.com.au/wp-content/uploads/2017/03/BFT-MITTO-2-4-19-6-17.pdf) +- [NICE FLOX2R Receiver Programming](https://apollogateopeners.com/store/pdf/apollo-flor-s-receiver-programming-guide.pdf) +- [Nice Flor S Programming](https://motepro.com.au/Instructions/Nice.pdf) \ No newline at end of file From 75a8f0a7b4c088fdb1a77dbed16aef5102216bbb Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 07:05:55 +0300 Subject: [PATCH 28/35] Update changelog --- CHANGELOG.md | 1 + ReadMe.md | 5 +++-- applications/plugins/hc_sr04/hc_sr04.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3140f742b8..072070ad2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * SubGHz: Nice One -> Add manually (programming is possible using regular button) * SubGHz: More precise settings for debug counter increase value * Plugins -> MouseJacker: Features, Fixes and improvements (by @MatthisC | PR #366) +* Plugins -> HC-SR04: Improve accuracy by measuring microseconds (by @clashlab | PR #367) * OFW: BadUSB UI fixes * OFW: Plugins: move to designated categories -> **We moved some plugins to new categories too** * OFW: Drivers: remove excessive check in bq25896 and make PVS happy diff --git a/ReadMe.md b/ReadMe.md index 9265fb6265..5563bc390c 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -190,12 +190,13 @@ Games: ## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md) ## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md) + +## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) + ### **Plugins** ## [- 🎲 Download Extra plugins for Unleashed](https://github.com/xMasterX/unleashed-extra-pack) -## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) - ## [- TOTP (Authenticator) config description](https://github.com/akopachov/flipper-zero_authenticator/blob/master/docs/conf-file_description.md) ## [- Barcode Generator](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md) diff --git a/applications/plugins/hc_sr04/hc_sr04.c b/applications/plugins/hc_sr04/hc_sr04.c index 3cb9e72d6d..db075247a6 100644 --- a/applications/plugins/hc_sr04/hc_sr04.c +++ b/applications/plugins/hc_sr04/hc_sr04.c @@ -165,7 +165,8 @@ static void hc_sr04_measure(PluginState* const plugin_state) { //FURI_CRITICAL_EXIT(); - plugin_state->echo = (pulse_end - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); + plugin_state->echo = + (pulse_end - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); plugin_state->distance = hc_sr04_us_to_m(plugin_state->echo); plugin_state->measurement_made = true; From c3a6ba3c02a8e389ebb236fb90ffbb5274745428 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 07:09:13 +0300 Subject: [PATCH 29/35] Small fixes --- lib/subghz/protocols/keeloq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index add35c8270..a58a95ed64 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -105,6 +105,8 @@ uint8_t keeloq_get_custom_btn() { void keeloq_reset_original_btn() { btn_temp_id_original = 0; + temp_counter = 0; + bft_prog_mode = false; } void keeloq_reset_mfname() { From e0f969775026ff0a4595a4060642a70befc27bcd Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 07:25:28 +0300 Subject: [PATCH 30/35] Add a special message in changelog for novices --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 072070ad2e..3f965db058 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ### New changes +* Remove `apps` folder on your microSD before installing this release to avoid issues! * SubGHz: **Custom buttons for Nice Flor S / Somfy Telis (+Programming mode)** - now you can use arrow buttons to send signal with different button code * SubGHz: Somfy Telis -> Add manually (create new remote, now with programming button (Prog / 0x8) you can write it into receiver) * SubGHz: BFT Mitto -> Add manually (create new remote, now with programming button (0xF) you can write it into receiver) From 8deb29a8ff328205071d92a3792da4d1a77dfdcc Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 28 Feb 2023 21:45:55 +0300 Subject: [PATCH 31/35] Fix #370 and fix other protocol counter --- lib/subghz/protocols/faac_slh.c | 6 +----- lib/subghz/protocols/secplus_v2.c | 7 ++----- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 6918101a9b..4b69ae73d1 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -110,11 +110,7 @@ void subghz_protocol_encoder_faac_slh_free(void* context) { } static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* instance) { - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); - } + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); uint32_t fix = instance->generic.serial << 4 | instance->generic.btn; uint32_t hop = 0; uint32_t decrypt = 0; diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index 593be04947..9f8c316542 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -379,11 +379,8 @@ static void subghz_protocol_secplus_v2_encode(SubGhzProtocolEncoderSecPlus_v2* i uint8_t roll_1[9] = {0}; uint8_t roll_2[9] = {0}; - if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { - instance->generic.cnt = 0; - } else { - instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); - } + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + //ToDo it is not known what value the counter starts if(instance->generic.cnt > 0xFFFFFFF) instance->generic.cnt = 0xE500000; uint32_t rolling = subghz_protocol_blocks_reverse_key(instance->generic.cnt, 28); From cf6dc9f8953c10a4a058d0ac9e33c2dafec625b1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 1 Mar 2023 00:25:11 +0300 Subject: [PATCH 32/35] Fix timings for CAME protocol, Fix #280 --- lib/subghz/protocols/came.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index bed26d7d27..00e2f49f2c 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -117,13 +117,25 @@ static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* i instance->encoder.size_upload = size_upload; } //Send header - instance->encoder.upload[index++] = level_duration_make( - false, - (((instance->generic.data_count_bit == CAME_24_COUNT_BIT) || - (instance->generic.data_count_bit == - subghz_protocol_came_const.min_count_bit_for_found)) ? - (uint32_t)subghz_protocol_came_const.te_short * 76 : - (uint32_t)subghz_protocol_came_const.te_short * 39)); + // CAME 24 Bit = 24320 us + if(instance->generic.data_count_bit == CAME_24_COUNT_BIT) { + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * 76); + } else if( + (instance->generic.data_count_bit == subghz_protocol_came_const.min_count_bit_for_found) || + (instance->generic.data_count_bit == AIRFORCE_COUNT_BIT)) { + // CAME 12 Bit Original only! and Airforce protocol = 15040 us + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * 47); + } else if(instance->generic.data_count_bit == PRASTEL_COUNT_BIT) { + // PRASTEL = 11520 us + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * 36); + } else { + // Some wrong detected protocols, 5120 us + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * 16); + } //Send start bit instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short); From cc52253e22602d707580989541ce6c841f154b41 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Mon, 27 Feb 2023 19:25:56 +0200 Subject: [PATCH 33/35] Exit to the main menu on pressing BACK --- applications/main/nfc/scenes/nfc_scene_read_card_success.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_success.c b/applications/main/nfc/scenes/nfc_scene_read_card_success.c index 9b2a2188e4..ee80ee7688 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_success.c @@ -46,6 +46,9 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(nfc->scene_manager); } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); } return consumed; } From ab6b3f8ed3762b377d9f646551b6c607320442aa Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Mon, 27 Feb 2023 20:30:11 +0300 Subject: [PATCH 34/35] Fix hangups when the user mashes the transmit button --- applications/main/infrared/infrared.c | 21 +++++++++++++-------- applications/main/infrared/infrared_i.h | 1 + 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared.c index 14729e0d81..a88306cc5e 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared.c @@ -3,6 +3,8 @@ #include #include +#define INFRARED_TX_MIN_INTERVAL_MS 50U + static const NotificationSequence* infrared_notification_sequences[] = { &sequence_success, &sequence_set_only_green_255, @@ -308,10 +310,13 @@ bool infrared_rename_current_remote(Infrared* infrared, const char* name) { void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { if(infrared->app_state.is_transmitting) { - FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already active"); return; - } else { - infrared->app_state.is_transmitting = true; + } + + const uint32_t time_elapsed = furi_get_tick() - infrared->app_state.last_transmit_time; + + if(time_elapsed < INFRARED_TX_MIN_INTERVAL_MS) { + return; } if(infrared_signal_is_raw(signal)) { @@ -328,6 +333,8 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { infrared_worker_tx_set_get_signal_callback( infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); infrared_worker_tx_start(infrared->worker); + + infrared->app_state.is_transmitting = true; } void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { @@ -337,26 +344,24 @@ void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { InfraredSignal* signal = infrared_remote_button_get_signal(button); infrared_tx_start_signal(infrared, signal); - infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); } void infrared_tx_start_received(Infrared* infrared) { infrared_tx_start_signal(infrared, infrared->received_signal); - infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); } void infrared_tx_stop(Infrared* infrared) { if(!infrared->app_state.is_transmitting) { - FURI_LOG_D(INFRARED_LOG_TAG, "Transmitter is already stopped"); return; - } else { - infrared->app_state.is_transmitting = false; } infrared_worker_tx_stop(infrared->worker); infrared_worker_tx_set_get_signal_callback(infrared->worker, NULL, NULL); infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStop); + + infrared->app_state.is_transmitting = false; + infrared->app_state.last_transmit_time = furi_get_tick(); } void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) { diff --git a/applications/main/infrared/infrared_i.h b/applications/main/infrared/infrared_i.h index 72800d9947..55b70fc5eb 100644 --- a/applications/main/infrared/infrared_i.h +++ b/applications/main/infrared/infrared_i.h @@ -70,6 +70,7 @@ typedef struct { InfraredEditTarget edit_target : 8; InfraredEditMode edit_mode : 8; int32_t current_button_index; + uint32_t last_transmit_time; } InfraredAppState; struct Infrared { From 1f6382e93debf8f3937114a5d282e1440ae80d51 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 1 Mar 2023 02:57:06 +0300 Subject: [PATCH 35/35] Update changelog and readme --- .drone.yml | 4 ++-- CHANGELOG.md | 8 ++++++-- ReadMe.md | 35 ++++++++++++++++------------------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/.drone.yml b/.drone.yml index 67848b6d77..06881b1ab3 100644 --- a/.drone.yml +++ b/.drone.yml @@ -198,7 +198,7 @@ steps: [-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) - [-Download latest extra apps pack-](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps) + [-Download latest extra apps pack-](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip) [-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/${DRONE_TAG}/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=release-cfw&version=${DRONE_TAG}) @@ -220,7 +220,7 @@ steps: commands: - wget "https://raw.githubusercontent.com/fieu/discord.sh/e1dc1a7595efad2cad8f072f0b3531c470f5b7c8/discord.sh" - chmod +x ./discord.sh - - ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)' + - ./discord.sh --text 'New Unleashed firmware released!\n\nVersion - '${DRONE_TAG}'\n\n[[Github - Changelog]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/'${DRONE_TAG}')\n\n[-How to install firmware-](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)\n\n[-Download latest extra apps pack-](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip)\n\n[-Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw/'${DRONE_TAG}'/flipper-z-f7-update-'${DRONE_TAG}'.tgz&channel=release-cfw&version='${DRONE_TAG}')\n\n[-Version without custom animations - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_no_anim/flipper-z-f7-update-'${DRONE_TAG}'n.tgz&channel=release-cfw&version='${DRONE_TAG}'n)\n\n[-Version with extra apps - Install FW via Web Updater-](https://lab.flipper.net/?url=https://unleashedflip.com/fw_extra_apps/flipper-z-f7-update-'${DRONE_TAG}'e.tgz&channel=release-cfw&version='${DRONE_TAG}'e)' - name: "Send extra pack build to telegram" image: appleboy/drone-telegram diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f965db058..27bf40e1c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ### New changes -* Remove `apps` folder on your microSD before installing this release to avoid issues! +* If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues! +* SubGHz: Fixed timings for static CAME 12 bit and other types (fixed issue #280) +* SubGHz: Fix #370 and fix other protocol counter issues * SubGHz: **Custom buttons for Nice Flor S / Somfy Telis (+Programming mode)** - now you can use arrow buttons to send signal with different button code * SubGHz: Somfy Telis -> Add manually (create new remote, now with programming button (Prog / 0x8) you can write it into receiver) * SubGHz: BFT Mitto -> Add manually (create new remote, now with programming button (0xF) you can write it into receiver) @@ -7,6 +9,8 @@ * SubGHz: More precise settings for debug counter increase value * Plugins -> MouseJacker: Features, Fixes and improvements (by @MatthisC | PR #366) * Plugins -> HC-SR04: Improve accuracy by measuring microseconds (by @clashlab | PR #367) +* OFW PR: 2441 - Infrared: Fix hangups on repeated button press (by gsurkov) +* OFW PR: 2440 - Fix navigation on unsupported card types (by Astrrra) * OFW: BadUSB UI fixes * OFW: Plugins: move to designated categories -> **We moved some plugins to new categories too** * OFW: Drivers: remove excessive check in bq25896 and make PVS happy @@ -19,7 +23,7 @@ * OFW: SD Cache: moved to diskio layer, invalidation in case of error * OFW: Picopass: factory key support, minor code cleanup -#### [🎲 Download latest extra apps pack](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps) +#### [🎲 Download latest extra apps pack](https://github.com/xMasterX/unleashed-extra-pack/archive/refs/heads/main.zip) [-> How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) diff --git a/ReadMe.md b/ReadMe.md index 5563bc390c..24659d6b6d 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -25,7 +25,7 @@ Our Discord Community:

-## Dev builds +## Dev builds (unstable) - https://dev.unleashedflip.com/ - https://t.me/kotnehleb ## Releases in Telegram @@ -35,7 +35,7 @@ Our Discord Community: * Sub-GHz regional TX restrictions removed * Sub-GHz frequency range can be extended in settings file (Warning: It can damage Flipper's hardware) * Many rolling code protocols now have the ability to save & send captured signals -* FAAC SLH (Spa) & BFT Mitto (secure with seed) manual creation +* FAAC SLH (Spa) & BFT Mitto (keeloq secure with seed) manual creation * Sub-GHz static code brute-force plugin * LFRFID Fuzzer plugin * Custom community plugins and games added + all known working apps can be downloaded in extra pack in every release @@ -43,13 +43,25 @@ Our Discord Community: * Picopass/iClass plugin included in releases * Recompiled IR TV Universal Remote for ALL buttons * Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.) -* BadUSB keyboard layouts * Customizable Flipper name +- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout) +- Sub-GHz -> External CC1101 module support - [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307) +- Sub-GHz -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43) +- Sub-GHz -> Save last used frequency [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77) +- Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77) +- Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79) +- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107) * Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes * Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu * Sub-GHz -> External CC1101 module support +* SubGHz -> **Hold right in received signal list to delete selected signal** +* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis** - now you can use arrow buttons to send signal with different button code +* SubGHz -> BFT Mitto / Somfy Telis / Nice Flor S manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis) +* SubGHz -> Debug mode counter increase settings (+1 -> +5, +10, default: +1) +* SubGHz -> Debug PIN output settings for protocol development +* Infrared -> Debug TX PIN output settings * Other small fixes and changes throughout -* See other changes in changelog and in readme below +* See other changes in readme below Also check the changelog in releases for latest updates! @@ -156,21 +168,6 @@ Games: - BlackJack [(by teeebor)](https://github.com/teeebor/flipper_games) - 2048 game [(by eugene-kirzhanov)](https://github.com/eugene-kirzhanov/flipper-zero-2048-game) -### Other changes - -- BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout) -- Sub-GHz -> External CC1101 module support - [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307) -- Sub-GHz -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43) -- Sub-GHz -> Save last used frequency [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77) -- Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77) -- Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79) -- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107) -* SubGHz -> **Hold right in received signal list to delete selected signal** -* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis** - now you can use arrow buttons to send signal with different button code -* SubGHz -> BFT Mitto / Somfy Telis / Nice Flor S manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis) -* SubGHz -> Debug mode counter increase settings (+5, +10, default: +1) -* SubGHz -> Debug PIN output settings for protocol development -* Infrared -> Debug TX PIN output settings # Instructions ## [- How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md)