From 080324f7e0b28283fd4da5b24b1efb41a0c9af0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 25 May 2023 23:22:31 +0900 Subject: [PATCH 1/7] [FL-3315] Desktop,Rpc: desktop status subscription (#2696) * Desktop,Rpc: desktop status subscription * Desktop,RPC: properly handle unsubscribe Co-authored-by: Sergey Gavrilov --- applications/services/desktop/desktop.c | 13 +++++ applications/services/desktop/desktop.h | 8 +++ applications/services/desktop/desktop_i.h | 2 + applications/services/rpc/rpc_desktop.c | 64 +++++++++++++++++++++++ assets/protobuf | 2 +- 5 files changed, 88 insertions(+), 1 deletion(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 36589aed4..e1da64940 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -147,6 +147,9 @@ void desktop_lock(Desktop* desktop) { desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); notification_message(desktop->notification, &sequence_display_backlight_off_delay_1000); + + DesktopStatus status = {.locked = true}; + furi_pubsub_publish(desktop->status_pubsub, &status); } void desktop_unlock(Desktop* desktop) { @@ -165,6 +168,9 @@ void desktop_unlock(Desktop* desktop) { cli_session_open(cli, &cli_vcp); furi_record_close(RECORD_CLI); } + + DesktopStatus status = {.locked = false}; + furi_pubsub_publish(desktop->status_pubsub, &status); } void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { @@ -308,6 +314,8 @@ Desktop* desktop_alloc() { desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); + desktop->status_pubsub = furi_pubsub_alloc(); + furi_record_create(RECORD_DESKTOP, desktop); return desktop; @@ -331,6 +339,11 @@ void desktop_api_unlock(Desktop* instance) { view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopLockedEventUnlocked); } +FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance) { + furi_assert(instance); + return instance->status_pubsub; +} + int32_t desktop_srv(void* p) { UNUSED(p); diff --git a/applications/services/desktop/desktop.h b/applications/services/desktop/desktop.h index 5b12647b8..4eab24fcc 100644 --- a/applications/services/desktop/desktop.h +++ b/applications/services/desktop/desktop.h @@ -1,5 +1,7 @@ #pragma once +#include + typedef struct Desktop Desktop; #define RECORD_DESKTOP "desktop" @@ -7,3 +9,9 @@ typedef struct Desktop Desktop; bool desktop_api_is_locked(Desktop* instance); void desktop_api_unlock(Desktop* instance); + +typedef struct { + bool locked; +} DesktopStatus; + +FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index ede6bbcc3..0b3d56801 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -71,6 +71,8 @@ struct Desktop { FuriPubSubSubscription* input_events_subscription; FuriTimer* auto_lock_timer; + FuriPubSub* status_pubsub; + bool in_transition; }; diff --git a/applications/services/rpc/rpc_desktop.c b/applications/services/rpc/rpc_desktop.c index dbf9796ec..0d72b43d5 100644 --- a/applications/services/rpc/rpc_desktop.c +++ b/applications/services/rpc/rpc_desktop.c @@ -8,6 +8,8 @@ typedef struct { RpcSession* session; Desktop* desktop; + FuriPubSub* status_pubsub; + FuriPubSubSubscription* status_subscription; } RpcDesktop; static void rpc_desktop_on_is_locked_request(const PB_Main* request, void* context) { @@ -39,11 +41,63 @@ static void rpc_desktop_on_unlock_request(const PB_Main* request, void* context) rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); } +static void rpc_desktop_on_desktop_pubsub(const void* message, void* context) { + RpcDesktop* rpc_desktop = context; + RpcSession* session = rpc_desktop->session; + const DesktopStatus* status = message; + + PB_Main rpc_message = { + .command_id = 0, + .command_status = PB_CommandStatus_OK, + .has_next = false, + .which_content = PB_Main_desktop_status_tag, + .content.desktop_status.locked = status->locked, + }; + rpc_send_and_release(session, &rpc_message); +} + +static void rpc_desktop_on_status_subscribe_request(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + furi_assert(request->which_content == PB_Main_desktop_status_subscribe_request_tag); + + FURI_LOG_D(TAG, "StatusSubscribeRequest"); + RpcDesktop* rpc_desktop = context; + RpcSession* session = rpc_desktop->session; + + if(rpc_desktop->status_subscription) { + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_ERROR); + } else { + rpc_desktop->status_subscription = furi_pubsub_subscribe( + rpc_desktop->status_pubsub, rpc_desktop_on_desktop_pubsub, rpc_desktop); + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); + } +} + +static void rpc_desktop_on_status_unsubscribe_request(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + furi_assert(request->which_content == PB_Main_desktop_status_unsubscribe_request_tag); + + FURI_LOG_D(TAG, "StatusUnsubscribeRequest"); + RpcDesktop* rpc_desktop = context; + RpcSession* session = rpc_desktop->session; + + if(rpc_desktop->status_subscription) { + furi_pubsub_unsubscribe(rpc_desktop->status_pubsub, rpc_desktop->status_subscription); + rpc_desktop->status_subscription = NULL; + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); + } else { + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_ERROR); + } +} + void* rpc_desktop_alloc(RpcSession* session) { furi_assert(session); RpcDesktop* rpc_desktop = malloc(sizeof(RpcDesktop)); rpc_desktop->desktop = furi_record_open(RECORD_DESKTOP); + rpc_desktop->status_pubsub = desktop_api_get_status_pubsub(rpc_desktop->desktop); rpc_desktop->session = session; RpcHandler rpc_handler = { @@ -58,6 +112,12 @@ void* rpc_desktop_alloc(RpcSession* session) { rpc_handler.message_handler = rpc_desktop_on_unlock_request; rpc_add_handler(session, PB_Main_desktop_unlock_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_desktop_on_status_subscribe_request; + rpc_add_handler(session, PB_Main_desktop_status_subscribe_request_tag, &rpc_handler); + + rpc_handler.message_handler = rpc_desktop_on_status_unsubscribe_request; + rpc_add_handler(session, PB_Main_desktop_status_unsubscribe_request_tag, &rpc_handler); + return rpc_desktop; } @@ -65,6 +125,10 @@ void rpc_desktop_free(void* context) { furi_assert(context); RpcDesktop* rpc_desktop = context; + if(rpc_desktop->status_subscription) { + furi_pubsub_unsubscribe(rpc_desktop->status_pubsub, rpc_desktop->status_subscription); + } + furi_assert(rpc_desktop->desktop); furi_record_close(RECORD_DESKTOP); diff --git a/assets/protobuf b/assets/protobuf index a13c5ddd0..f71c4b7f7 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit a13c5ddd0397511bd4c6de4afdd1031a5b6f5bca +Subproject commit f71c4b7f750f2539a1fed08925d8da3abdc80ff9 From faa14cfa1c7f48481d0165776ff320993853fa68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Legrelle?= Date: Thu, 25 May 2023 16:30:07 +0200 Subject: [PATCH 2/7] :sparkles: Add fr-FR-mac key layout (#2666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../resources/badusb/assets/layouts/fr-FR-mac.kl | Bin 0 -> 256 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/resources/badusb/assets/layouts/fr-FR-mac.kl diff --git a/assets/resources/badusb/assets/layouts/fr-FR-mac.kl b/assets/resources/badusb/assets/layouts/fr-FR-mac.kl new file mode 100644 index 0000000000000000000000000000000000000000..0906936547cd3c8accd9632bac82cb4193a24c25 GIT binary patch literal 256 zcmaLLM{dGU007a^2*c-7jOjgKAVDOih=6?{?tg}?*<^Na;Jp*y9N*W!`r*KahgW`G zvn8kCYGsczPfNdC`{Bl|xjXkB{IulBi;9;$9}G>b+c4NP+OloOuBmr3`wpx*a_q#Z zGgmHLIyaAHEaHW;H-;qCX%J` Date: Thu, 25 May 2023 17:38:56 +0300 Subject: [PATCH 3/7] [FL-3322] Infrared: respect carrier frequency and duty cycle settings (#2677) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make infrared_worker respect carrier frequency and duty cycle * Update comments Co-authored-by: あく --- applications/main/infrared/infrared.c | 3 +- firmware/targets/f18/api_symbols.csv | 2 +- firmware/targets/f7/api_symbols.csv | 4 +-- .../targets/f7/furi_hal/furi_hal_infrared.c | 14 +++----- lib/infrared/worker/infrared_worker.c | 32 ++++++++++++------- lib/infrared/worker/infrared_worker.h | 10 ++++-- 6 files changed, 38 insertions(+), 27 deletions(-) diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared.c index 4f450496d..685dd57ec 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared.c @@ -312,7 +312,8 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { if(infrared_signal_is_raw(signal)) { InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); - infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size); + infrared_worker_set_raw_signal( + infrared->worker, raw->timings, raw->timings_size, raw->frequency, raw->duty_cycle); } else { InfraredMessage* message = infrared_signal_get_message(signal); infrared_worker_set_decoded_signal(infrared->worker, message); diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index ee1ae1154..b7abdfc05 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,+,26.3,, +Version,+,27.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index e2bedffb7..15c19091e 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,+,26.3,, +Version,+,27.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1715,7 +1715,7 @@ Function,+,infrared_worker_rx_set_received_signal_callback,void,"InfraredWorker* Function,+,infrared_worker_rx_start,void,InfraredWorker* Function,+,infrared_worker_rx_stop,void,InfraredWorker* Function,+,infrared_worker_set_decoded_signal,void,"InfraredWorker*, const InfraredMessage*" -Function,+,infrared_worker_set_raw_signal,void,"InfraredWorker*, const uint32_t*, size_t" +Function,+,infrared_worker_set_raw_signal,void,"InfraredWorker*, const uint32_t*, size_t, uint32_t, float" Function,+,infrared_worker_signal_is_decoded,_Bool,const InfraredWorkerSignal* Function,+,infrared_worker_tx_get_signal_steady_callback,InfraredWorkerGetSignalResponse,"void*, InfraredWorker*" Function,+,infrared_worker_tx_set_get_signal_callback,void,"InfraredWorker*, InfraredWorkerGetSignalCallback, void*" diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index 2598e5fa3..7b4f17084 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -1,7 +1,6 @@ #include #include #include "stm32wbxx_ll_dma.h" -#include "sys/_stdint.h" #include #include @@ -13,11 +12,10 @@ #include #include -#define INFRARED_TX_DEBUG 0 +// #define INFRARED_TX_DEBUG -#if INFRARED_TX_DEBUG == 1 -#define gpio_infrared_tx gpio_infrared_tx_debug -const GpioPin gpio_infrared_tx_debug = {.port = GPIOA, .pin = GpioModeAnalog}; +#if defined INFRARED_TX_DEBUG +#define gpio_infrared_tx gpio_ext_pa7 #endif #define INFRARED_TIM_TX_DMA_BUFFER_SIZE 200 @@ -330,8 +328,6 @@ static void furi_hal_infrared_tx_dma_isr() { } static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cycle) { - /* LL_DBGMCU_APB2_GRP1_FreezePeriph(LL_DBGMCU_APB2_GRP1_TIM1_STOP); */ - LL_TIM_DisableCounter(TIM1); LL_TIM_SetRepetitionCounter(TIM1, 0); LL_TIM_SetCounter(TIM1, 0); @@ -340,7 +336,7 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc LL_TIM_EnableARRPreload(TIM1); LL_TIM_SetAutoReload( TIM1, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM1), freq)); -#if INFRARED_TX_DEBUG == 1 +#if defined INFRARED_TX_DEBUG LL_TIM_OC_SetCompareCH1(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1); /* LL_TIM_OCMODE_PWM2 set by DMA */ @@ -370,7 +366,7 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) { LL_DMA_InitTypeDef dma_config = {0}; -#if INFRARED_TX_DEBUG == 1 +#if defined INFRARED_TX_DEBUG dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR1); #else dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR2); diff --git a/lib/infrared/worker/infrared_worker.c b/lib/infrared/worker/infrared_worker.c index 5add1413e..46effd420 100644 --- a/lib/infrared/worker/infrared_worker.c +++ b/lib/infrared/worker/infrared_worker.c @@ -40,8 +40,12 @@ struct InfraredWorkerSignal { size_t timings_cnt; union { InfraredMessage message; - /* +1 is for pause we add at the beginning */ - uint32_t timings[MAX_TIMINGS_AMOUNT + 1]; + struct { + /* +1 is for pause we add at the beginning */ + uint32_t timings[MAX_TIMINGS_AMOUNT + 1]; + uint32_t frequency; + float duty_cycle; + } raw; }; }; @@ -146,7 +150,7 @@ static void } if(instance->signal.timings_cnt < MAX_TIMINGS_AMOUNT) { - instance->signal.timings[instance->signal.timings_cnt] = duration; + instance->signal.raw.timings[instance->signal.timings_cnt] = duration; ++instance->signal.timings_cnt; } else { uint32_t flags_set = furi_thread_flags_set( @@ -300,7 +304,7 @@ void infrared_worker_get_raw_signal( furi_assert(timings); furi_assert(timings_cnt); - *timings = signal->timings; + *timings = signal->raw.timings; *timings_cnt = signal->timings_cnt; } @@ -390,8 +394,8 @@ static bool infrared_get_new_signal(InfraredWorker* instance) { infrared_get_protocol_duty_cycle(instance->signal.message.protocol); } else { furi_assert(instance->signal.timings_cnt > 1); - new_tx_frequency = INFRARED_COMMON_CARRIER_FREQUENCY; - new_tx_duty_cycle = INFRARED_COMMON_DUTY_CYCLE; + new_tx_frequency = instance->signal.raw.frequency; + new_tx_duty_cycle = instance->signal.raw.duty_cycle; } instance->tx.tx_raw_cnt = 0; @@ -426,7 +430,7 @@ static bool infrared_worker_tx_fill_buffer(InfraredWorker* instance) { if(instance->signal.decoded) { status = infrared_encode(instance->infrared_encoder, &timing.duration, &timing.level); } else { - timing.duration = instance->signal.timings[instance->tx.tx_raw_cnt]; + timing.duration = instance->signal.raw.timings[instance->tx.tx_raw_cnt]; /* raw always starts from Mark, but we fill it with space delay at start */ timing.level = (instance->tx.tx_raw_cnt % 2); ++instance->tx.tx_raw_cnt; @@ -597,15 +601,21 @@ void infrared_worker_set_decoded_signal(InfraredWorker* instance, const Infrared void infrared_worker_set_raw_signal( InfraredWorker* instance, const uint32_t* timings, - size_t timings_cnt) { + size_t timings_cnt, + uint32_t frequency, + float duty_cycle) { furi_assert(instance); furi_assert(timings); furi_assert(timings_cnt > 0); - size_t max_copy_num = COUNT_OF(instance->signal.timings) - 1; + furi_assert((frequency <= INFRARED_MAX_FREQUENCY) && (frequency >= INFRARED_MIN_FREQUENCY)); + furi_assert((duty_cycle < 1.0f) && (duty_cycle > 0.0f)); + size_t max_copy_num = COUNT_OF(instance->signal.raw.timings) - 1; furi_check(timings_cnt <= max_copy_num); - instance->signal.timings[0] = INFRARED_RAW_TX_TIMING_DELAY_US; - memcpy(&instance->signal.timings[1], timings, timings_cnt * sizeof(uint32_t)); + instance->signal.raw.frequency = frequency; + instance->signal.raw.duty_cycle = duty_cycle; + instance->signal.raw.timings[0] = INFRARED_RAW_TX_TIMING_DELAY_US; + memcpy(&instance->signal.raw.timings[1], timings, timings_cnt * sizeof(uint32_t)); instance->signal.decoded = false; instance->signal.timings_cnt = timings_cnt + 1; } diff --git a/lib/infrared/worker/infrared_worker.h b/lib/infrared/worker/infrared_worker.h index 1a8cd9a76..e0e861983 100644 --- a/lib/infrared/worker/infrared_worker.h +++ b/lib/infrared/worker/infrared_worker.h @@ -130,9 +130,9 @@ void infrared_worker_tx_set_signal_sent_callback( /** Callback to pass to infrared_worker_tx_set_get_signal_callback() if signal * is steady and will not be changed between infrared_worker start and stop. * Before starting transmission, desired steady signal must be set with - * infrared_worker_make_decoded_signal() or infrared_worker_make_raw_signal(). + * infrared_worker_set_decoded_signal() or infrared_worker_set_raw_signal(). * - * This function should not be implicitly called. + * This function should not be called directly. * * @param[in] context - context * @param[out] instance - InfraredWorker instance @@ -172,11 +172,15 @@ void infrared_worker_set_decoded_signal(InfraredWorker* instance, const Infrared * @param[out] instance - InfraredWorker instance * @param[in] timings - array of raw timings * @param[in] timings_cnt - size of array of raw timings + * @param[in] frequency - carrier frequency in Hertz + * @param[in] duty_cycle - carrier duty cycle (0.0 - 1.0) */ void infrared_worker_set_raw_signal( InfraredWorker* instance, const uint32_t* timings, - size_t timings_cnt); + size_t timings_cnt, + uint32_t frequency, + float duty_cycle); #ifdef __cplusplus } From 12dc5b186f49dde06b1d11effacd08ba3f55612b Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Thu, 25 May 2023 17:50:13 +0300 Subject: [PATCH 4/7] USB HID report timeout (#2682) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- firmware/targets/f7/furi_hal/furi_hal_usb_hid.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c index d27613410..334aa0102 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -436,7 +436,11 @@ static bool hid_send_report(uint8_t report_id) { if((hid_semaphore == NULL) || (hid_connected == false)) return false; if((boot_protocol == true) && (report_id != ReportIdKeyboard)) return false; - furi_check(furi_semaphore_acquire(hid_semaphore, FuriWaitForever) == FuriStatusOk); + FuriStatus status = furi_semaphore_acquire(hid_semaphore, HID_INTERVAL * 2); + if(status == FuriStatusErrorTimeout) { + return false; + } + furi_check(status == FuriStatusOk); if(hid_connected == false) { return false; } From a472ff7a0fbff7c42682e1aa9e2afdfaa3732e4d Mon Sep 17 00:00:00 2001 From: minchogaydarov <134236905+minchogaydarov@users.noreply.github.com> Date: Thu, 25 May 2023 16:00:13 +0100 Subject: [PATCH 5/7] Add Airwell Prime DCI Series and match file style (#2686) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- assets/resources/infrared/assets/ac.ir | 41 ++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 96a2a0f38..cfa62f6a2 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -297,8 +297,8 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 2320 634 837 637 838 637 838 640 835 642 832 1378 836 645 826 670 809 667 808 1406 806 672 803 674 802 1412 802 1412 800 676 801 675 802 1412 802 674 802 1413 801 1412 801 1413 802 1412 802 50937 2285 671 801 1411 802 51225 2280 696 775 1412 801 51212 2283 671 775 1412 802 -# Model: Daikin FTXM20M. # +# Model: Daikin FTXM20M. name: Off type: raw frequency: 38000 @@ -334,8 +334,8 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 503 365 500 364 501 366 499 365 500 364 502 25049 3535 1660 504 1228 503 390 474 391 473 393 471 1261 469 397 468 397 469 397 469 397 469 1264 468 398 468 1264 468 1264 468 398 468 1265 467 1265 467 1265 467 1265 467 1265 467 399 467 399 467 1266 466 399 467 400 466 400 466 400 466 423 443 423 443 401 465 423 442 424 442 424 442 1290 442 424 442 1290 442 424 442 424 441 424 442 1290 442 1291 441 425 441 424 442 425 441 425 441 1291 441 425 440 425 441 425 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 426 440 1292 440 1292 440 1292 440 426 440 426 440 1292 440 1293 439 1293 439 35480 3503 1696 467 1264 468 398 468 398 467 398 468 1265 467 398 467 399 467 399 466 399 467 1265 467 399 467 1266 466 1267 465 400 466 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 442 1290 442 424 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 425 441 425 441 1291 441 425 441 425 441 425 441 425 440 1292 440 425 441 425 440 426 440 426 440 426 440 426 440 426 440 426 440 426 440 426 439 427 439 426 440 426 440 1293 439 427 439 427 439 427 438 427 439 428 438 1294 438 428 437 428 438 1295 437 1319 413 453 413 35480 3503 1696 468 1265 467 398 468 398 468 398 468 1265 467 398 468 399 466 399 467 399 467 1266 466 399 466 1267 465 1290 442 401 465 1290 442 1290 442 1290 442 1290 442 1290 442 424 442 424 441 1291 441 424 442 424 442 424 442 424 442 424 441 424 442 425 441 424 442 424 441 425 441 425 441 425 440 425 441 425 441 425 441 425 441 425 441 425 441 1292 440 426 440 426 440 1292 440 426 440 426 440 1293 439 426 440 426 440 1293 439 1293 439 1293 439 427 439 1294 438 427 438 427 439 427 438 428 438 428 438 428 438 428 438 453 413 429 437 453 413 1319 413 1320 412 1320 412 1320 412 454 412 1320 412 454 412 1321 411 1321 411 1321 411 1321 411 1321 411 455 410 455 411 455 411 455 410 456 410 456 410 456 410 481 384 481 385 482 383 482 383 483 358 507 359 1374 358 1374 358 508 358 508 358 508 358 509 357 509 357 535 331 535 331 535 330 535 330 536 330 1403 329 1403 329 563 302 564 301 564 302 564 301 565 301 591 274 619 246 593 273 620 245 620 245 621 245 673 189 -# Model: Mitsubishi SRK63HE. # +# Model: Mitsubishi SRK63HE. name: Off type: raw frequency: 38000 @@ -371,3 +371,40 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3234 1525 463 333 462 1127 465 332 462 333 436 1153 518 307 488 1073 518 307 488 308 434 1131 459 1155 435 1156 434 362 433 1159 432 363 432 1159 432 1159 432 1159 433 363 432 363 432 363 433 363 432 1159 433 1159 432 363 432 1159 433 1159 432 363 432 363 432 1159 432 363 433 363 432 1159 432 363 432 363 432 1159 432 1159 432 363 432 1160 432 1160 431 1160 432 1160 431 1160 431 1160 431 364 431 1160 431 1160 431 1160 431 364 431 364 431 364 431 364 431 1160 431 364 431 364 431 364 431 1160 432 1160 431 1160 432 364 431 1160 431 1160 431 1161 431 1161 430 364 431 364 431 364 431 1160 432 364 431 364 431 364 432 364 431 1161 431 1161 431 364 431 364 431 1161 430 364 432 364 431 1161 430 365 431 365 431 1161 430 1161 430 365 431 1161 430 1161 430 365 430 +# +# Model: Airwell Prime DCI Series +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3078 3852 2004 888 1054 1824 1045 894 1051 865 2062 861 1078 860 1080 865 1046 894 1015 1883 1945 899 1013 901 1013 901 1012 902 1012 900 1042 927 986 902 1012 927 987 901 1012 902 1012 927 986 903 1011 902 1012 931 1011 931 1011 904 1010 933 1009 928 985 928 986 1885 1944 927 3017 3943 1943 927 985 1915 984 929 985 929 1943 957 984 929 985 928 985 929 985 1886 1943 899 984 930 983 930 984 957 986 929 985 929 985 930 984 930 983 930 984 930 1013 930 984 959 983 931 982 931 983 930 984 930 984 930 984 960 1011 931 984 1918 1939 929 3016 3917 1940 930 982 1916 954 959 954 959 1913 957 955 933 981 959 928 1015 954 1916 1913 959 953 960 957 986 927 1015 928 1015 953 961 927 987 927 986 927 987 927 986 927 1016 927 987 927 1016 926 1044 928 987 926 1015 928 988 926 987 926 988 926 1946 1883 987 3974 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3060 3870 1026 888 1984 886 1026 888 1053 888 1026 887 1055 858 1055 858 1052 860 1024 891 1044 1854 1016 897 1975 1853 1975 925 1015 898 1015 898 1016 897 1016 898 1015 898 1016 898 1015 898 1015 898 1015 899 1015 899 1014 899 1014 899 1016 927 1014 900 1014 899 1014 1856 1974 926 3048 3883 1015 898 1975 897 1014 899 1015 899 1014 900 1014 899 1015 900 1013 900 1014 899 1014 1857 1014 900 1973 1855 1973 899 1012 901 1013 902 1011 926 987 927 987 926 987 927 987 955 987 926 988 926 987 927 1015 927 987 927 987 926 988 926 1016 927 1015 1884 1945 925 3020 3911 986 928 1946 925 986 927 986 928 986 928 986 927 987 927 987 928 986 928 986 1884 987 956 1946 1882 1946 925 986 928 986 927 986 928 985 928 986 928 986 928 986 928 985 928 985 929 959 954 984 930 984 987 931 955 959 956 958 955 959 1968 1891 980 3982 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3054 3879 1977 892 1020 1846 1083 838 1073 840 2031 859 1051 864 1047 864 1077 896 1014 927 986 928 986 928 986 1885 1943 927 985 929 1013 928 986 929 985 928 985 928 985 928 985 929 985 929 985 957 985 928 1015 928 1015 928 985 929 984 929 985 929 985 1886 1943 927 3017 3914 1943 928 984 1886 985 958 984 929 1972 957 984 958 984 929 984 930 984 929 984 930 984 930 983 1887 1942 929 983 930 984 930 984 930 983 959 984 930 984 930 983 930 984 930 984 930 984 930 983 931 983 931 983 959 984 931 983 931 983 1888 1941 930 3014 3943 1914 931 981 1915 955 959 955 959 1913 958 955 959 954 959 955 959 955 959 955 988 955 960 953 1917 1941 959 953 960 953 961 953 961 953 961 927 987 927 987 927 987 926 987 927 1017 926 988 926 988 925 988 925 988 926 988 925 1018 925 1972 1857 1014 3946 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3080 3850 2007 863 1049 1851 1048 888 1054 887 2012 886 1026 887 1025 888 1050 865 1045 1854 2029 871 1041 872 1040 873 1042 899 1043 899 1043 872 1015 898 1016 899 1041 872 1042 872 1015 926 1017 898 1016 927 1016 926 1016 899 1014 898 1015 926 1016 899 1015 898 1015 1856 1973 897 3048 3910 1947 898 1015 1884 1015 925 988 899 2003 953 988 900 1014 954 988 926 987 1857 1972 896 988 899 1014 900 1014 900 1013 927 987 929 1014 929 1013 926 987 927 986 927 987 927 987 927 987 927 986 927 987 927 986 985 958 928 986 927 986 927 1012 1860 1943 927 3018 3914 1943 955 986 1914 986 929 984 928 1944 955 957 930 984 957 985 956 958 1913 1915 956 957 957 956 957 931 1012 957 930 983 958 955 931 982 958 956 960 983 958 956 958 955 958 930 984 930 984 930 984 930 984 930 1013 930 984 930 985 928 1942 1887 983 3977 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3083 3873 2012 1843 2013 1873 1054 888 2011 887 1025 887 1025 887 1052 890 1048 1852 1017 896 1018 895 1018 896 1976 895 1017 898 1016 898 1015 898 1016 897 1016 897 1016 897 1017 897 1016 897 1017 900 1043 899 1014 897 1016 897 1016 898 1016 898 1015 898 1015 1857 1972 896 3048 3911 1947 1853 1975 1854 1015 898 1973 897 1016 927 1015 926 987 926 1016 1857 1014 926 987 899 1015 901 1970 926 987 927 987 926 988 955 988 1013 958 900 1014 926 987 900 1014 900 1014 900 1013 927 986 927 987 927 1016 955 987 927 987 955 987 1884 1946 928 3045 3912 1974 1883 1974 1883 987 927 1974 926 986 927 987 928 987 956 987 1942 986 956 986 928 986 928 1944 926 986 928 985 929 984 929 985 928 986 956 987 928 986 958 984 929 984 930 984 930 983 929 985 958 984 930 984 957 957 956 957 1887 1971 956 4003 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3108 3851 2062 1793 2006 1821 1103 839 2031 859 1085 829 1081 833 1079 836 1045 1911 1973 897 1015 898 1016 899 1041 871 1016 899 1014 898 1015 899 1015 899 1014 899 1041 872 1015 899 1041 872 1041 872 1015 899 1015 899 1041 873 1014 899 1041 873 1014 899 1014 1883 1975 900 3045 3886 1997 1856 1945 1857 1012 927 1945 900 1013 901 1012 901 1013 901 1012 1859 1999 901 1012 930 1012 903 1011 903 1010 903 1011 902 1012 960 1011 928 986 932 1010 903 1011 928 1015 928 985 929 985 928 1014 928 985 929 985 929 984 929 985 928 986 1915 1971 928 3017 3915 1942 1885 1943 1885 985 930 1971 929 984 930 983 930 984 930 984 1887 1942 929 983 960 983 931 982 931 983 932 981 958 985 958 956 958 984 959 954 931 983 932 981 959 955 932 982 959 954 960 982 961 983 933 955 988 955 985 929 1943 1915 958 4003 From 77bb997b0b4bc73a53624af3d1b9391856f70c98 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Thu, 25 May 2023 10:16:41 -0600 Subject: [PATCH 6/7] desktop: Refactor favorites settings and allow app browser in selection (#2687) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * desktop: Refactor favorites settings and allow app browser in selection * desktop: Gate app browser entry add, just in case * Desktop: simplify favorite application selection * Desktop: refactor favorite application opening routine and cleanup code * Desktop: handle exit from external application selection Co-authored-by: hedger Co-authored-by: あく --- .../services/desktop/desktop_settings.h | 2 - .../desktop/scenes/desktop_scene_main.c | 49 ++++------ .../scenes/desktop_settings_scene_favorite.c | 94 +++++++++---------- 3 files changed, 61 insertions(+), 84 deletions(-) diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 5d1b6126f..7ab39094d 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -36,8 +36,6 @@ #define MIN_PIN_SIZE 4 #define MAX_APP_LENGTH 128 -#define FAP_LOADER_APP_NAME "Applications" - typedef struct { InputKey data[MAX_PIN_SIZE]; uint8_t length; diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 053ac56f1..d19b5560f 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -16,6 +16,8 @@ #define SNAKE_GAME_APP EXT_PATH("/apps/Games/snake_game.fap") #define CLOCK_APP EXT_PATH("/apps/Tools/clock.fap") +#define FAP_LOADER_APP_NAME "Applications" + static void desktop_scene_main_new_idle_animation_callback(void* context) { furi_assert(context); Desktop* desktop = context; @@ -77,6 +79,21 @@ static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char* } while(false); } +static void desktop_scene_main_start_favorite(Desktop* desktop, FavoriteApp* application) { + LoaderStatus status = LoaderStatusErrorInternal; + if(application->is_external) { + status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, application->name_or_path); + } else if(strlen(application->name_or_path) > 0) { + status = loader_start(desktop->loader, application->name_or_path, NULL); + } else { + status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, NULL); + } + + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } +} + void desktop_scene_main_callback(DesktopEvent event, void* context) { Desktop* desktop = (Desktop*)context; if(desktop->in_transition) return; @@ -141,40 +158,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { case DesktopMainEventOpenFavoritePrimary: DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.favorite_primary.is_external) { - LoaderStatus status = loader_start( - desktop->loader, - FAP_LOADER_APP_NAME, - desktop->settings.favorite_primary.name_or_path); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } else { - LoaderStatus status = loader_start( - desktop->loader, desktop->settings.favorite_primary.name_or_path, NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } + desktop_scene_main_start_favorite(desktop, &desktop->settings.favorite_primary); consumed = true; break; case DesktopMainEventOpenFavoriteSecondary: DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.favorite_secondary.is_external) { - LoaderStatus status = loader_start( - desktop->loader, - FAP_LOADER_APP_NAME, - desktop->settings.favorite_secondary.name_or_path); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } else { - LoaderStatus status = loader_start( - desktop->loader, desktop->settings.favorite_secondary.name_or_path, NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } + desktop_scene_main_start_favorite(desktop, &desktop->settings.favorite_secondary); consumed = true; break; case DesktopAnimationEventCheckAnimation: diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 94c5ee9f0..4b5c47921 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -5,6 +5,9 @@ #include #include +#define EXTERNAL_APPLICATION_NAME ("[External Application]") +#define EXTERNAL_APPLICATION_INDEX (FLIPPER_APPS_COUNT + 1) + static bool favorite_fap_selector_item_callback( FuriString* file_path, void* context, @@ -44,6 +47,8 @@ void desktop_settings_scene_favorite_on_enter(void* context) { uint32_t primary_favorite = scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); uint32_t pre_select_item = 0; + FavoriteApp* curr_favorite_app = primary_favorite ? &app->settings.favorite_primary : + &app->settings.favorite_secondary; for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { submenu_add_item( @@ -53,21 +58,25 @@ void desktop_settings_scene_favorite_on_enter(void* context) { desktop_settings_scene_favorite_submenu_callback, app); - if(primary_favorite) { // Select favorite item in submenu - if((app->settings.favorite_primary.is_external && - !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || - (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_primary.name_or_path))) { - pre_select_item = i; - } - } else { - if((app->settings.favorite_secondary.is_external && - !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || - (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_secondary.name_or_path))) { - pre_select_item = i; - } + // Select favorite item in submenu + if(!curr_favorite_app->is_external && + !strcmp(FLIPPER_APPS[i].name, curr_favorite_app->name_or_path)) { + pre_select_item = i; } } +#ifdef APP_FAP_LOADER + submenu_add_item( + submenu, + EXTERNAL_APPLICATION_NAME, + EXTERNAL_APPLICATION_INDEX, + desktop_settings_scene_favorite_submenu_callback, + app); + if(curr_favorite_app->is_external) { + pre_select_item = EXTERNAL_APPLICATION_INDEX; + } +#endif + submenu_set_header( submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:"); submenu_set_selected_item(submenu, pre_select_item); // If set during loop, visual glitch. @@ -82,23 +91,11 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e uint32_t primary_favorite = scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); + FavoriteApp* curr_favorite_app = primary_favorite ? &app->settings.favorite_primary : + &app->settings.favorite_secondary; if(event.type == SceneManagerEventTypeCustom) { - if(strcmp(FLIPPER_APPS[event.event].name, FAP_LOADER_APP_NAME) != 0) { - if(primary_favorite) { - app->settings.favorite_primary.is_external = false; - strncpy( - app->settings.favorite_primary.name_or_path, - FLIPPER_APPS[event.event].name, - MAX_APP_LENGTH); - } else { - app->settings.favorite_secondary.is_external = false; - strncpy( - app->settings.favorite_secondary.name_or_path, - FLIPPER_APPS[event.event].name, - MAX_APP_LENGTH); - } - } else { + if(event.event == EXTERNAL_APPLICATION_INDEX) { const DialogsFileBrowserOptions browser_options = { .extension = ".fap", .icon = &I_unknown_10px, @@ -109,36 +106,29 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e .base_path = EXT_PATH("apps"), }; - if(primary_favorite) { // Select favorite fap in file browser - if(favorite_fap_selector_file_exists( - app->settings.favorite_primary.name_or_path)) { - furi_string_set_str(temp_path, app->settings.favorite_primary.name_or_path); - } - } else { - if(favorite_fap_selector_file_exists( - app->settings.favorite_secondary.name_or_path)) { - furi_string_set_str(temp_path, app->settings.favorite_secondary.name_or_path); - } + // Select favorite fap in file browser + if(favorite_fap_selector_file_exists(curr_favorite_app->name_or_path)) { + furi_string_set_str(temp_path, curr_favorite_app->name_or_path); } - submenu_reset(app->submenu); if(dialog_file_browser_show(app->dialogs, temp_path, temp_path, &browser_options)) { - if(primary_favorite) { - app->settings.favorite_primary.is_external = true; - strncpy( - app->settings.favorite_primary.name_or_path, - furi_string_get_cstr(temp_path), - MAX_APP_LENGTH); - } else { - app->settings.favorite_secondary.is_external = true; - strncpy( - app->settings.favorite_secondary.name_or_path, - furi_string_get_cstr(temp_path), - MAX_APP_LENGTH); - } + submenu_reset(app->submenu); // Prevent menu from being shown when we exiting scene + curr_favorite_app->is_external = true; + strncpy( + curr_favorite_app->name_or_path, + furi_string_get_cstr(temp_path), + MAX_APP_LENGTH); + consumed = true; } + } else { + curr_favorite_app->is_external = false; + strncpy( + curr_favorite_app->name_or_path, FLIPPER_APPS[event.event].name, MAX_APP_LENGTH); + consumed = true; } - scene_manager_previous_scene(app->scene_manager); + if(consumed) { + scene_manager_previous_scene(app->scene_manager); + }; consumed = true; } From 490447bbd482126063bce3e5378198365b580963 Mon Sep 17 00:00:00 2001 From: Avery <30564701+nullableVoidPtr@users.noreply.github.com> Date: Fri, 26 May 2023 03:01:02 +1000 Subject: [PATCH 7/7] NFC: Add support for Gen4 "ultimate card" in Magic app (#2238) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * NFC: gen4 gtu detect in magic app * NFC: more support for GTU card * NFC: Fix Gen1 in Magic * Allow double UIDs for MFClassic on GTU cards * NFC: Small magic app tweaks * nfc magic: notify card event on wiping * nfc magic: fix power consumption * nfc magic: disable i2c writing and fix wipe loop * NfcMagic: correct formatting in printf * NfcMagic: correct formatting in printf, proper version * nfc_magic: rework card found notification and gen4 wiping Co-authored-by: あく --- .../nfc_magic/lib/magic/classic_gen1.c | 175 ++++++++ .../nfc_magic/lib/magic/classic_gen1.h | 13 + .../external/nfc_magic/lib/magic/common.c | 33 ++ .../external/nfc_magic/lib/magic/common.h | 19 + .../external/nfc_magic/lib/magic/gen4.c | 199 ++++++++++ .../external/nfc_magic/lib/magic/gen4.h | 48 +++ .../external/nfc_magic/lib/magic/magic.c | 52 +-- .../external/nfc_magic/lib/magic/magic.h | 15 - .../external/nfc_magic/lib/magic/types.c | 23 ++ .../external/nfc_magic/lib/magic/types.h | 5 + applications/external/nfc_magic/nfc_magic.c | 22 +- applications/external/nfc_magic/nfc_magic.h | 2 + applications/external/nfc_magic/nfc_magic_i.h | 20 +- .../external/nfc_magic/nfc_magic_worker.c | 372 +++++++++++++++--- .../external/nfc_magic/nfc_magic_worker.h | 4 + .../external/nfc_magic/nfc_magic_worker_i.h | 5 + .../scenes/nfc_magic_scene_actions.c | 50 +++ .../nfc_magic/scenes/nfc_magic_scene_check.c | 4 +- .../nfc_magic/scenes/nfc_magic_scene_config.h | 6 + .../scenes/nfc_magic_scene_file_select.c | 60 ++- .../scenes/nfc_magic_scene_gen4_actions.c | 70 ++++ .../scenes/nfc_magic_scene_key_input.c | 45 +++ .../scenes/nfc_magic_scene_magic_info.c | 14 + .../scenes/nfc_magic_scene_new_key_input.c | 45 +++ .../nfc_magic/scenes/nfc_magic_scene_rekey.c | 95 +++++ .../scenes/nfc_magic_scene_rekey_fail.c | 50 +++ .../nfc_magic/scenes/nfc_magic_scene_start.c | 25 +- .../nfc_magic/scenes/nfc_magic_scene_wipe.c | 11 +- .../nfc_magic/scenes/nfc_magic_scene_write.c | 11 +- .../scenes/nfc_magic_scene_wrong_card.c | 2 +- 30 files changed, 1345 insertions(+), 150 deletions(-) create mode 100644 applications/external/nfc_magic/lib/magic/classic_gen1.c create mode 100644 applications/external/nfc_magic/lib/magic/classic_gen1.h create mode 100644 applications/external/nfc_magic/lib/magic/common.c create mode 100644 applications/external/nfc_magic/lib/magic/common.h create mode 100644 applications/external/nfc_magic/lib/magic/gen4.c create mode 100644 applications/external/nfc_magic/lib/magic/gen4.h delete mode 100644 applications/external/nfc_magic/lib/magic/magic.h create mode 100644 applications/external/nfc_magic/lib/magic/types.c create mode 100644 applications/external/nfc_magic/lib/magic/types.h create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c diff --git a/applications/external/nfc_magic/lib/magic/classic_gen1.c b/applications/external/nfc_magic/lib/magic/classic_gen1.c new file mode 100644 index 000000000..ebd2b0805 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/classic_gen1.c @@ -0,0 +1,175 @@ +#include "classic_gen1.h" + +#include + +#define TAG "Magic" + +#define MAGIC_CMD_WUPA (0x40) +#define MAGIC_CMD_WIPE (0x41) +#define MAGIC_CMD_ACCESS (0x43) + +#define MAGIC_MIFARE_READ_CMD (0x30) +#define MAGIC_MIFARE_WRITE_CMD (0xA0) + +#define MAGIC_ACK (0x0A) + +#define MAGIC_BUFFER_SIZE (32) + +bool magic_gen1_wupa() { + bool magic_activated = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_WUPA; + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 7, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | + FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + magic_activated = true; + } while(false); + + return magic_activated; +} + +bool magic_gen1_data_access_cmd() { + bool write_cmd_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + tx_data[0] = MAGIC_CMD_ACCESS; + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 8, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | + FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + + write_cmd_success = true; + } while(false); + + return write_cmd_success; +} + +bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data) { + furi_assert(data); + + bool read_success = false; + + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + tx_data[0] = MAGIC_MIFARE_READ_CMD; + tx_data[1] = block_num; + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 2 * 8, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON, + furi_hal_nfc_ll_ms2fc(20)); + + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 16 * 8) break; + memcpy(data->value, rx_data, sizeof(data->value)); + read_success = true; + } while(false); + + return read_success; +} + +bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data) { + furi_assert(data); + + bool write_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + tx_data[0] = MAGIC_MIFARE_WRITE_CMD; + tx_data[1] = block_num; + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 2 * 8, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + + memcpy(tx_data, data->value, sizeof(data->value)); + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 16 * 8, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + + write_success = true; + } while(false); + + return write_success; +} + +bool magic_gen1_wipe() { + bool wipe_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + tx_data[0] = MAGIC_CMD_WIPE; + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 8, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | + FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP, + furi_hal_nfc_ll_ms2fc(2000)); + + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + + wipe_success = true; + } while(false); + + return wipe_success; +} \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/classic_gen1.h b/applications/external/nfc_magic/lib/magic/classic_gen1.h new file mode 100644 index 000000000..6d4ff6dcd --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/classic_gen1.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +bool magic_gen1_wupa(); + +bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data); + +bool magic_gen1_data_access_cmd(); + +bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data); + +bool magic_gen1_wipe(); \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/common.c b/applications/external/nfc_magic/lib/magic/common.c new file mode 100644 index 000000000..0ea3cb218 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/common.c @@ -0,0 +1,33 @@ +#include "common.h" + +#include + +#define REQA (0x26) +#define CL1_PREFIX (0x93) +#define SELECT (0x70) + +#define MAGIC_BUFFER_SIZE (32) + +bool magic_activate() { + FuriHalNfcReturn ret = 0; + + // Setup nfc poller + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_ll_txrx_on(); + furi_hal_nfc_ll_poll(); + ret = furi_hal_nfc_ll_set_mode( + FuriHalNfcModePollNfca, FuriHalNfcBitrate106, FuriHalNfcBitrate106); + if(ret != FuriHalNfcReturnOk) return false; + + furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER); + furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER); + furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc); + furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCA); + + return true; +} + +void magic_deactivate() { + furi_hal_nfc_ll_txrx_off(); + furi_hal_nfc_sleep(); +} \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/common.h b/applications/external/nfc_magic/lib/magic/common.h new file mode 100644 index 000000000..bef166c8f --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/common.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +typedef enum { + MagicTypeClassicGen1, + MagicTypeClassicDirectWrite, + MagicTypeClassicAPDU, + MagicTypeUltralightGen1, + MagicTypeUltralightDirectWrite, + MagicTypeUltralightC_Gen1, + MagicTypeUltralightC_DirectWrite, + MagicTypeGen4, +} MagicType; + +bool magic_activate(); + +void magic_deactivate(); \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/gen4.c b/applications/external/nfc_magic/lib/magic/gen4.c new file mode 100644 index 000000000..31be649a0 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/gen4.c @@ -0,0 +1,199 @@ +#include "gen4.h" + +#include +#include + +#define TAG "Magic" + +#define MAGIC_CMD_PREFIX (0xCF) + +#define MAGIC_CMD_GET_CFG (0xC6) +#define MAGIC_CMD_WRITE (0xCD) +#define MAGIC_CMD_READ (0xCE) +#define MAGIC_CMD_SET_CFG (0xF0) +#define MAGIC_CMD_FUSE_CFG (0xF1) +#define MAGIC_CMD_SET_PWD (0xFE) + +#define MAGIC_BUFFER_SIZE (40) + +const uint8_t MAGIC_DEFAULT_CONFIG[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x04, 0x00, 0x08, 0x00 +}; + +const uint8_t MAGIC_DEFAULT_BLOCK0[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t MAGIC_EMPTY_BLOCK[16] = { 0 }; + +const uint8_t MAGIC_DEFAULT_SECTOR_TRAILER[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static bool magic_gen4_is_block_num_trailer(uint8_t n) { + n++; + if (n < 32 * 4) { + return (n % 4 == 0); + } + + return (n % 16 == 0); +} + +bool magic_gen4_get_cfg(uint32_t pwd, uint8_t* config) { + bool is_valid_config_len = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_PREFIX; + tx_data[1] = (uint8_t)(pwd >> 24); + tx_data[2] = (uint8_t)(pwd >> 16); + tx_data[3] = (uint8_t)(pwd >> 8); + tx_data[4] = (uint8_t)pwd; + tx_data[5] = MAGIC_CMD_GET_CFG; + ret = furi_hal_nfc_ll_txrx( + tx_data, + 6, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_TXRX_DEFAULT, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 30 && rx_len != 32) break; + memcpy(config, rx_data, rx_len); + is_valid_config_len = true; + } while(false); + + return is_valid_config_len; +} + +bool magic_gen4_set_cfg(uint32_t pwd, const uint8_t* config, uint8_t config_length, bool fuse) { + bool write_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_PREFIX; + tx_data[1] = (uint8_t)(pwd >> 24); + tx_data[2] = (uint8_t)(pwd >> 16); + tx_data[3] = (uint8_t)(pwd >> 8); + tx_data[4] = (uint8_t)pwd; + tx_data[5] = fuse ? MAGIC_CMD_FUSE_CFG : MAGIC_CMD_SET_CFG; + memcpy(tx_data + 6, config, config_length); + ret = furi_hal_nfc_ll_txrx( + tx_data, + 6 + config_length, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_TXRX_DEFAULT, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 2) break; + write_success = true; + } while(false); + + return write_success; +} + +bool magic_gen4_set_pwd(uint32_t old_pwd, uint32_t new_pwd) { + bool change_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_PREFIX; + tx_data[1] = (uint8_t)(old_pwd >> 24); + tx_data[2] = (uint8_t)(old_pwd >> 16); + tx_data[3] = (uint8_t)(old_pwd >> 8); + tx_data[4] = (uint8_t)old_pwd; + tx_data[5] = MAGIC_CMD_SET_PWD; + tx_data[6] = (uint8_t)(new_pwd >> 24); + tx_data[7] = (uint8_t)(new_pwd >> 16); + tx_data[8] = (uint8_t)(new_pwd >> 8); + tx_data[9] = (uint8_t)new_pwd; + ret = furi_hal_nfc_ll_txrx( + tx_data, + 10, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_TXRX_DEFAULT, + furi_hal_nfc_ll_ms2fc(20)); + FURI_LOG_I(TAG, "ret %d, len %d", ret, rx_len); + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 2) break; + change_success = true; + } while(false); + + return change_success; +} + +bool magic_gen4_write_blk(uint32_t pwd, uint8_t block_num, const uint8_t* data) { + bool write_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_PREFIX; + tx_data[1] = (uint8_t)(pwd >> 24); + tx_data[2] = (uint8_t)(pwd >> 16); + tx_data[3] = (uint8_t)(pwd >> 8); + tx_data[4] = (uint8_t)pwd; + tx_data[5] = MAGIC_CMD_WRITE; + tx_data[6] = block_num; + memcpy(tx_data + 7, data, 16); + ret = furi_hal_nfc_ll_txrx( + tx_data, + 23, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_TXRX_DEFAULT, + furi_hal_nfc_ll_ms2fc(200)); + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 2) break; + write_success = true; + } while(false); + + return write_success; +} + +bool magic_gen4_wipe(uint32_t pwd) { + if(!magic_gen4_set_cfg(pwd, MAGIC_DEFAULT_CONFIG, sizeof(MAGIC_DEFAULT_CONFIG), false)) { + FURI_LOG_E(TAG, "Set config failed"); + return false; + } + if(!magic_gen4_write_blk(pwd, 0, MAGIC_DEFAULT_BLOCK0)) { + FURI_LOG_E(TAG, "Block 0 write failed"); + return false; + } + for(size_t i = 1; i < 64; i++) { + const uint8_t* block = magic_gen4_is_block_num_trailer(i) ? MAGIC_DEFAULT_SECTOR_TRAILER : MAGIC_EMPTY_BLOCK; + if(!magic_gen4_write_blk(pwd, i, block)) { + FURI_LOG_E(TAG, "Block %d write failed", i); + return false; + } + } + for(size_t i = 65; i < 256; i++) { + if(!magic_gen4_write_blk(pwd, i, MAGIC_EMPTY_BLOCK)) { + FURI_LOG_E(TAG, "Block %d write failed", i); + return false; + } + } + + return true; +} \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/gen4.h b/applications/external/nfc_magic/lib/magic/gen4.h new file mode 100644 index 000000000..c515af820 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/gen4.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#define MAGIC_GEN4_DEFAULT_PWD 0x00000000 +#define MAGIC_GEN4_CONFIG_LEN 32 + +#define NFCID1_SINGLE_SIZE 4 +#define NFCID1_DOUBLE_SIZE 7 +#define NFCID1_TRIPLE_SIZE 10 + +typedef enum { + MagicGen4UIDLengthSingle = 0x00, + MagicGen4UIDLengthDouble = 0x01, + MagicGen4UIDLengthTriple = 0x02 +} MagicGen4UIDLength; + +typedef enum { + MagicGen4UltralightModeUL_EV1 = 0x00, + MagicGen4UltralightModeNTAG = 0x01, + MagicGen4UltralightModeUL_C = 0x02, + MagicGen4UltralightModeUL = 0x03 +} MagicGen4UltralightMode; + +typedef enum { + // for writing original (shadow) data + MagicGen4ShadowModePreWrite = 0x00, + // written data can be read once before restored to original + MagicGen4ShadowModeRestore = 0x01, + // written data is discarded + MagicGen4ShadowModeIgnore = 0x02, + // apparently for UL? + MagicGen4ShadowModeHighSpeedIgnore = 0x03 +} MagicGen4ShadowMode; + +bool magic_gen4_get_cfg(uint32_t pwd, uint8_t* config); + +bool magic_gen4_set_cfg(uint32_t pwd, const uint8_t* config, uint8_t config_length, bool fuse); + +bool magic_gen4_set_pwd(uint32_t old_pwd, uint32_t new_pwd); + +bool magic_gen4_read_blk(uint32_t pwd, uint8_t block_num, uint8_t* data); + +bool magic_gen4_write_blk(uint32_t pwd, uint8_t block_num, const uint8_t* data); + +bool magic_gen4_wipe(uint32_t pwd); + +void magic_gen4_deactivate(); diff --git a/applications/external/nfc_magic/lib/magic/magic.c b/applications/external/nfc_magic/lib/magic/magic.c index 9a71daaa0..ebd2b0805 100644 --- a/applications/external/nfc_magic/lib/magic/magic.c +++ b/applications/external/nfc_magic/lib/magic/magic.c @@ -1,4 +1,4 @@ -#include "magic.h" +#include "classic_gen1.h" #include @@ -15,7 +15,7 @@ #define MAGIC_BUFFER_SIZE (32) -bool magic_wupa() { +bool magic_gen1_wupa() { bool magic_activated = false; uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; @@ -23,19 +23,6 @@ bool magic_wupa() { FuriHalNfcReturn ret = 0; do { - // Setup nfc poller - furi_hal_nfc_exit_sleep(); - furi_hal_nfc_ll_txrx_on(); - furi_hal_nfc_ll_poll(); - ret = furi_hal_nfc_ll_set_mode( - FuriHalNfcModePollNfca, FuriHalNfcBitrate106, FuriHalNfcBitrate106); - if(ret != FuriHalNfcReturnOk) break; - - furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER); - furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER); - furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc); - furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCA); - // Start communication tx_data[0] = MAGIC_CMD_WUPA; ret = furi_hal_nfc_ll_txrx_bits( @@ -53,15 +40,10 @@ bool magic_wupa() { magic_activated = true; } while(false); - if(!magic_activated) { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); - } - return magic_activated; } -bool magic_data_access_cmd() { +bool magic_gen1_data_access_cmd() { bool write_cmd_success = false; uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; @@ -86,15 +68,10 @@ bool magic_data_access_cmd() { write_cmd_success = true; } while(false); - if(!write_cmd_success) { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); - } - return write_cmd_success; } -bool magic_read_block(uint8_t block_num, MfClassicBlock* data) { +bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data) { furi_assert(data); bool read_success = false; @@ -122,15 +99,10 @@ bool magic_read_block(uint8_t block_num, MfClassicBlock* data) { read_success = true; } while(false); - if(!read_success) { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); - } - return read_success; } -bool magic_write_blk(uint8_t block_num, MfClassicBlock* data) { +bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data) { furi_assert(data); bool write_success = false; @@ -170,15 +142,10 @@ bool magic_write_blk(uint8_t block_num, MfClassicBlock* data) { write_success = true; } while(false); - if(!write_success) { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); - } - return write_success; } -bool magic_wipe() { +bool magic_gen1_wipe() { bool wipe_success = false; uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; @@ -205,9 +172,4 @@ bool magic_wipe() { } while(false); return wipe_success; -} - -void magic_deactivate() { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_sleep(); -} +} \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/magic.h b/applications/external/nfc_magic/lib/magic/magic.h deleted file mode 100644 index 64c60a0a7..000000000 --- a/applications/external/nfc_magic/lib/magic/magic.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -bool magic_wupa(); - -bool magic_read_block(uint8_t block_num, MfClassicBlock* data); - -bool magic_data_access_cmd(); - -bool magic_write_blk(uint8_t block_num, MfClassicBlock* data); - -bool magic_wipe(); - -void magic_deactivate(); diff --git a/applications/external/nfc_magic/lib/magic/types.c b/applications/external/nfc_magic/lib/magic/types.c new file mode 100644 index 000000000..77c6c0a4e --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/types.c @@ -0,0 +1,23 @@ +#include "types.h" + +const char* nfc_magic_type(MagicType type) { + if(type == MagicTypeClassicGen1) { + return "Classic Gen 1A/B"; + } else if(type == MagicTypeClassicDirectWrite) { + return "Classic DirectWrite"; + } else if(type == MagicTypeClassicAPDU) { + return "Classic APDU"; + } else if(type == MagicTypeUltralightGen1) { + return "Ultralight Gen 1"; + } else if(type == MagicTypeUltralightDirectWrite) { + return "Ultralight DirectWrite"; + } else if(type == MagicTypeUltralightC_Gen1) { + return "Ultralight-C Gen 1"; + } else if(type == MagicTypeUltralightC_DirectWrite) { + return "Ultralight-C DirectWrite"; + } else if(type == MagicTypeGen4) { + return "Gen 4 GTU"; + } else { + return "Unknown"; + } +} diff --git a/applications/external/nfc_magic/lib/magic/types.h b/applications/external/nfc_magic/lib/magic/types.h new file mode 100644 index 000000000..dbf554063 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/types.h @@ -0,0 +1,5 @@ +#pragma once + +#include "common.h" + +const char* nfc_magic_type(MagicType type); \ No newline at end of file diff --git a/applications/external/nfc_magic/nfc_magic.c b/applications/external/nfc_magic/nfc_magic.c index 1805f35ed..68c9a65b5 100644 --- a/applications/external/nfc_magic/nfc_magic.c +++ b/applications/external/nfc_magic/nfc_magic.c @@ -48,8 +48,9 @@ NfcMagic* nfc_magic_alloc() { nfc_magic->view_dispatcher, nfc_magic_tick_event_callback, 100); // Nfc device - nfc_magic->nfc_dev = nfc_device_alloc(); - furi_string_set(nfc_magic->nfc_dev->folder, NFC_APP_FOLDER); + nfc_magic->dev = malloc(sizeof(NfcMagicDevice)); + nfc_magic->source_dev = nfc_device_alloc(); + furi_string_set(nfc_magic->source_dev->folder, NFC_APP_FOLDER); // Open GUI record nfc_magic->gui = furi_record_open(RECORD_GUI); @@ -81,6 +82,13 @@ NfcMagic* nfc_magic_alloc() { NfcMagicViewTextInput, text_input_get_view(nfc_magic->text_input)); + // Byte Input + nfc_magic->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + nfc_magic->view_dispatcher, + NfcMagicViewByteInput, + byte_input_get_view(nfc_magic->byte_input)); + // Custom Widget nfc_magic->widget = widget_alloc(); view_dispatcher_add_view( @@ -93,7 +101,8 @@ void nfc_magic_free(NfcMagic* nfc_magic) { furi_assert(nfc_magic); // Nfc device - nfc_device_free(nfc_magic->nfc_dev); + free(nfc_magic->dev); + nfc_device_free(nfc_magic->source_dev); // Submenu view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewMenu); @@ -107,10 +116,14 @@ void nfc_magic_free(NfcMagic* nfc_magic) { view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewLoading); loading_free(nfc_magic->loading); - // TextInput + // Text Input view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewTextInput); text_input_free(nfc_magic->text_input); + // Byte Input + view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput); + byte_input_free(nfc_magic->byte_input); + // Custom Widget view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); widget_free(nfc_magic->widget); @@ -164,6 +177,7 @@ int32_t nfc_magic_app(void* p) { view_dispatcher_run(nfc_magic->view_dispatcher); + magic_deactivate(); nfc_magic_free(nfc_magic); return 0; diff --git a/applications/external/nfc_magic/nfc_magic.h b/applications/external/nfc_magic/nfc_magic.h index 1abf1371e..f9cf395d8 100644 --- a/applications/external/nfc_magic/nfc_magic.h +++ b/applications/external/nfc_magic/nfc_magic.h @@ -1,3 +1,5 @@ #pragma once +typedef struct NfcMagicDevice NfcMagicDevice; + typedef struct NfcMagic NfcMagic; diff --git a/applications/external/nfc_magic/nfc_magic_i.h b/applications/external/nfc_magic/nfc_magic_i.h index 378912e5b..4d6b89103 100644 --- a/applications/external/nfc_magic/nfc_magic_i.h +++ b/applications/external/nfc_magic/nfc_magic_i.h @@ -3,7 +3,10 @@ #include "nfc_magic.h" #include "nfc_magic_worker.h" -#include "lib/magic/magic.h" +#include "lib/magic/common.h" +#include "lib/magic/types.h" +#include "lib/magic/classic_gen1.h" +#include "lib/magic/gen4.h" #include #include @@ -15,6 +18,7 @@ #include #include #include +#include #include #include @@ -39,14 +43,22 @@ enum NfcMagicCustomEvent { NfcMagicCustomEventTextInputDone, }; +struct NfcMagicDevice { + MagicType type; + uint32_t cuid; + uint32_t password; +}; + struct NfcMagic { NfcMagicWorker* worker; ViewDispatcher* view_dispatcher; Gui* gui; NotificationApp* notifications; SceneManager* scene_manager; - // NfcMagicDevice* dev; - NfcDevice* nfc_dev; + struct NfcMagicDevice* dev; + NfcDevice* source_dev; + + uint32_t new_password; FuriString* text_box_store; @@ -55,6 +67,7 @@ struct NfcMagic { Popup* popup; Loading* loading; TextInput* text_input; + ByteInput* byte_input; Widget* widget; }; @@ -63,6 +76,7 @@ typedef enum { NfcMagicViewPopup, NfcMagicViewLoading, NfcMagicViewTextInput, + NfcMagicViewByteInput, NfcMagicViewWidget, } NfcMagicView; diff --git a/applications/external/nfc_magic/nfc_magic_worker.c b/applications/external/nfc_magic/nfc_magic_worker.c index 92eb793a7..dc22b5d3e 100644 --- a/applications/external/nfc_magic/nfc_magic_worker.c +++ b/applications/external/nfc_magic/nfc_magic_worker.c @@ -1,6 +1,9 @@ #include "nfc_magic_worker_i.h" -#include "lib/magic/magic.h" +#include "nfc_magic_i.h" +#include "lib/magic/common.h" +#include "lib/magic/classic_gen1.h" +#include "lib/magic/gen4.h" #define TAG "NfcMagicWorker" @@ -43,15 +46,20 @@ void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker) { void nfc_magic_worker_start( NfcMagicWorker* nfc_magic_worker, NfcMagicWorkerState state, + NfcMagicDevice* magic_dev, NfcDeviceData* dev_data, + uint32_t new_password, NfcMagicWorkerCallback callback, void* context) { furi_assert(nfc_magic_worker); + furi_assert(magic_dev); furi_assert(dev_data); nfc_magic_worker->callback = callback; nfc_magic_worker->context = context; + nfc_magic_worker->magic_dev = magic_dev; nfc_magic_worker->dev_data = dev_data; + nfc_magic_worker->new_password = new_password; nfc_magic_worker_change_state(nfc_magic_worker, state); furi_thread_start(nfc_magic_worker->thread); } @@ -63,6 +71,8 @@ int32_t nfc_magic_worker_task(void* context) { nfc_magic_worker_check(nfc_magic_worker); } else if(nfc_magic_worker->state == NfcMagicWorkerStateWrite) { nfc_magic_worker_write(nfc_magic_worker); + } else if(nfc_magic_worker->state == NfcMagicWorkerStateRekey) { + nfc_magic_worker_rekey(nfc_magic_worker); } else if(nfc_magic_worker->state == NfcMagicWorkerStateWipe) { nfc_magic_worker_wipe(nfc_magic_worker); } @@ -74,59 +84,245 @@ int32_t nfc_magic_worker_task(void* context) { void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { bool card_found_notified = false; + bool done = false; FuriHalNfcDevData nfc_data = {}; - MfClassicData* src_data = &nfc_magic_worker->dev_data->mf_classic_data; + NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; + NfcDeviceData* dev_data = nfc_magic_worker->dev_data; + NfcProtocol dev_protocol = dev_data->protocol; while(nfc_magic_worker->state == NfcMagicWorkerStateWrite) { - if(furi_hal_nfc_detect(&nfc_data, 200)) { - if(!card_found_notified) { - nfc_magic_worker->callback( - NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); - card_found_notified = true; - } - furi_hal_nfc_sleep(); - if(!magic_wupa()) { - FURI_LOG_E(TAG, "No card response to WUPA (not a magic card)"); - nfc_magic_worker->callback( - NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); - break; - } - furi_hal_nfc_sleep(); - } - if(magic_wupa()) { - if(!magic_data_access_cmd()) { - FURI_LOG_E(TAG, "No card response to data access command (not a magic card)"); - nfc_magic_worker->callback( - NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); - break; - } - for(size_t i = 0; i < 64; i++) { - FURI_LOG_D(TAG, "Writing block %d", i); - if(!magic_write_blk(i, &src_data->block[i])) { - FURI_LOG_E(TAG, "Failed to write %d block", i); - nfc_magic_worker->callback(NfcMagicWorkerEventFail, nfc_magic_worker->context); + do { + if(furi_hal_nfc_detect(&nfc_data, 200)) { + if(nfc_data.cuid != magic_dev->cuid) break; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } + furi_hal_nfc_sleep(); + + magic_activate(); + if(magic_dev->type == MagicTypeClassicGen1) { + if(dev_protocol != NfcDeviceProtocolMifareClassic) break; + MfClassicData* mfc_data = &dev_data->mf_classic_data; + + if(mfc_data->type != MfClassicType1k) break; + if(!magic_gen1_wupa()) { + FURI_LOG_E(TAG, "Not Magic card"); + nfc_magic_worker->callback( + NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); + done = true; + break; + } + if(!magic_gen1_data_access_cmd()) { + FURI_LOG_E(TAG, "Not Magic card"); + nfc_magic_worker->callback( + NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); + done = true; + break; + } + for(size_t i = 0; i < 64; i++) { + FURI_LOG_D(TAG, "Writing block %d", i); + if(!magic_gen1_write_blk(i, &mfc_data->block[i])) { + FURI_LOG_E(TAG, "Failed to write %d block", i); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + + nfc_magic_worker->callback( + NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + done = true; + break; + } else if(magic_dev->type == MagicTypeGen4) { + uint8_t gen4_config[28]; + uint32_t password = magic_dev->password; + + uint32_t cuid; + if(dev_protocol == NfcDeviceProtocolMifareClassic) { + gen4_config[0] = 0x00; + gen4_config[27] = 0x00; + } else if(dev_protocol == NfcDeviceProtocolMifareUl) { + MfUltralightData* mf_ul_data = &dev_data->mf_ul_data; + gen4_config[0] = 0x01; + switch(mf_ul_data->type) { + case MfUltralightTypeUL11: + case MfUltralightTypeUL21: + // UL-C? + // UL? + default: + gen4_config[27] = MagicGen4UltralightModeUL_EV1; + break; + case MfUltralightTypeNTAG203: + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2C2K: + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + gen4_config[27] = MagicGen4UltralightModeNTAG; + break; + } + } + + if(dev_data->nfc_data.uid_len == 4) { + gen4_config[1] = MagicGen4UIDLengthSingle; + } else if(dev_data->nfc_data.uid_len == 7) { + gen4_config[1] = MagicGen4UIDLengthDouble; + } else { + FURI_LOG_E(TAG, "Unexpected UID length %d", dev_data->nfc_data.uid_len); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + + gen4_config[2] = (uint8_t)(password >> 24); + gen4_config[3] = (uint8_t)(password >> 16); + gen4_config[4] = (uint8_t)(password >> 8); + gen4_config[5] = (uint8_t)password; + + if(dev_protocol == NfcDeviceProtocolMifareUl) { + gen4_config[6] = MagicGen4ShadowModeHighSpeedIgnore; + } else { + gen4_config[6] = MagicGen4ShadowModeIgnore; + } + gen4_config[7] = 0x00; + memset(gen4_config + 8, 0, 16); + gen4_config[24] = dev_data->nfc_data.atqa[0]; + gen4_config[25] = dev_data->nfc_data.atqa[1]; + gen4_config[26] = dev_data->nfc_data.sak; + + furi_hal_nfc_activate_nfca(200, &cuid); + if(!magic_gen4_set_cfg(password, gen4_config, sizeof(gen4_config), false)) { + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + if(dev_protocol == NfcDeviceProtocolMifareClassic) { + MfClassicData* mfc_data = &dev_data->mf_classic_data; + size_t block_count = 64; + if(mfc_data->type == MfClassicType4k) block_count = 256; + for(size_t i = 0; i < block_count; i++) { + FURI_LOG_D(TAG, "Writing block %d", i); + if(!magic_gen4_write_blk(password, i, mfc_data->block[i].value)) { + FURI_LOG_E(TAG, "Failed to write %d block", i); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + } else if(dev_protocol == NfcDeviceProtocolMifareUl) { + MfUltralightData* mf_ul_data = &dev_data->mf_ul_data; + for(size_t i = 0; (i * 4) < mf_ul_data->data_read; i++) { + size_t data_offset = i * 4; + FURI_LOG_D( + TAG, + "Writing page %zu (%zu/%u)", + i, + data_offset, + mf_ul_data->data_read); + uint8_t* block = mf_ul_data->data + data_offset; + if(!magic_gen4_write_blk(password, i, block)) { + FURI_LOG_E(TAG, "Failed to write %zu page", i); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + + uint8_t buffer[16] = {0}; + + for(size_t i = 0; i < 8; i++) { + memcpy(buffer, &mf_ul_data->signature[i * 4], 4); //-V1086 + if(!magic_gen4_write_blk(password, 0xF2 + i, buffer)) { + FURI_LOG_E(TAG, "Failed to write signature block %d", i); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + + buffer[0] = mf_ul_data->version.header; + buffer[1] = mf_ul_data->version.vendor_id; + buffer[2] = mf_ul_data->version.prod_type; + buffer[3] = mf_ul_data->version.prod_subtype; + if(!magic_gen4_write_blk(password, 0xFA, buffer)) { + FURI_LOG_E(TAG, "Failed to write version block 0"); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + + buffer[0] = mf_ul_data->version.prod_ver_major; + buffer[1] = mf_ul_data->version.prod_ver_minor; + buffer[2] = mf_ul_data->version.storage_size; + buffer[3] = mf_ul_data->version.protocol_type; + if(!magic_gen4_write_blk(password, 0xFB, buffer)) { + FURI_LOG_E(TAG, "Failed to write version block 1"); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + + nfc_magic_worker->callback( + NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + done = true; break; } } - nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); - break; - } else { - if(card_found_notified) { - nfc_magic_worker->callback( - NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); - card_found_notified = false; - } + } while(false); + + if(done) break; + + if(card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; } + furi_delay_ms(300); } magic_deactivate(); } void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { + NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; bool card_found_notified = false; + uint8_t gen4_config[MAGIC_GEN4_CONFIG_LEN]; while(nfc_magic_worker->state == NfcMagicWorkerStateCheck) { - if(magic_wupa()) { + magic_activate(); + if(magic_gen1_wupa()) { + magic_dev->type = MagicTypeClassicGen1; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } + + furi_hal_nfc_activate_nfca(200, &magic_dev->cuid); + nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + break; + } + + magic_deactivate(); + furi_delay_ms(300); + magic_activate(); + + furi_hal_nfc_activate_nfca(200, &magic_dev->cuid); + if(magic_gen4_get_cfg(magic_dev->password, gen4_config)) { + magic_dev->type = MagicTypeGen4; if(!card_found_notified) { nfc_magic_worker->callback( NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); @@ -135,12 +331,56 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); break; - } else { + } + + if(card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; + } + + magic_deactivate(); + furi_delay_ms(300); + } + + magic_deactivate(); +} + +void nfc_magic_worker_rekey(NfcMagicWorker* nfc_magic_worker) { + NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; + bool card_found_notified = false; + + if(magic_dev->type != MagicTypeGen4) { + nfc_magic_worker->callback(NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + return; + } + + while(nfc_magic_worker->state == NfcMagicWorkerStateRekey) { + magic_activate(); + uint32_t cuid; + furi_hal_nfc_activate_nfca(200, &cuid); + if(cuid != magic_dev->cuid) { if(card_found_notified) { nfc_magic_worker->callback( NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); card_found_notified = false; } + continue; + } + + nfc_magic_worker->callback(NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + + if(magic_gen4_set_pwd(magic_dev->password, nfc_magic_worker->new_password)) { + magic_dev->password = nfc_magic_worker->new_password; + nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + break; + } + + if(card_found_notified) { //-V547 + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; } furi_delay_ms(300); } @@ -148,6 +388,10 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { } void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) { + NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; + bool card_found_notified = false; + bool card_wiped = false; + MfClassicBlock block; memset(&block, 0, sizeof(MfClassicBlock)); block.value[0] = 0x01; @@ -159,14 +403,48 @@ void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) { block.value[6] = 0x04; while(nfc_magic_worker->state == NfcMagicWorkerStateWipe) { - magic_deactivate(); - furi_delay_ms(300); - if(!magic_wupa()) continue; - if(!magic_wipe()) continue; - if(!magic_data_access_cmd()) continue; - if(!magic_write_blk(0, &block)) continue; - nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); - break; + do { + magic_deactivate(); + furi_delay_ms(300); + if(!magic_activate()) break; + if(magic_dev->type == MagicTypeClassicGen1) { + if(!magic_gen1_wupa()) break; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } + + if(!magic_gen1_wipe()) break; + if(!magic_gen1_data_access_cmd()) break; + if(!magic_gen1_write_blk(0, &block)) break; + + card_wiped = true; + nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + } else if(magic_dev->type == MagicTypeGen4) { + uint32_t cuid; + if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; + if(cuid != magic_dev->cuid) break; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } + + if(!magic_gen4_wipe(magic_dev->password)) break; + + card_wiped = true; + nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + } + } while(false); + + if(card_wiped) break; + + if(card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; + } } magic_deactivate(); } diff --git a/applications/external/nfc_magic/nfc_magic_worker.h b/applications/external/nfc_magic/nfc_magic_worker.h index 9d29bb3a8..51ff4ee43 100644 --- a/applications/external/nfc_magic/nfc_magic_worker.h +++ b/applications/external/nfc_magic/nfc_magic_worker.h @@ -1,6 +1,7 @@ #pragma once #include +#include "nfc_magic.h" typedef struct NfcMagicWorker NfcMagicWorker; @@ -9,6 +10,7 @@ typedef enum { NfcMagicWorkerStateCheck, NfcMagicWorkerStateWrite, + NfcMagicWorkerStateRekey, NfcMagicWorkerStateWipe, NfcMagicWorkerStateStop, @@ -33,6 +35,8 @@ void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker); void nfc_magic_worker_start( NfcMagicWorker* nfc_magic_worker, NfcMagicWorkerState state, + NfcMagicDevice* magic_dev, NfcDeviceData* dev_data, + uint32_t new_password, NfcMagicWorkerCallback callback, void* context); diff --git a/applications/external/nfc_magic/nfc_magic_worker_i.h b/applications/external/nfc_magic/nfc_magic_worker_i.h index 0cde2e712..a354f8047 100644 --- a/applications/external/nfc_magic/nfc_magic_worker_i.h +++ b/applications/external/nfc_magic/nfc_magic_worker_i.h @@ -3,11 +3,14 @@ #include #include "nfc_magic_worker.h" +#include "lib/magic/common.h" struct NfcMagicWorker { FuriThread* thread; + NfcMagicDevice* magic_dev; NfcDeviceData* dev_data; + uint32_t new_password; NfcMagicWorkerCallback callback; void* context; @@ -21,4 +24,6 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker); void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker); +void nfc_magic_worker_rekey(NfcMagicWorker* nfc_magic_worker); + void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c new file mode 100644 index 000000000..675262a9b --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c @@ -0,0 +1,50 @@ +#include "../nfc_magic_i.h" +enum SubmenuIndex { + SubmenuIndexWrite, + SubmenuIndexWipe, +}; + +void nfc_magic_scene_actions_submenu_callback(void* context, uint32_t index) { + NfcMagic* nfc_magic = context; + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index); +} + +void nfc_magic_scene_actions_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + Submenu* submenu = nfc_magic->submenu; + submenu_add_item( + submenu, "Write", SubmenuIndexWrite, nfc_magic_scene_actions_submenu_callback, nfc_magic); + submenu_add_item( + submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_actions_submenu_callback, nfc_magic); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneActions)); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu); +} + +bool nfc_magic_scene_actions_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect); + consumed = true; + } else if(event.event == SubmenuIndexWipe) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe); + consumed = true; + } + scene_manager_set_scene_state(nfc_magic->scene_manager, NfcMagicSceneActions, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + + return consumed; +} + +void nfc_magic_scene_actions_on_exit(void* context) { + NfcMagic* nfc_magic = context; + submenu_reset(nfc_magic->submenu); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_check.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_check.c index d51797242..90b43d7d3 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_check.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_check.c @@ -42,7 +42,9 @@ void nfc_magic_scene_check_on_enter(void* context) { nfc_magic_worker_start( nfc_magic->worker, NfcMagicWorkerStateCheck, - &nfc_magic->nfc_dev->dev_data, + nfc_magic->dev, + &nfc_magic->source_dev->dev_data, + nfc_magic->new_password, nfc_magic_check_worker_callback, nfc_magic); nfc_magic_blink_start(nfc_magic); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_config.h b/applications/external/nfc_magic/scenes/nfc_magic_scene_config.h index 557e26914..2f9860d96 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_config.h +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_config.h @@ -1,4 +1,8 @@ ADD_SCENE(nfc_magic, start, Start) +ADD_SCENE(nfc_magic, key_input, KeyInput) +ADD_SCENE(nfc_magic, actions, Actions) +ADD_SCENE(nfc_magic, gen4_actions, Gen4Actions) +ADD_SCENE(nfc_magic, new_key_input, NewKeyInput) ADD_SCENE(nfc_magic, file_select, FileSelect) ADD_SCENE(nfc_magic, write_confirm, WriteConfirm) ADD_SCENE(nfc_magic, wrong_card, WrongCard) @@ -8,5 +12,7 @@ ADD_SCENE(nfc_magic, success, Success) ADD_SCENE(nfc_magic, check, Check) ADD_SCENE(nfc_magic, not_magic, NotMagic) ADD_SCENE(nfc_magic, magic_info, MagicInfo) +ADD_SCENE(nfc_magic, rekey, Rekey) +ADD_SCENE(nfc_magic, rekey_fail, RekeyFail) ADD_SCENE(nfc_magic, wipe, Wipe) ADD_SCENE(nfc_magic, wipe_fail, WipeFail) diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c index d78422eeb..baa6bcccc 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c @@ -1,22 +1,60 @@ #include "../nfc_magic_i.h" -static bool nfc_magic_scene_file_select_is_file_suitable(NfcDevice* nfc_dev) { - return (nfc_dev->format == NfcDeviceSaveFormatMifareClassic) && - (nfc_dev->dev_data.mf_classic_data.type == MfClassicType1k) && - (nfc_dev->dev_data.nfc_data.uid_len == 4); +static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) { + NfcDevice* nfc_dev = nfc_magic->source_dev; + if(nfc_dev->format == NfcDeviceSaveFormatMifareClassic) { + switch(nfc_magic->dev->type) { + case MagicTypeClassicGen1: + case MagicTypeClassicDirectWrite: + case MagicTypeClassicAPDU: + if((nfc_dev->dev_data.mf_classic_data.type != MfClassicType1k) || + (nfc_dev->dev_data.nfc_data.uid_len != 4)) { + return false; + } + return true; + + case MagicTypeGen4: + return true; + default: + return false; + } + } else if( + (nfc_dev->format == NfcDeviceSaveFormatMifareUl) && + (nfc_dev->dev_data.nfc_data.uid_len == 7)) { + switch(nfc_magic->dev->type) { + case MagicTypeUltralightGen1: + case MagicTypeUltralightDirectWrite: + case MagicTypeUltralightC_Gen1: + case MagicTypeUltralightC_DirectWrite: + case MagicTypeGen4: + switch(nfc_dev->dev_data.mf_ul_data.type) { + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2C2K: + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + return false; + default: + return true; + } + default: + return false; + } + } + + return false; } void nfc_magic_scene_file_select_on_enter(void* context) { NfcMagic* nfc_magic = context; // Process file_select return - nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic); + nfc_device_set_loading_callback( + nfc_magic->source_dev, nfc_magic_show_loading_popup, nfc_magic); - if(!furi_string_size(nfc_magic->nfc_dev->load_path)) { - furi_string_set_str(nfc_magic->nfc_dev->load_path, NFC_APP_FOLDER); + if(!furi_string_size(nfc_magic->source_dev->load_path)) { + furi_string_set_str(nfc_magic->source_dev->load_path, NFC_APP_FOLDER); } - - if(nfc_file_select(nfc_magic->nfc_dev)) { - if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) { + if(nfc_file_select(nfc_magic->source_dev)) { + if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic)) { scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm); } else { scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWrongCard); @@ -34,5 +72,5 @@ bool nfc_magic_scene_file_select_on_event(void* context, SceneManagerEvent event void nfc_magic_scene_file_select_on_exit(void* context) { NfcMagic* nfc_magic = context; - nfc_device_set_loading_callback(nfc_magic->nfc_dev, NULL, nfc_magic); + nfc_device_set_loading_callback(nfc_magic->source_dev, NULL, nfc_magic); } diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c new file mode 100644 index 000000000..ceaa33e29 --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c @@ -0,0 +1,70 @@ +#include "../nfc_magic_i.h" +enum SubmenuIndex { + SubmenuIndexWrite, + SubmenuIndexChangePassword, + SubmenuIndexWipe, +}; + +void nfc_magic_scene_gen4_actions_submenu_callback(void* context, uint32_t index) { + NfcMagic* nfc_magic = context; + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index); +} + +void nfc_magic_scene_gen4_actions_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + Submenu* submenu = nfc_magic->submenu; + submenu_add_item( + submenu, + "Write", + SubmenuIndexWrite, + nfc_magic_scene_gen4_actions_submenu_callback, + nfc_magic); + submenu_add_item( + submenu, + "Change password", + SubmenuIndexChangePassword, + nfc_magic_scene_gen4_actions_submenu_callback, + nfc_magic); + submenu_add_item( + submenu, + "Wipe", + SubmenuIndexWipe, + nfc_magic_scene_gen4_actions_submenu_callback, + nfc_magic); + + submenu_set_selected_item( + submenu, + scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneGen4Actions)); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu); +} + +bool nfc_magic_scene_gen4_actions_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect); + consumed = true; + } else if(event.event == SubmenuIndexChangePassword) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNewKeyInput); + consumed = true; + } else if(event.event == SubmenuIndexWipe) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe); + consumed = true; + } + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneGen4Actions, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + + return consumed; +} + +void nfc_magic_scene_gen4_actions_on_exit(void* context) { + NfcMagic* nfc_magic = context; + submenu_reset(nfc_magic->submenu); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c new file mode 100644 index 000000000..58b487a09 --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c @@ -0,0 +1,45 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_key_input_byte_input_callback(void* context) { + NfcMagic* nfc_magic = context; + + view_dispatcher_send_custom_event( + nfc_magic->view_dispatcher, NfcMagicCustomEventByteInputDone); +} + +void nfc_magic_scene_key_input_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + // Setup view + ByteInput* byte_input = nfc_magic->byte_input; + byte_input_set_header_text(byte_input, "Enter the password in hex"); + byte_input_set_result_callback( + byte_input, + nfc_magic_scene_key_input_byte_input_callback, + NULL, + nfc_magic, + (uint8_t*)&nfc_magic->dev->password, + 4); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput); +} + +bool nfc_magic_scene_key_input_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicCustomEventByteInputDone) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_key_input_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + // Clear view + byte_input_set_result_callback(nfc_magic->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc_magic->byte_input, ""); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_magic_info.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_magic_info.c index e9b226b3a..c147ac438 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_magic_info.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_magic_info.c @@ -1,4 +1,5 @@ #include "../nfc_magic_i.h" +#include "../lib/magic/types.h" void nfc_magic_scene_magic_info_widget_callback( GuiButtonType result, @@ -13,14 +14,18 @@ void nfc_magic_scene_magic_info_widget_callback( void nfc_magic_scene_magic_info_on_enter(void* context) { NfcMagic* nfc_magic = context; Widget* widget = nfc_magic->widget; + const char* card_type = nfc_magic_type(nfc_magic->dev->type); notification_message(nfc_magic->notifications, &sequence_success); widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); widget_add_string_element( widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Magic card detected"); + widget_add_string_element(widget, 3, 17, AlignLeft, AlignTop, FontSecondary, card_type); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_magic_info_widget_callback, nfc_magic); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_magic_scene_magic_info_widget_callback, nfc_magic); // Setup and start worker view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); @@ -33,6 +38,15 @@ bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(nfc_magic->scene_manager); + } else if(event.event == GuiButtonTypeRight) { + MagicType type = nfc_magic->dev->type; + if(type == MagicTypeGen4) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneGen4Actions); + consumed = true; + } else { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneActions); + consumed = true; + } } } return consumed; diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c new file mode 100644 index 000000000..b5247f6c5 --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c @@ -0,0 +1,45 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_new_key_input_byte_input_callback(void* context) { + NfcMagic* nfc_magic = context; + + view_dispatcher_send_custom_event( + nfc_magic->view_dispatcher, NfcMagicCustomEventByteInputDone); +} + +void nfc_magic_scene_new_key_input_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + // Setup view + ByteInput* byte_input = nfc_magic->byte_input; + byte_input_set_header_text(byte_input, "Enter the password in hex"); + byte_input_set_result_callback( + byte_input, + nfc_magic_scene_new_key_input_byte_input_callback, + NULL, + nfc_magic, + (uint8_t*)&nfc_magic->new_password, + 4); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput); +} + +bool nfc_magic_scene_new_key_input_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicCustomEventByteInputDone) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneRekey); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_new_key_input_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + // Clear view + byte_input_set_result_callback(nfc_magic->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc_magic->byte_input, ""); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c new file mode 100644 index 000000000..259dc78ea --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c @@ -0,0 +1,95 @@ +#include "../nfc_magic_i.h" + +enum { + NfcMagicSceneRekeyStateCardSearch, + NfcMagicSceneRekeyStateCardFound, +}; + +bool nfc_magic_rekey_worker_callback(NfcMagicWorkerEvent event, void* context) { + furi_assert(context); + + NfcMagic* nfc_magic = context; + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, event); + + return true; +} + +static void nfc_magic_scene_rekey_setup_view(NfcMagic* nfc_magic) { + Popup* popup = nfc_magic->popup; + popup_reset(popup); + uint32_t state = scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneRekey); + + if(state == NfcMagicSceneRekeyStateCardSearch) { + popup_set_text( + nfc_magic->popup, + "Apply the\nsame card\nto the back", + 128, + 32, + AlignRight, + AlignCenter); + popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_icon(popup, 12, 23, &I_Loading_24); + popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); + } + + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup); +} + +void nfc_magic_scene_rekey_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch); + nfc_magic_scene_rekey_setup_view(nfc_magic); + + // Setup and start worker + nfc_magic_worker_start( + nfc_magic->worker, + NfcMagicWorkerStateRekey, + nfc_magic->dev, + &nfc_magic->source_dev->dev_data, + nfc_magic->new_password, + nfc_magic_rekey_worker_callback, + nfc_magic); + nfc_magic_blink_start(nfc_magic); +} + +bool nfc_magic_scene_rekey_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicWorkerEventSuccess) { + nfc_magic->dev->password = nfc_magic->new_password; + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneSuccess); + consumed = true; + } else if(event.event == NfcMagicWorkerEventFail) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneRekeyFail); + consumed = true; + } else if(event.event == NfcMagicWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardFound); + nfc_magic_scene_rekey_setup_view(nfc_magic); + consumed = true; + } else if(event.event == NfcMagicWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch); + nfc_magic_scene_rekey_setup_view(nfc_magic); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_rekey_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + nfc_magic_worker_stop(nfc_magic->worker); + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch); + // Clear view + popup_reset(nfc_magic->popup); + + nfc_magic_blink_stop(nfc_magic); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c new file mode 100644 index 000000000..d30ee57bc --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c @@ -0,0 +1,50 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_rekey_fail_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcMagic* nfc_magic = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result); + } +} + +void nfc_magic_scene_rekey_fail_on_enter(void* context) { + NfcMagic* nfc_magic = context; + Widget* widget = nfc_magic->widget; + + notification_message(nfc_magic->notifications, &sequence_error); + + widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Can't change password!"); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Finish", nfc_magic_scene_rekey_fail_widget_callback, nfc_magic); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); +} + +bool nfc_magic_scene_rekey_fail_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + return consumed; +} + +void nfc_magic_scene_rekey_fail_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + widget_reset(nfc_magic->widget); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_start.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_start.c index a70eb8acc..b5861629e 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_start.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_start.c @@ -1,8 +1,7 @@ #include "../nfc_magic_i.h" enum SubmenuIndex { SubmenuIndexCheck, - SubmenuIndexWriteGen1A, - SubmenuIndexWipe, + SubmenuIndexAuthenticateGen4, }; void nfc_magic_scene_start_submenu_callback(void* context, uint32_t index) { @@ -22,12 +21,10 @@ void nfc_magic_scene_start_on_enter(void* context) { nfc_magic); submenu_add_item( submenu, - "Write Gen1A", - SubmenuIndexWriteGen1A, + "Authenticate Gen4", + SubmenuIndexAuthenticateGen4, nfc_magic_scene_start_submenu_callback, nfc_magic); - submenu_add_item( - submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_start_submenu_callback, nfc_magic); submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneStart)); @@ -40,23 +37,13 @@ bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexCheck) { + nfc_magic->dev->password = MAGIC_GEN4_DEFAULT_PWD; scene_manager_set_scene_state( nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck); scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck); consumed = true; - } else if(event.event == SubmenuIndexWriteGen1A) { - // Explicitly save state in each branch so that the - // correct option is reselected if the user cancels - // loading a file. - scene_manager_set_scene_state( - nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexWriteGen1A); - scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect); - consumed = true; - } else if(event.event == SubmenuIndexWipe) { - scene_manager_set_scene_state( - nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexWipe); - scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe); - consumed = true; + } else if(event.event == SubmenuIndexAuthenticateGen4) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneKeyInput); } } diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_wipe.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_wipe.c index 1ca194286..29640f89c 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_wipe.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_wipe.c @@ -22,7 +22,12 @@ static void nfc_magic_scene_wipe_setup_view(NfcMagic* nfc_magic) { if(state == NfcMagicSceneWipeStateCardSearch) { popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50); popup_set_text( - nfc_magic->popup, "Apply card to\nthe back", 128, 32, AlignRight, AlignCenter); + nfc_magic->popup, + "Apply the\nsame card\nto the back", + 128, + 32, + AlignRight, + AlignCenter); } else { popup_set_icon(popup, 12, 23, &I_Loading_24); popup_set_header(popup, "Wiping\nDon't move...", 52, 32, AlignLeft, AlignCenter); @@ -42,7 +47,9 @@ void nfc_magic_scene_wipe_on_enter(void* context) { nfc_magic_worker_start( nfc_magic->worker, NfcMagicWorkerStateWipe, - &nfc_magic->nfc_dev->dev_data, + nfc_magic->dev, + &nfc_magic->source_dev->dev_data, + nfc_magic->new_password, nfc_magic_wipe_worker_callback, nfc_magic); nfc_magic_blink_start(nfc_magic); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_write.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_write.c index c3e6f962a..45c54557f 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_write.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_write.c @@ -21,7 +21,12 @@ static void nfc_magic_scene_write_setup_view(NfcMagic* nfc_magic) { if(state == NfcMagicSceneWriteStateCardSearch) { popup_set_text( - nfc_magic->popup, "Apply card to\nthe back", 128, 32, AlignRight, AlignCenter); + nfc_magic->popup, + "Apply the\nsame card\nto the back", + 128, + 32, + AlignRight, + AlignCenter); popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50); } else { popup_set_icon(popup, 12, 23, &I_Loading_24); @@ -42,7 +47,9 @@ void nfc_magic_scene_write_on_enter(void* context) { nfc_magic_worker_start( nfc_magic->worker, NfcMagicWorkerStateWrite, - &nfc_magic->nfc_dev->dev_data, + nfc_magic->dev, + &nfc_magic->source_dev->dev_data, + nfc_magic->new_password, nfc_magic_write_worker_callback, nfc_magic); nfc_magic_blink_start(nfc_magic); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_wrong_card.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_wrong_card.c index 4b8089693..857d50c1f 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_wrong_card.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_wrong_card.c @@ -26,7 +26,7 @@ void nfc_magic_scene_wrong_card_on_enter(void* context) { AlignLeft, AlignTop, FontSecondary, - "Writing is supported\nonly for 4 bytes UID\nMifare Classic 1k"); + "Writing this file is\nnot supported for\nthis magic card."); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wrong_card_widget_callback, nfc_magic);